mirror of https://github.com/xqemu/xqemu.git
pc, pci, virtio: cleanups, fixes
a bunch of bugfixes and a couple of cleanups making these easier and/or making debugging easier Signed-off-by: Michael S. Tsirkin <mst@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQEcBAABAgAGBQJXmslFAAoJECgfDbjSjVRpev0IAMZghEuSeKMB2JR88dErS8P5 J6y/1W2VFuRa1YBkTz/ecr5r2RwIO5teZUZpUkibM65Zo6bu1liMo6gbzeCg/xOi k437pNRl6W9RVWuXQM9VOegNoGYhX3Hrnu3iQeiT8KRY3OMCwG52umUXYVodJh1R mlozlEcSyUEDZVdNjhRECuUiw8RRcErEtiKda+zjkf4tPAGkyCItVpLYshE6A2/I lfQLkv+EWOyuD4cfEHl+4F9K9wegothFTSd/xBmcqqaWRc+pboMVF2A2yga+GjKm Xgb8SzQYkt9Q1nFr9fz89q89CsjhmfrD/ct/vJAcCFnw/dNXnC6mYjr6MDX0Gd0= =26Uu -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/mst/tags/for_upstream' into staging pc, pci, virtio: cleanups, fixes a bunch of bugfixes and a couple of cleanups making these easier and/or making debugging easier Signed-off-by: Michael S. Tsirkin <mst@redhat.com> # gpg: Signature made Fri 29 Jul 2016 04:11:01 BST # gpg: using RSA key 0x281F0DB8D28D5469 # gpg: Good signature from "Michael S. Tsirkin <mst@kernel.org>" # gpg: aka "Michael S. Tsirkin <mst@redhat.com>" # Primary key fingerprint: 0270 606B 6F3C DF3D 0B17 0970 C350 3912 AFBE 8E67 # Subkey fingerprint: 5D09 FD08 71C8 F85B 94CA 8A0D 281F 0DB8 D28D 5469 * remotes/mst/tags/for_upstream: (41 commits) mptsas: Fix a migration compatible issue vhost: do not update last avail idx on get_vring_base() failure vhost: add vhost_net_set_backend() vhost-user: add error report in vhost_user_write() tests: fix vhost-user-test leak tests: plug some leaks in virtio-net-test vhost-user: wait until backend init is completed char: add and use tcp_chr_wait_connected char: add chr_wait_connected callback vhost: add assert() to check runtime behaviour vhost-net: vhost_migration_done is vhost-user specific Revert "vhost-net: do not crash if backend is not present" vhost-user: add get_vhost_net() assertions vhost-user: keep vhost_net after a disconnection vhost-user: check vhost_user_{read,write}() return value vhost-user: check qemu_chr_fe_set_msgfds() return value vhost-user: call set_msgfds unconditionally qemu-char: fix qemu_chr_fe_set_msgfds() crash when disconnected vhost: use error_report() instead of fprintf(stderr,...) vhost: add missing VHOST_OPS_DEBUG ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
cbe81c6331
|
@ -30,9 +30,7 @@ static void virtio_gpu_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||
int i;
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
/* force virtio-1.0 */
|
||||
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
|
||||
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
|
||||
virtio_pci_force_virtio_1(vpci_dev);
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
|
||||
for (i = 0; i < g->conf.max_outputs; i++) {
|
||||
|
|
|
@ -134,9 +134,7 @@ static void virtio_vga_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||
|
||||
/* init virtio bits */
|
||||
qdev_set_parent_bus(DEVICE(g), BUS(&vpci_dev->bus));
|
||||
/* force virtio-1.0 */
|
||||
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
|
||||
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
|
||||
virtio_pci_force_virtio_1(vpci_dev);
|
||||
object_property_set_bool(OBJECT(g), true, "realized", &err);
|
||||
if (err) {
|
||||
error_propagate(errp, err);
|
||||
|
|
|
@ -600,6 +600,10 @@ static void build_append_pci_bus_devices(Aml *parent_scope, PCIBus *bus,
|
|||
QLIST_FOREACH(sec, &bus->child, sibling) {
|
||||
int32_t devfn = sec->parent_dev->devfn;
|
||||
|
||||
if (pci_bus_is_root(sec) || pci_bus_is_express(sec)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aml_append(method, aml_name("^S%.02X.PCNT", devfn));
|
||||
}
|
||||
}
|
||||
|
@ -747,6 +751,27 @@ static void crs_range_free(gpointer data)
|
|||
g_free(entry);
|
||||
}
|
||||
|
||||
typedef struct CrsRangeSet {
|
||||
GPtrArray *io_ranges;
|
||||
GPtrArray *mem_ranges;
|
||||
GPtrArray *mem_64bit_ranges;
|
||||
} CrsRangeSet;
|
||||
|
||||
static void crs_range_set_init(CrsRangeSet *range_set)
|
||||
{
|
||||
range_set->io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
range_set->mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
range_set->mem_64bit_ranges =
|
||||
g_ptr_array_new_with_free_func(crs_range_free);
|
||||
}
|
||||
|
||||
static void crs_range_set_free(CrsRangeSet *range_set)
|
||||
{
|
||||
g_ptr_array_free(range_set->io_ranges, true);
|
||||
g_ptr_array_free(range_set->mem_ranges, true);
|
||||
g_ptr_array_free(range_set->mem_64bit_ranges, true);
|
||||
}
|
||||
|
||||
static gint crs_range_compare(gconstpointer a, gconstpointer b)
|
||||
{
|
||||
CrsRangeEntry *entry_a = *(CrsRangeEntry **)a;
|
||||
|
@ -831,18 +856,17 @@ static void crs_range_merge(GPtrArray *range)
|
|||
g_ptr_array_free(tmp, true);
|
||||
}
|
||||
|
||||
static Aml *build_crs(PCIHostState *host,
|
||||
GPtrArray *io_ranges, GPtrArray *mem_ranges)
|
||||
static Aml *build_crs(PCIHostState *host, CrsRangeSet *range_set)
|
||||
{
|
||||
Aml *crs = aml_resource_template();
|
||||
GPtrArray *host_io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
GPtrArray *host_mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
CrsRangeSet temp_range_set;
|
||||
CrsRangeEntry *entry;
|
||||
uint8_t max_bus = pci_bus_num(host->bus);
|
||||
uint8_t type;
|
||||
int devfn;
|
||||
int i;
|
||||
|
||||
crs_range_set_init(&temp_range_set);
|
||||
for (devfn = 0; devfn < ARRAY_SIZE(host->bus->devices); devfn++) {
|
||||
uint64_t range_base, range_limit;
|
||||
PCIDevice *dev = host->bus->devices[devfn];
|
||||
|
@ -866,9 +890,11 @@ static Aml *build_crs(PCIHostState *host,
|
|||
}
|
||||
|
||||
if (r->type & PCI_BASE_ADDRESS_SPACE_IO) {
|
||||
crs_range_insert(host_io_ranges, range_base, range_limit);
|
||||
crs_range_insert(temp_range_set.io_ranges,
|
||||
range_base, range_limit);
|
||||
} else { /* "memory" */
|
||||
crs_range_insert(host_mem_ranges, range_base, range_limit);
|
||||
crs_range_insert(temp_range_set.mem_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -887,7 +913,8 @@ static Aml *build_crs(PCIHostState *host,
|
|||
* that do not support multiple root buses
|
||||
*/
|
||||
if (range_base && range_base <= range_limit) {
|
||||
crs_range_insert(host_io_ranges, range_base, range_limit);
|
||||
crs_range_insert(temp_range_set.io_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
|
||||
range_base =
|
||||
|
@ -900,7 +927,14 @@ static Aml *build_crs(PCIHostState *host,
|
|||
* that do not support multiple root buses
|
||||
*/
|
||||
if (range_base && range_base <= range_limit) {
|
||||
crs_range_insert(host_mem_ranges, range_base, range_limit);
|
||||
uint64_t length = range_limit - range_base + 1;
|
||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||
crs_range_insert(temp_range_set.mem_ranges,
|
||||
range_base, range_limit);
|
||||
} else {
|
||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
}
|
||||
|
||||
range_base =
|
||||
|
@ -913,35 +947,55 @@ static Aml *build_crs(PCIHostState *host,
|
|||
* that do not support multiple root buses
|
||||
*/
|
||||
if (range_base && range_base <= range_limit) {
|
||||
crs_range_insert(host_mem_ranges, range_base, range_limit);
|
||||
uint64_t length = range_limit - range_base + 1;
|
||||
if (range_limit <= UINT32_MAX && length <= UINT32_MAX) {
|
||||
crs_range_insert(temp_range_set.mem_ranges,
|
||||
range_base, range_limit);
|
||||
} else {
|
||||
crs_range_insert(temp_range_set.mem_64bit_ranges,
|
||||
range_base, range_limit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crs_range_merge(host_io_ranges);
|
||||
for (i = 0; i < host_io_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(host_io_ranges, i);
|
||||
crs_range_merge(temp_range_set.io_ranges);
|
||||
for (i = 0; i < temp_range_set.io_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(temp_range_set.io_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||
0, entry->base, entry->limit, 0,
|
||||
entry->limit - entry->base + 1));
|
||||
crs_range_insert(io_ranges, entry->base, entry->limit);
|
||||
crs_range_insert(range_set->io_ranges, entry->base, entry->limit);
|
||||
}
|
||||
g_ptr_array_free(host_io_ranges, true);
|
||||
|
||||
crs_range_merge(host_mem_ranges);
|
||||
for (i = 0; i < host_mem_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(host_mem_ranges, i);
|
||||
crs_range_merge(temp_range_set.mem_ranges);
|
||||
for (i = 0; i < temp_range_set.mem_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(temp_range_set.mem_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, entry->base, entry->limit, 0,
|
||||
entry->limit - entry->base + 1));
|
||||
crs_range_insert(mem_ranges, entry->base, entry->limit);
|
||||
crs_range_insert(range_set->mem_ranges, entry->base, entry->limit);
|
||||
}
|
||||
g_ptr_array_free(host_mem_ranges, true);
|
||||
|
||||
crs_range_merge(temp_range_set.mem_64bit_ranges);
|
||||
for (i = 0; i < temp_range_set.mem_64bit_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(temp_range_set.mem_64bit_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED, AML_NON_CACHEABLE,
|
||||
AML_READ_WRITE,
|
||||
0, entry->base, entry->limit, 0,
|
||||
entry->limit - entry->base + 1));
|
||||
crs_range_insert(range_set->mem_64bit_ranges,
|
||||
entry->base, entry->limit);
|
||||
}
|
||||
|
||||
crs_range_set_free(&temp_range_set);
|
||||
|
||||
aml_append(crs,
|
||||
aml_word_bus_number(AML_MIN_FIXED, AML_MAX_FIXED, AML_POS_DECODE,
|
||||
|
@ -1898,8 +1952,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
{
|
||||
CrsRangeEntry *entry;
|
||||
Aml *dsdt, *sb_scope, *scope, *dev, *method, *field, *pkg, *crs;
|
||||
GPtrArray *mem_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
GPtrArray *io_ranges = g_ptr_array_new_with_free_func(crs_range_free);
|
||||
CrsRangeSet crs_range_set;
|
||||
PCMachineState *pcms = PC_MACHINE(machine);
|
||||
PCMachineClass *pcmc = PC_MACHINE_GET_CLASS(machine);
|
||||
uint32_t nr_mem = machine->ram_slots;
|
||||
|
@ -1988,6 +2041,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
}
|
||||
aml_append(dsdt, scope);
|
||||
|
||||
crs_range_set_init(&crs_range_set);
|
||||
bus = PC_MACHINE(machine)->bus;
|
||||
if (bus) {
|
||||
QLIST_FOREACH(bus, &bus->child, sibling) {
|
||||
|
@ -2014,8 +2068,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
}
|
||||
|
||||
aml_append(dev, build_prt(false));
|
||||
crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent),
|
||||
io_ranges, mem_ranges);
|
||||
crs = build_crs(PCI_HOST_BRIDGE(BUS(bus)->parent), &crs_range_set);
|
||||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
aml_append(dsdt, scope);
|
||||
|
@ -2036,9 +2089,9 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||
0x0000, 0x0000, 0x0CF7, 0x0000, 0x0CF8));
|
||||
|
||||
crs_replace_with_free_ranges(io_ranges, 0x0D00, 0xFFFF);
|
||||
for (i = 0; i < io_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(io_ranges, i);
|
||||
crs_replace_with_free_ranges(crs_range_set.io_ranges, 0x0D00, 0xFFFF);
|
||||
for (i = 0; i < crs_range_set.io_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(crs_range_set.io_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_word_io(AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_POS_DECODE, AML_ENTIRE_RANGE,
|
||||
|
@ -2051,11 +2104,11 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
AML_CACHEABLE, AML_READ_WRITE,
|
||||
0, 0x000A0000, 0x000BFFFF, 0, 0x00020000));
|
||||
|
||||
crs_replace_with_free_ranges(mem_ranges,
|
||||
crs_replace_with_free_ranges(crs_range_set.mem_ranges,
|
||||
range_lob(pci_hole),
|
||||
range_upb(pci_hole));
|
||||
for (i = 0; i < mem_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(mem_ranges, i);
|
||||
for (i = 0; i < crs_range_set.mem_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(crs_range_set.mem_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_dword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_NON_CACHEABLE, AML_READ_WRITE,
|
||||
|
@ -2064,11 +2117,18 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
}
|
||||
|
||||
if (!range_is_empty(pci_hole64)) {
|
||||
aml_append(crs,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED, AML_MAX_FIXED,
|
||||
AML_CACHEABLE, AML_READ_WRITE,
|
||||
0, range_lob(pci_hole64), range_upb(pci_hole64), 0,
|
||||
range_upb(pci_hole64) + 1 - range_lob(pci_hole64)));
|
||||
crs_replace_with_free_ranges(crs_range_set.mem_64bit_ranges,
|
||||
range_lob(pci_hole64),
|
||||
range_upb(pci_hole64));
|
||||
for (i = 0; i < crs_range_set.mem_64bit_ranges->len; i++) {
|
||||
entry = g_ptr_array_index(crs_range_set.mem_64bit_ranges, i);
|
||||
aml_append(crs,
|
||||
aml_qword_memory(AML_POS_DECODE, AML_MIN_FIXED,
|
||||
AML_MAX_FIXED,
|
||||
AML_CACHEABLE, AML_READ_WRITE,
|
||||
0, entry->base, entry->limit,
|
||||
0, entry->limit - entry->base + 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (misc->tpm_version != TPM_VERSION_UNSPEC) {
|
||||
|
@ -2090,8 +2150,7 @@ build_dsdt(GArray *table_data, BIOSLinker *linker,
|
|||
aml_append(dev, aml_name_decl("_CRS", crs));
|
||||
aml_append(scope, dev);
|
||||
|
||||
g_ptr_array_free(io_ranges, true);
|
||||
g_ptr_array_free(mem_ranges, true);
|
||||
crs_range_set_free(&crs_range_set);
|
||||
|
||||
/* reserve PCIHP resources */
|
||||
if (pm->pcihp_io_len) {
|
||||
|
|
|
@ -140,7 +140,7 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
|||
{
|
||||
int r;
|
||||
bool backend_kernel = options->backend_type == VHOST_BACKEND_TYPE_KERNEL;
|
||||
struct vhost_net *net = g_malloc(sizeof *net);
|
||||
struct vhost_net *net = g_new0(struct vhost_net, 1);
|
||||
uint64_t features = 0;
|
||||
|
||||
if (!options->net_backend) {
|
||||
|
@ -185,7 +185,6 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
|||
fprintf(stderr, "vhost lacks feature mask %" PRIu64
|
||||
" for backend\n",
|
||||
(uint64_t)(~net->dev.features & net->dev.backend_features));
|
||||
vhost_dev_cleanup(&net->dev);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
@ -197,7 +196,6 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
|||
fprintf(stderr, "vhost lacks feature mask %" PRIu64
|
||||
" for backend\n",
|
||||
(uint64_t)(~net->dev.features & features));
|
||||
vhost_dev_cleanup(&net->dev);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
@ -205,7 +203,9 @@ struct vhost_net *vhost_net_init(VhostNetOptions *options)
|
|||
vhost_net_ack_features(net, features);
|
||||
|
||||
return net;
|
||||
|
||||
fail:
|
||||
vhost_dev_cleanup(&net->dev);
|
||||
g_free(net);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -242,8 +242,7 @@ static int vhost_net_start_one(struct vhost_net *net,
|
|||
qemu_set_fd_handler(net->backend, NULL, NULL, NULL);
|
||||
file.fd = net->backend;
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
|
||||
r = vhost_net_set_backend(&net->dev, &file);
|
||||
if (r < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
|
@ -255,8 +254,7 @@ fail:
|
|||
file.fd = -1;
|
||||
if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
|
||||
while (file.index-- > 0) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
|
||||
int r = vhost_net_set_backend(&net->dev, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
}
|
||||
|
@ -277,8 +275,7 @@ static void vhost_net_stop_one(struct vhost_net *net,
|
|||
|
||||
if (net->nc->info->type == NET_CLIENT_DRIVER_TAP) {
|
||||
for (file.index = 0; file.index < net->dev.nvqs; ++file.index) {
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = vhost_ops->vhost_net_set_backend(&net->dev, &file);
|
||||
int r = vhost_net_set_backend(&net->dev, &file);
|
||||
assert(r >= 0);
|
||||
}
|
||||
}
|
||||
|
@ -313,7 +310,7 @@ int vhost_net_start(VirtIODevice *dev, NetClientState *ncs,
|
|||
* properly.
|
||||
*/
|
||||
if (net->nc->info->type == NET_CLIENT_DRIVER_VHOST_USER) {
|
||||
dev->use_guest_notifier_mask = false;
|
||||
dev->use_guest_notifier_mask = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -378,19 +375,16 @@ void vhost_net_stop(VirtIODevice *dev, NetClientState *ncs,
|
|||
void vhost_net_cleanup(struct vhost_net *net)
|
||||
{
|
||||
vhost_dev_cleanup(&net->dev);
|
||||
g_free(net);
|
||||
}
|
||||
|
||||
int vhost_net_notify_migration_done(struct vhost_net *net, char* mac_addr)
|
||||
{
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
int r = -1;
|
||||
|
||||
if (vhost_ops->vhost_migration_done) {
|
||||
r = vhost_ops->vhost_migration_done(&net->dev, mac_addr);
|
||||
}
|
||||
assert(vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
|
||||
assert(vhost_ops->vhost_migration_done);
|
||||
|
||||
return r;
|
||||
return vhost_ops->vhost_migration_done(&net->dev, mac_addr);
|
||||
}
|
||||
|
||||
bool vhost_net_virtqueue_pending(VHostNetState *net, int idx)
|
||||
|
@ -418,6 +412,7 @@ VHostNetState *get_vhost_net(NetClientState *nc)
|
|||
break;
|
||||
case NET_CLIENT_DRIVER_VHOST_USER:
|
||||
vhost_net = vhost_user_get_vhost_net(nc);
|
||||
assert(vhost_net);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -429,15 +424,10 @@ VHostNetState *get_vhost_net(NetClientState *nc)
|
|||
int vhost_set_vring_enable(NetClientState *nc, int enable)
|
||||
{
|
||||
VHostNetState *net = get_vhost_net(nc);
|
||||
const VhostOps *vhost_ops;
|
||||
const VhostOps *vhost_ops = net->dev.vhost_ops;
|
||||
|
||||
nc->vring_enable = enable;
|
||||
|
||||
if (!net) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
vhost_ops = net->dev.vhost_ops;
|
||||
if (vhost_ops->vhost_set_vring_enable) {
|
||||
return vhost_ops->vhost_set_vring_enable(&net->dev, enable);
|
||||
}
|
||||
|
|
|
@ -100,6 +100,7 @@ static int ioh3420_initfn(PCIDevice *d)
|
|||
int rc;
|
||||
Error *err = NULL;
|
||||
|
||||
pci_config_set_interrupt_pin(d->config, 1);
|
||||
pci_bridge_initfn(d, TYPE_PCIE_BUS);
|
||||
pcie_port_init_reg(d);
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
*/
|
||||
|
||||
#include "qemu/osdep.h"
|
||||
#include "qapi/error.h"
|
||||
#include "hw/pci/pci.h"
|
||||
#include "hw/pci/pci_bus.h"
|
||||
#include "hw/pci/pci_host.h"
|
||||
|
@ -162,30 +163,25 @@ static const TypeInfo pxb_host_info = {
|
|||
};
|
||||
|
||||
/*
|
||||
* Registers the PXB bus as a child of the i440fx root bus.
|
||||
*
|
||||
* Returns 0 on successs, -1 if i440fx host was not
|
||||
* found or the bus number is already in use.
|
||||
* Registers the PXB bus as a child of pci host root bus.
|
||||
*/
|
||||
static int pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus)
|
||||
static void pxb_register_bus(PCIDevice *dev, PCIBus *pxb_bus, Error **errp)
|
||||
{
|
||||
PCIBus *bus = dev->bus;
|
||||
int pxb_bus_num = pci_bus_num(pxb_bus);
|
||||
|
||||
if (bus->parent_dev) {
|
||||
error_report("PXB devices can be attached only to root bus.");
|
||||
return -1;
|
||||
error_setg(errp, "PXB devices can be attached only to root bus");
|
||||
return;
|
||||
}
|
||||
|
||||
QLIST_FOREACH(bus, &bus->child, sibling) {
|
||||
if (pci_bus_num(bus) == pxb_bus_num) {
|
||||
error_report("Bus %d is already in use.", pxb_bus_num);
|
||||
return -1;
|
||||
error_setg(errp, "Bus %d is already in use", pxb_bus_num);
|
||||
return;
|
||||
}
|
||||
}
|
||||
QLIST_INSERT_HEAD(&dev->bus->child, pxb_bus, sibling);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pxb_map_irq_fn(PCIDevice *pci_dev, int pin)
|
||||
|
@ -215,17 +211,18 @@ static gint pxb_compare(gconstpointer a, gconstpointer b)
|
|||
0;
|
||||
}
|
||||
|
||||
static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
|
||||
static void pxb_dev_realize_common(PCIDevice *dev, bool pcie, Error **errp)
|
||||
{
|
||||
PXBDev *pxb = convert_to_pxb(dev);
|
||||
DeviceState *ds, *bds = NULL;
|
||||
PCIBus *bus;
|
||||
const char *dev_name = NULL;
|
||||
Error *local_err = NULL;
|
||||
|
||||
if (pxb->numa_node != NUMA_NODE_UNASSIGNED &&
|
||||
pxb->numa_node >= nb_numa_nodes) {
|
||||
error_report("Illegal numa node %d.", pxb->numa_node);
|
||||
return -EINVAL;
|
||||
error_setg(errp, "Illegal numa node %d", pxb->numa_node);
|
||||
return;
|
||||
}
|
||||
|
||||
if (dev->qdev.id && *dev->qdev.id) {
|
||||
|
@ -250,7 +247,9 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
|
|||
|
||||
PCI_HOST_BRIDGE(ds)->bus = bus;
|
||||
|
||||
if (pxb_register_bus(dev, bus)) {
|
||||
pxb_register_bus(dev, bus, &local_err);
|
||||
if (local_err) {
|
||||
error_propagate(errp, local_err);
|
||||
goto err_register_bus;
|
||||
}
|
||||
|
||||
|
@ -264,23 +263,22 @@ static int pxb_dev_init_common(PCIDevice *dev, bool pcie)
|
|||
pci_config_set_class(dev->config, PCI_CLASS_BRIDGE_HOST);
|
||||
|
||||
pxb_dev_list = g_list_insert_sorted(pxb_dev_list, pxb, pxb_compare);
|
||||
return 0;
|
||||
return;
|
||||
|
||||
err_register_bus:
|
||||
object_unref(OBJECT(bds));
|
||||
object_unparent(OBJECT(bus));
|
||||
object_unref(OBJECT(ds));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int pxb_dev_initfn(PCIDevice *dev)
|
||||
static void pxb_dev_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
if (pci_bus_is_express(dev->bus)) {
|
||||
error_report("pxb devices cannot reside on a PCIe bus!");
|
||||
return -EINVAL;
|
||||
error_setg(errp, "pxb devices cannot reside on a PCIe bus");
|
||||
return;
|
||||
}
|
||||
|
||||
return pxb_dev_init_common(dev, false);
|
||||
pxb_dev_realize_common(dev, false, errp);
|
||||
}
|
||||
|
||||
static void pxb_dev_exitfn(PCIDevice *pci_dev)
|
||||
|
@ -302,7 +300,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
|
|||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pxb_dev_initfn;
|
||||
k->realize = pxb_dev_realize;
|
||||
k->exit = pxb_dev_exitfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_REDHAT;
|
||||
k->device_id = PCI_DEVICE_ID_REDHAT_PXB;
|
||||
|
@ -310,6 +308,7 @@ static void pxb_dev_class_init(ObjectClass *klass, void *data)
|
|||
|
||||
dc->desc = "PCI Expander Bridge";
|
||||
dc->props = pxb_dev_properties;
|
||||
dc->hotpluggable = false;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
}
|
||||
|
||||
|
@ -320,14 +319,14 @@ static const TypeInfo pxb_dev_info = {
|
|||
.class_init = pxb_dev_class_init,
|
||||
};
|
||||
|
||||
static int pxb_pcie_dev_initfn(PCIDevice *dev)
|
||||
static void pxb_pcie_dev_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
if (!pci_bus_is_express(dev->bus)) {
|
||||
error_report("pxb-pcie devices cannot reside on a PCI bus!");
|
||||
return -EINVAL;
|
||||
error_setg(errp, "pxb-pcie devices cannot reside on a PCI bus");
|
||||
return;
|
||||
}
|
||||
|
||||
return pxb_dev_init_common(dev, true);
|
||||
pxb_dev_realize_common(dev, true, errp);
|
||||
}
|
||||
|
||||
static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
|
||||
|
@ -335,7 +334,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
|
|||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = pxb_pcie_dev_initfn;
|
||||
k->realize = pxb_pcie_dev_realize;
|
||||
k->exit = pxb_dev_exitfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_REDHAT;
|
||||
k->device_id = PCI_DEVICE_ID_REDHAT_PXB_PCIE;
|
||||
|
@ -343,6 +342,7 @@ static void pxb_pcie_dev_class_init(ObjectClass *klass, void *data)
|
|||
|
||||
dc->desc = "PCI Express Expander Bridge";
|
||||
dc->props = pxb_dev_properties;
|
||||
dc->hotpluggable = false;
|
||||
set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories);
|
||||
}
|
||||
|
||||
|
|
|
@ -634,7 +634,7 @@ static void pci_apb_set_irq(void *opaque, int irq_num, int level)
|
|||
}
|
||||
}
|
||||
|
||||
static int apb_pci_bridge_initfn(PCIDevice *dev)
|
||||
static void apb_pci_bridge_realize(PCIDevice *dev, Error **errp)
|
||||
{
|
||||
pci_bridge_initfn(dev, TYPE_PCI_BUS);
|
||||
|
||||
|
@ -652,7 +652,6 @@ static int apb_pci_bridge_initfn(PCIDevice *dev)
|
|||
pci_set_word(dev->config + PCI_STATUS,
|
||||
PCI_STATUS_FAST_BACK | PCI_STATUS_66MHZ |
|
||||
PCI_STATUS_DEVSEL_MEDIUM);
|
||||
return 0;
|
||||
}
|
||||
|
||||
PCIBus *pci_apb_init(hwaddr special_base,
|
||||
|
@ -843,7 +842,7 @@ static void pbm_pci_bridge_class_init(ObjectClass *klass, void *data)
|
|||
DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
|
||||
|
||||
k->init = apb_pci_bridge_initfn;
|
||||
k->realize = apb_pci_bridge_realize;
|
||||
k->exit = pci_bridge_exitfn;
|
||||
k->vendor_id = PCI_VENDOR_ID_SUN;
|
||||
k->device_id = PCI_DEVICE_ID_SUN_SIMBA;
|
||||
|
|
|
@ -62,6 +62,8 @@ static Property pci_props[] = {
|
|||
QEMU_PCI_CAP_MULTIFUNCTION_BITNR, false),
|
||||
DEFINE_PROP_BIT("command_serr_enable", PCIDevice, cap_present,
|
||||
QEMU_PCI_CAP_SERR_BITNR, true),
|
||||
DEFINE_PROP_BIT("x-pcie-lnksta-dllla", PCIDevice, cap_present,
|
||||
QEMU_PCIE_LNKSTA_DLLLA_BITNR, true),
|
||||
DEFINE_PROP_END_OF_LIST()
|
||||
};
|
||||
|
||||
|
|
|
@ -45,8 +45,11 @@
|
|||
*/
|
||||
|
||||
static void
|
||||
pcie_cap_v1_fill(uint8_t *exp_cap, uint8_t port, uint8_t type, uint8_t version)
|
||||
pcie_cap_v1_fill(PCIDevice *dev, uint8_t port, uint8_t type, uint8_t version)
|
||||
{
|
||||
uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
|
||||
uint8_t *cmask = dev->cmask + dev->exp.exp_cap;
|
||||
|
||||
/* capability register
|
||||
interrupt message number defaults to 0 */
|
||||
pci_set_word(exp_cap + PCI_EXP_FLAGS,
|
||||
|
@ -69,7 +72,18 @@ pcie_cap_v1_fill(uint8_t *exp_cap, uint8_t port, uint8_t type, uint8_t version)
|
|||
PCI_EXP_LNK_LS_25);
|
||||
|
||||
pci_set_word(exp_cap + PCI_EXP_LNKSTA,
|
||||
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25 |PCI_EXP_LNKSTA_DLLLA);
|
||||
PCI_EXP_LNK_MLW_1 | PCI_EXP_LNK_LS_25);
|
||||
|
||||
if (dev->cap_present & QEMU_PCIE_LNKSTA_DLLLA) {
|
||||
pci_word_test_and_set_mask(exp_cap + PCI_EXP_LNKSTA,
|
||||
PCI_EXP_LNKSTA_DLLLA);
|
||||
}
|
||||
|
||||
/* We changed link status bits over time, and changing them across
|
||||
* migrations is generally fine as hardware changes them too.
|
||||
* Let's not bother checking.
|
||||
*/
|
||||
pci_set_word(cmask + PCI_EXP_LNKSTA, 0);
|
||||
}
|
||||
|
||||
int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
|
||||
|
@ -88,7 +102,7 @@ int pcie_cap_init(PCIDevice *dev, uint8_t offset, uint8_t type, uint8_t port)
|
|||
exp_cap = dev->config + pos;
|
||||
|
||||
/* Filling values common with v1 */
|
||||
pcie_cap_v1_fill(exp_cap, port, type, PCI_EXP_FLAGS_VER2);
|
||||
pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER2);
|
||||
|
||||
/* Filling v2 specific values */
|
||||
pci_set_long(exp_cap + PCI_EXP_DEVCAP2,
|
||||
|
@ -103,7 +117,6 @@ int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type,
|
|||
{
|
||||
/* PCIe cap v1 init */
|
||||
int pos;
|
||||
uint8_t *exp_cap;
|
||||
|
||||
assert(pci_is_express(dev));
|
||||
|
||||
|
@ -112,9 +125,8 @@ int pcie_cap_v1_init(PCIDevice *dev, uint8_t offset, uint8_t type,
|
|||
return pos;
|
||||
}
|
||||
dev->exp.exp_cap = pos;
|
||||
exp_cap = dev->config + pos;
|
||||
|
||||
pcie_cap_v1_fill(exp_cap, port, type, PCI_EXP_FLAGS_VER1);
|
||||
pcie_cap_v1_fill(dev, port, type, PCI_EXP_FLAGS_VER1);
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
|
|
@ -1370,7 +1370,7 @@ static const VMStateDescription vmstate_mptsas = {
|
|||
.post_load = mptsas_post_load,
|
||||
.fields = (VMStateField[]) {
|
||||
VMSTATE_PCI_DEVICE(dev, MPTSASState),
|
||||
|
||||
VMSTATE_UNUSED(sizeof(bool)), /* Was msi_in_use */
|
||||
VMSTATE_UINT32(state, MPTSASState),
|
||||
VMSTATE_UINT8(who_init, MPTSASState),
|
||||
VMSTATE_UINT8(doorbell_state, MPTSASState),
|
||||
|
|
|
@ -176,7 +176,7 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
|
|||
int *fds, int fd_num)
|
||||
{
|
||||
CharDriverState *chr = dev->opaque;
|
||||
int size = VHOST_USER_HDR_SIZE + msg->size;
|
||||
int ret, size = VHOST_USER_HDR_SIZE + msg->size;
|
||||
|
||||
/*
|
||||
* For non-vring specific requests, like VHOST_USER_SET_MEM_TABLE,
|
||||
|
@ -187,12 +187,19 @@ static int vhost_user_write(struct vhost_dev *dev, VhostUserMsg *msg,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if (fd_num) {
|
||||
qemu_chr_fe_set_msgfds(chr, fds, fd_num);
|
||||
if (qemu_chr_fe_set_msgfds(chr, fds, fd_num) < 0) {
|
||||
error_report("Failed to set msg fds.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size) == size ?
|
||||
0 : -1;
|
||||
ret = qemu_chr_fe_write_all(chr, (const uint8_t *) msg, size);
|
||||
if (ret != size) {
|
||||
error_report("Failed to write msg."
|
||||
" Wrote %d instead of %d.", ret, size);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
|
||||
|
@ -214,12 +221,14 @@ static int vhost_user_set_log_base(struct vhost_dev *dev, uint64_t base,
|
|||
fds[fd_num++] = log->fd;
|
||||
}
|
||||
|
||||
vhost_user_write(dev, &msg, fds, fd_num);
|
||||
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (shmfd) {
|
||||
msg.size = 0;
|
||||
if (vhost_user_read(dev, &msg) < 0) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.request != VHOST_USER_SET_LOG_BASE) {
|
||||
|
@ -275,7 +284,9 @@ static int vhost_user_set_mem_table(struct vhost_dev *dev,
|
|||
msg.size += sizeof(msg.payload.memory.padding);
|
||||
msg.size += fd_num * sizeof(VhostUserMemoryRegion);
|
||||
|
||||
vhost_user_write(dev, &msg, fds, fd_num);
|
||||
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -290,7 +301,9 @@ static int vhost_user_set_vring_addr(struct vhost_dev *dev,
|
|||
.size = sizeof(msg.payload.addr),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -313,7 +326,9 @@ static int vhost_set_vring(struct vhost_dev *dev,
|
|||
.size = sizeof(msg.payload.state),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -360,10 +375,12 @@ static int vhost_user_get_vring_base(struct vhost_dev *dev,
|
|||
.size = sizeof(msg.payload.state),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vhost_user_read(dev, &msg) < 0) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.request != VHOST_USER_GET_VRING_BASE) {
|
||||
|
@ -401,7 +418,9 @@ static int vhost_set_vring_file(struct vhost_dev *dev,
|
|||
msg.payload.u64 |= VHOST_USER_VRING_NOFD_MASK;
|
||||
}
|
||||
|
||||
vhost_user_write(dev, &msg, fds, fd_num);
|
||||
if (vhost_user_write(dev, &msg, fds, fd_num) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -427,7 +446,9 @@ static int vhost_user_set_u64(struct vhost_dev *dev, int request, uint64_t u64)
|
|||
.size = sizeof(msg.payload.u64),
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -455,10 +476,12 @@ static int vhost_user_get_u64(struct vhost_dev *dev, int request, uint64_t *u64)
|
|||
return 0;
|
||||
}
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (vhost_user_read(dev, &msg) < 0) {
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.request != request) {
|
||||
|
@ -489,7 +512,9 @@ static int vhost_user_set_owner(struct vhost_dev *dev)
|
|||
.flags = VHOST_USER_VERSION,
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -501,7 +526,9 @@ static int vhost_user_reset_device(struct vhost_dev *dev)
|
|||
.flags = VHOST_USER_VERSION,
|
||||
};
|
||||
|
||||
vhost_user_write(dev, &msg, NULL, 0);
|
||||
if (vhost_user_write(dev, &msg, NULL, 0) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -588,7 +615,6 @@ static bool vhost_user_requires_shm_log(struct vhost_dev *dev)
|
|||
static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
|
||||
{
|
||||
VhostUserMsg msg = { 0 };
|
||||
int err;
|
||||
|
||||
assert(dev->vhost_ops->backend_type == VHOST_BACKEND_TYPE_USER);
|
||||
|
||||
|
@ -605,8 +631,7 @@ static int vhost_user_migration_done(struct vhost_dev *dev, char* mac_addr)
|
|||
memcpy((char *)&msg.payload.u64, mac_addr, 6);
|
||||
msg.size = sizeof(msg.payload.u64);
|
||||
|
||||
err = vhost_user_write(dev, &msg, NULL, 0);
|
||||
return err;
|
||||
return vhost_user_write(dev, &msg, NULL, 0);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,18 @@
|
|||
#include "hw/virtio/virtio-access.h"
|
||||
#include "migration/migration.h"
|
||||
|
||||
/* enabled until disconnected backend stabilizes */
|
||||
#define _VHOST_DEBUG 1
|
||||
|
||||
#ifdef _VHOST_DEBUG
|
||||
#define VHOST_OPS_DEBUG(fmt, ...) \
|
||||
do { error_report(fmt ": %s (%d)", ## __VA_ARGS__, \
|
||||
strerror(errno), errno); } while (0)
|
||||
#else
|
||||
#define VHOST_OPS_DEBUG(fmt, ...) \
|
||||
do { } while (0)
|
||||
#endif
|
||||
|
||||
static struct vhost_log *vhost_log;
|
||||
static struct vhost_log *vhost_log_shm;
|
||||
|
||||
|
@ -362,6 +374,8 @@ static void vhost_log_put(struct vhost_dev *dev, bool sync)
|
|||
if (!log) {
|
||||
return;
|
||||
}
|
||||
dev->log = NULL;
|
||||
dev->log_size = 0;
|
||||
|
||||
--log->refcnt;
|
||||
if (log->refcnt == 0) {
|
||||
|
@ -398,7 +412,10 @@ static inline void vhost_dev_log_resize(struct vhost_dev *dev, uint64_t size)
|
|||
/* inform backend of log switching, this must be done before
|
||||
releasing the current log, to ensure no logging is lost */
|
||||
r = dev->vhost_ops->vhost_set_log_base(dev, log_base, log);
|
||||
assert(r >= 0);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_log_base failed");
|
||||
}
|
||||
|
||||
vhost_log_put(dev, true);
|
||||
dev->log = log;
|
||||
dev->log_size = size;
|
||||
|
@ -422,11 +439,11 @@ static int vhost_verify_ring_mappings(struct vhost_dev *dev,
|
|||
l = vq->ring_size;
|
||||
p = cpu_physical_memory_map(vq->ring_phys, &l, 1);
|
||||
if (!p || l != vq->ring_size) {
|
||||
fprintf(stderr, "Unable to map ring buffer for ring %d\n", i);
|
||||
error_report("Unable to map ring buffer for ring %d", i);
|
||||
r = -ENOMEM;
|
||||
}
|
||||
if (p != vq->ring) {
|
||||
fprintf(stderr, "Ring buffer relocated for ring %d\n", i);
|
||||
error_report("Ring buffer relocated for ring %d", i);
|
||||
r = -EBUSY;
|
||||
}
|
||||
cpu_physical_memory_unmap(p, l, 0, 0);
|
||||
|
@ -565,7 +582,9 @@ static void vhost_commit(MemoryListener *listener)
|
|||
|
||||
if (!dev->log_enabled) {
|
||||
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
|
||||
assert(r >= 0);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_mem_table failed");
|
||||
}
|
||||
dev->memory_changed = false;
|
||||
return;
|
||||
}
|
||||
|
@ -578,7 +597,9 @@ static void vhost_commit(MemoryListener *listener)
|
|||
vhost_dev_log_resize(dev, log_size + VHOST_LOG_BUFFER);
|
||||
}
|
||||
r = dev->vhost_ops->vhost_set_mem_table(dev, dev->mem);
|
||||
assert(r >= 0);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_mem_table failed");
|
||||
}
|
||||
/* To log less, can only decrease log size after table update. */
|
||||
if (dev->log_size > log_size + VHOST_LOG_BUFFER) {
|
||||
vhost_dev_log_resize(dev, log_size);
|
||||
|
@ -647,6 +668,7 @@ static int vhost_virtqueue_set_addr(struct vhost_dev *dev,
|
|||
};
|
||||
int r = dev->vhost_ops->vhost_set_vring_addr(dev, &addr);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_addr failed");
|
||||
return -errno;
|
||||
}
|
||||
return 0;
|
||||
|
@ -660,12 +682,15 @@ static int vhost_dev_set_features(struct vhost_dev *dev, bool enable_log)
|
|||
features |= 0x1ULL << VHOST_F_LOG_ALL;
|
||||
}
|
||||
r = dev->vhost_ops->vhost_set_features(dev, features);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_features failed");
|
||||
}
|
||||
return r < 0 ? -errno : 0;
|
||||
}
|
||||
|
||||
static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
|
||||
{
|
||||
int r, t, i, idx;
|
||||
int r, i, idx;
|
||||
r = vhost_dev_set_features(dev, enable_log);
|
||||
if (r < 0) {
|
||||
goto err_features;
|
||||
|
@ -682,12 +707,10 @@ static int vhost_dev_set_log(struct vhost_dev *dev, bool enable_log)
|
|||
err_vq:
|
||||
for (; i >= 0; --i) {
|
||||
idx = dev->vhost_ops->vhost_get_vq_index(dev, dev->vq_index + i);
|
||||
t = vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
|
||||
dev->log_enabled);
|
||||
assert(t >= 0);
|
||||
vhost_virtqueue_set_addr(dev, dev->vqs + i, idx,
|
||||
dev->log_enabled);
|
||||
}
|
||||
t = vhost_dev_set_features(dev, dev->log_enabled);
|
||||
assert(t >= 0);
|
||||
vhost_dev_set_features(dev, dev->log_enabled);
|
||||
err_features:
|
||||
return r;
|
||||
}
|
||||
|
@ -710,8 +733,6 @@ static int vhost_migration_log(MemoryListener *listener, int enable)
|
|||
return r;
|
||||
}
|
||||
vhost_log_put(dev, false);
|
||||
dev->log = NULL;
|
||||
dev->log_size = 0;
|
||||
} else {
|
||||
vhost_dev_log_resize(dev, vhost_get_log_size(dev));
|
||||
r = vhost_dev_set_log(dev, true);
|
||||
|
@ -787,6 +808,7 @@ static int vhost_virtqueue_set_vring_endian_legacy(struct vhost_dev *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_endian failed");
|
||||
if (errno == ENOTTY) {
|
||||
error_report("vhost does not support cross-endian");
|
||||
return -ENOSYS;
|
||||
|
@ -815,12 +837,14 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
|||
vq->num = state.num = virtio_queue_get_num(vdev, idx);
|
||||
r = dev->vhost_ops->vhost_set_vring_num(dev, &state);
|
||||
if (r) {
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_num failed");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
state.num = virtio_queue_get_last_avail_idx(vdev, idx);
|
||||
r = dev->vhost_ops->vhost_set_vring_base(dev, &state);
|
||||
if (r) {
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_base failed");
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
@ -872,6 +896,7 @@ static int vhost_virtqueue_start(struct vhost_dev *dev,
|
|||
file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
|
||||
r = dev->vhost_ops->vhost_set_vring_kick(dev, &file);
|
||||
if (r) {
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_kick failed");
|
||||
r = -errno;
|
||||
goto fail_kick;
|
||||
}
|
||||
|
@ -919,25 +944,21 @@ static void vhost_virtqueue_stop(struct vhost_dev *dev,
|
|||
|
||||
r = dev->vhost_ops->vhost_get_vring_base(dev, &state);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "vhost VQ %d ring restore failed: %d\n", idx, r);
|
||||
fflush(stderr);
|
||||
VHOST_OPS_DEBUG("vhost VQ %d ring restore failed: %d", idx, r);
|
||||
} else {
|
||||
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
|
||||
}
|
||||
virtio_queue_set_last_avail_idx(vdev, idx, state.num);
|
||||
virtio_queue_invalidate_signalled_used(vdev, idx);
|
||||
|
||||
/* In the cross-endian case, we need to reset the vring endianness to
|
||||
* native as legacy devices expect so by default.
|
||||
*/
|
||||
if (vhost_needs_vring_endian(vdev)) {
|
||||
r = vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||
!virtio_is_big_endian(vdev),
|
||||
vhost_vq_index);
|
||||
if (r < 0) {
|
||||
error_report("failed to reset vring endianness");
|
||||
}
|
||||
vhost_virtqueue_set_vring_endian_legacy(dev,
|
||||
!virtio_is_big_endian(vdev),
|
||||
vhost_vq_index);
|
||||
}
|
||||
|
||||
assert (r >= 0);
|
||||
cpu_physical_memory_unmap(vq->ring, virtio_queue_get_ring_size(vdev, idx),
|
||||
0, virtio_queue_get_ring_size(vdev, idx));
|
||||
cpu_physical_memory_unmap(vq->used, virtio_queue_get_used_size(vdev, idx),
|
||||
|
@ -976,6 +997,7 @@ static int vhost_virtqueue_set_busyloop_timeout(struct vhost_dev *dev,
|
|||
|
||||
r = dev->vhost_ops->vhost_set_vring_busyloop_timeout(dev, &state);
|
||||
if (r) {
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_busyloop_timeout failed");
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -997,6 +1019,7 @@ static int vhost_virtqueue_init(struct vhost_dev *dev,
|
|||
file.fd = event_notifier_get_fd(&vq->masked_notifier);
|
||||
r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
|
||||
if (r) {
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_call failed");
|
||||
r = -errno;
|
||||
goto fail_call;
|
||||
}
|
||||
|
@ -1015,42 +1038,41 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
|||
VhostBackendType backend_type, uint32_t busyloop_timeout)
|
||||
{
|
||||
uint64_t features;
|
||||
int i, r;
|
||||
int i, r, n_initialized_vqs = 0;
|
||||
|
||||
hdev->migration_blocker = NULL;
|
||||
|
||||
if (vhost_set_backend_type(hdev, backend_type) < 0) {
|
||||
close((uintptr_t)opaque);
|
||||
return -1;
|
||||
}
|
||||
r = vhost_set_backend_type(hdev, backend_type);
|
||||
assert(r >= 0);
|
||||
|
||||
if (hdev->vhost_ops->vhost_backend_init(hdev, opaque) < 0) {
|
||||
close((uintptr_t)opaque);
|
||||
return -errno;
|
||||
r = hdev->vhost_ops->vhost_backend_init(hdev, opaque);
|
||||
if (r < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (used_memslots > hdev->vhost_ops->vhost_backend_memslots_limit(hdev)) {
|
||||
fprintf(stderr, "vhost backend memory slots limit is less"
|
||||
" than current number of present memory slots\n");
|
||||
close((uintptr_t)opaque);
|
||||
return -1;
|
||||
error_report("vhost backend memory slots limit is less"
|
||||
" than current number of present memory slots");
|
||||
r = -1;
|
||||
goto fail;
|
||||
}
|
||||
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
|
||||
|
||||
r = hdev->vhost_ops->vhost_set_owner(hdev);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_owner failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
r = hdev->vhost_ops->vhost_get_features(hdev, &features);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_get_features failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (i = 0; i < hdev->nvqs; ++i) {
|
||||
for (i = 0; i < hdev->nvqs; ++i, ++n_initialized_vqs) {
|
||||
r = vhost_virtqueue_init(hdev, hdev->vqs + i, hdev->vq_index + i);
|
||||
if (r < 0) {
|
||||
goto fail_vq;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1105,38 +1127,43 @@ int vhost_dev_init(struct vhost_dev *hdev, void *opaque,
|
|||
hdev->started = false;
|
||||
hdev->memory_changed = false;
|
||||
memory_listener_register(&hdev->memory_listener, &address_space_memory);
|
||||
QLIST_INSERT_HEAD(&vhost_devices, hdev, entry);
|
||||
return 0;
|
||||
|
||||
fail_busyloop:
|
||||
while (--i >= 0) {
|
||||
vhost_virtqueue_set_busyloop_timeout(hdev, hdev->vq_index + i, 0);
|
||||
}
|
||||
i = hdev->nvqs;
|
||||
fail_vq:
|
||||
while (--i >= 0) {
|
||||
vhost_virtqueue_cleanup(hdev->vqs + i);
|
||||
}
|
||||
fail:
|
||||
r = -errno;
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
QLIST_REMOVE(hdev, entry);
|
||||
hdev->nvqs = n_initialized_vqs;
|
||||
vhost_dev_cleanup(hdev);
|
||||
return r;
|
||||
}
|
||||
|
||||
void vhost_dev_cleanup(struct vhost_dev *hdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < hdev->nvqs; ++i) {
|
||||
vhost_virtqueue_cleanup(hdev->vqs + i);
|
||||
}
|
||||
memory_listener_unregister(&hdev->memory_listener);
|
||||
if (hdev->mem) {
|
||||
/* those are only safe after successful init */
|
||||
memory_listener_unregister(&hdev->memory_listener);
|
||||
QLIST_REMOVE(hdev, entry);
|
||||
}
|
||||
if (hdev->migration_blocker) {
|
||||
migrate_del_blocker(hdev->migration_blocker);
|
||||
error_free(hdev->migration_blocker);
|
||||
}
|
||||
g_free(hdev->mem);
|
||||
g_free(hdev->mem_sections);
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
QLIST_REMOVE(hdev, entry);
|
||||
if (hdev->vhost_ops) {
|
||||
hdev->vhost_ops->vhost_backend_cleanup(hdev);
|
||||
}
|
||||
assert(!hdev->log);
|
||||
|
||||
memset(hdev, 0, sizeof(struct vhost_dev));
|
||||
}
|
||||
|
||||
/* Stop processing guest IO notifications in qemu.
|
||||
|
@ -1148,8 +1175,9 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
VirtioBusState *vbus = VIRTIO_BUS(qbus);
|
||||
VirtioBusClass *k = VIRTIO_BUS_GET_CLASS(vbus);
|
||||
int i, r, e;
|
||||
|
||||
if (!k->ioeventfd_started) {
|
||||
fprintf(stderr, "binding does not support host notifiers\n");
|
||||
error_report("binding does not support host notifiers");
|
||||
r = -ENOSYS;
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1158,7 +1186,7 @@ int vhost_dev_enable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
|
||||
true);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "vhost VQ %d notifier binding failed: %d\n", i, -r);
|
||||
error_report("vhost VQ %d notifier binding failed: %d", i, -r);
|
||||
goto fail_vq;
|
||||
}
|
||||
}
|
||||
|
@ -1169,8 +1197,7 @@ fail_vq:
|
|||
e = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
|
||||
false);
|
||||
if (e < 0) {
|
||||
fprintf(stderr, "vhost VQ %d notifier cleanup error: %d\n", i, -r);
|
||||
fflush(stderr);
|
||||
error_report("vhost VQ %d notifier cleanup error: %d", i, -r);
|
||||
}
|
||||
assert (e >= 0);
|
||||
}
|
||||
|
@ -1192,8 +1219,7 @@ void vhost_dev_disable_notifiers(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
r = virtio_bus_set_host_notifier(VIRTIO_BUS(qbus), hdev->vq_index + i,
|
||||
false);
|
||||
if (r < 0) {
|
||||
fprintf(stderr, "vhost VQ %d notifier cleanup failed: %d\n", i, -r);
|
||||
fflush(stderr);
|
||||
error_report("vhost VQ %d notifier cleanup failed: %d", i, -r);
|
||||
}
|
||||
assert (r >= 0);
|
||||
}
|
||||
|
@ -1217,6 +1243,9 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
|
|||
int r, index = n - hdev->vq_index;
|
||||
struct vhost_vring_file file;
|
||||
|
||||
/* should only be called after backend is connected */
|
||||
assert(hdev->vhost_ops);
|
||||
|
||||
if (mask) {
|
||||
assert(vdev->use_guest_notifier_mask);
|
||||
file.fd = event_notifier_get_fd(&hdev->vqs[index].masked_notifier);
|
||||
|
@ -1226,7 +1255,9 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
|
|||
|
||||
file.index = hdev->vhost_ops->vhost_get_vq_index(hdev, n);
|
||||
r = hdev->vhost_ops->vhost_set_vring_call(hdev, &file);
|
||||
assert(r >= 0);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_vring_call failed");
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
|
||||
|
@ -1261,6 +1292,9 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
{
|
||||
int i, r;
|
||||
|
||||
/* should only be called after backend is connected */
|
||||
assert(hdev->vhost_ops);
|
||||
|
||||
hdev->started = true;
|
||||
|
||||
r = vhost_dev_set_features(hdev, hdev->log_enabled);
|
||||
|
@ -1269,6 +1303,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
}
|
||||
r = hdev->vhost_ops->vhost_set_mem_table(hdev, hdev->mem);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_mem_table failed");
|
||||
r = -errno;
|
||||
goto fail_mem;
|
||||
}
|
||||
|
@ -1293,6 +1328,7 @@ int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
hdev->log_size ? log_base : 0,
|
||||
hdev->log);
|
||||
if (r < 0) {
|
||||
VHOST_OPS_DEBUG("vhost_set_log_base failed");
|
||||
r = -errno;
|
||||
goto fail_log;
|
||||
}
|
||||
|
@ -1321,6 +1357,9 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
{
|
||||
int i;
|
||||
|
||||
/* should only be called after backend is connected */
|
||||
assert(hdev->vhost_ops);
|
||||
|
||||
for (i = 0; i < hdev->nvqs; ++i) {
|
||||
vhost_virtqueue_stop(hdev,
|
||||
vdev,
|
||||
|
@ -1330,7 +1369,14 @@ void vhost_dev_stop(struct vhost_dev *hdev, VirtIODevice *vdev)
|
|||
|
||||
vhost_log_put(hdev, true);
|
||||
hdev->started = false;
|
||||
hdev->log = NULL;
|
||||
hdev->log_size = 0;
|
||||
}
|
||||
|
||||
int vhost_net_set_backend(struct vhost_dev *hdev,
|
||||
struct vhost_vring_file *file)
|
||||
{
|
||||
if (hdev->vhost_ops->vhost_net_set_backend) {
|
||||
return hdev->vhost_ops->vhost_net_set_backend(hdev, file);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -161,7 +161,7 @@ static bool virtio_pci_modern_state_needed(void *opaque)
|
|||
{
|
||||
VirtIOPCIProxy *proxy = opaque;
|
||||
|
||||
return !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
|
||||
return virtio_pci_modern(proxy);
|
||||
}
|
||||
|
||||
static const VMStateDescription vmstate_virtio_pci_modern_state = {
|
||||
|
@ -300,8 +300,8 @@ static int virtio_pci_ioeventfd_assign(DeviceState *d, EventNotifier *notifier,
|
|||
VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d);
|
||||
VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus);
|
||||
VirtQueue *vq = virtio_get_queue(vdev, n);
|
||||
bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
|
||||
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
|
||||
bool legacy = virtio_pci_legacy(proxy);
|
||||
bool modern = virtio_pci_modern(proxy);
|
||||
bool fast_mmio = kvm_ioeventfd_any_length_enabled();
|
||||
bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
|
||||
MemoryRegion *modern_mr = &proxy->notify.mr;
|
||||
|
@ -1574,8 +1574,8 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
|
|||
{
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
|
||||
VirtioBusState *bus = &proxy->bus;
|
||||
bool legacy = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_LEGACY);
|
||||
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
|
||||
bool legacy = virtio_pci_legacy(proxy);
|
||||
bool modern = virtio_pci_modern(proxy);
|
||||
bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
|
||||
uint8_t *config;
|
||||
uint32_t size;
|
||||
|
@ -1694,7 +1694,7 @@ static void virtio_pci_device_plugged(DeviceState *d, Error **errp)
|
|||
static void virtio_pci_device_unplugged(DeviceState *d)
|
||||
{
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(d);
|
||||
bool modern = !(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN);
|
||||
bool modern = virtio_pci_modern(proxy);
|
||||
bool modern_pio = proxy->flags & VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY;
|
||||
|
||||
virtio_pci_stop_ioeventfd(proxy);
|
||||
|
@ -1714,6 +1714,8 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
|
|||
{
|
||||
VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev);
|
||||
VirtioPCIClass *k = VIRTIO_PCI_GET_CLASS(pci_dev);
|
||||
bool pcie_port = pci_bus_is_express(pci_dev->bus) &&
|
||||
!pci_bus_is_root(pci_dev->bus);
|
||||
|
||||
/*
|
||||
* virtio pci bar layout used by default.
|
||||
|
@ -1764,8 +1766,11 @@ static void virtio_pci_realize(PCIDevice *pci_dev, Error **errp)
|
|||
|
||||
address_space_init(&proxy->modern_as, &proxy->modern_cfg, "virtio-pci-cfg-as");
|
||||
|
||||
if (pci_is_express(pci_dev) && pci_bus_is_express(pci_dev->bus) &&
|
||||
!pci_bus_is_root(pci_dev->bus)) {
|
||||
if (proxy->disable_legacy == ON_OFF_AUTO_AUTO) {
|
||||
proxy->disable_legacy = pcie_port ? ON_OFF_AUTO_ON : ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
if (pcie_port && pci_is_express(pci_dev)) {
|
||||
int pos;
|
||||
|
||||
pos = pcie_endpoint_cap_init(pci_dev, 0);
|
||||
|
@ -1819,10 +1824,9 @@ static void virtio_pci_reset(DeviceState *qdev)
|
|||
static Property virtio_pci_properties[] = {
|
||||
DEFINE_PROP_BIT("virtio-pci-bus-master-bug-migration", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT, false),
|
||||
DEFINE_PROP_BIT("disable-legacy", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT, false),
|
||||
DEFINE_PROP_BIT("disable-modern", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT, true),
|
||||
DEFINE_PROP_ON_OFF_AUTO("disable-legacy", VirtIOPCIProxy, disable_legacy,
|
||||
ON_OFF_AUTO_AUTO),
|
||||
DEFINE_PROP_BOOL("disable-modern", VirtIOPCIProxy, disable_modern, false),
|
||||
DEFINE_PROP_BIT("migrate-extra", VirtIOPCIProxy, flags,
|
||||
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT, true),
|
||||
DEFINE_PROP_BIT("modern-pio-notify", VirtIOPCIProxy, flags,
|
||||
|
@ -1839,7 +1843,7 @@ static void virtio_pci_dc_realize(DeviceState *qdev, Error **errp)
|
|||
PCIDevice *pci_dev = &proxy->pci_dev;
|
||||
|
||||
if (!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_PCIE) &&
|
||||
!(proxy->flags & VIRTIO_PCI_FLAG_DISABLE_MODERN)) {
|
||||
virtio_pci_modern(proxy)) {
|
||||
pci_dev->cap_present |= QEMU_PCI_CAP_EXPRESS;
|
||||
}
|
||||
|
||||
|
@ -2301,9 +2305,7 @@ static void virtio_input_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp)
|
|||
DeviceState *vdev = DEVICE(&vinput->vdev);
|
||||
|
||||
qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
|
||||
/* force virtio-1.0 */
|
||||
vpci_dev->flags &= ~VIRTIO_PCI_FLAG_DISABLE_MODERN;
|
||||
vpci_dev->flags |= VIRTIO_PCI_FLAG_DISABLE_LEGACY;
|
||||
virtio_pci_force_virtio_1(vpci_dev);
|
||||
object_property_set_bool(OBJECT(vdev), true, "realized", errp);
|
||||
}
|
||||
|
||||
|
|
|
@ -61,8 +61,6 @@ typedef struct VirtioBusClass VirtioPCIBusClass;
|
|||
enum {
|
||||
VIRTIO_PCI_FLAG_BUS_MASTER_BUG_MIGRATION_BIT,
|
||||
VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT,
|
||||
VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT,
|
||||
VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT,
|
||||
VIRTIO_PCI_FLAG_MIGRATE_EXTRA_BIT,
|
||||
VIRTIO_PCI_FLAG_MODERN_PIO_NOTIFY_BIT,
|
||||
VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT,
|
||||
|
@ -77,8 +75,6 @@ enum {
|
|||
#define VIRTIO_PCI_FLAG_USE_IOEVENTFD (1 << VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT)
|
||||
|
||||
/* virtio version flags */
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_LEGACY (1 << VIRTIO_PCI_FLAG_DISABLE_LEGACY_BIT)
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_MODERN (1 << VIRTIO_PCI_FLAG_DISABLE_MODERN_BIT)
|
||||
#define VIRTIO_PCI_FLAG_DISABLE_PCIE (1 << VIRTIO_PCI_FLAG_DISABLE_PCIE_BIT)
|
||||
|
||||
/* migrate extra state */
|
||||
|
@ -144,6 +140,8 @@ struct VirtIOPCIProxy {
|
|||
uint32_t modern_mem_bar;
|
||||
int config_cap;
|
||||
uint32_t flags;
|
||||
bool disable_modern;
|
||||
OnOffAuto disable_legacy;
|
||||
uint32_t class_code;
|
||||
uint32_t nvectors;
|
||||
uint32_t dfselect;
|
||||
|
@ -158,6 +156,21 @@ struct VirtIOPCIProxy {
|
|||
VirtioBusState bus;
|
||||
};
|
||||
|
||||
static inline bool virtio_pci_modern(VirtIOPCIProxy *proxy)
|
||||
{
|
||||
return !proxy->disable_modern;
|
||||
}
|
||||
|
||||
static inline bool virtio_pci_legacy(VirtIOPCIProxy *proxy)
|
||||
{
|
||||
return proxy->disable_legacy == ON_OFF_AUTO_OFF;
|
||||
}
|
||||
|
||||
static inline void virtio_pci_force_virtio_1(VirtIOPCIProxy *proxy)
|
||||
{
|
||||
proxy->disable_modern = false;
|
||||
proxy->disable_legacy = ON_OFF_AUTO_ON;
|
||||
}
|
||||
|
||||
/*
|
||||
* virtio-scsi-pci: This extends VirtioPCIProxy.
|
||||
|
|
|
@ -458,6 +458,11 @@ static void virtqueue_map_desc(unsigned int *p_num_sg, hwaddr *addr, struct iove
|
|||
unsigned num_sg = *p_num_sg;
|
||||
assert(num_sg <= max_num_sg);
|
||||
|
||||
if (!sz) {
|
||||
error_report("virtio: zero sized buffers are not allowed");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
while (sz) {
|
||||
hwaddr len = sz;
|
||||
|
||||
|
|
|
@ -6,6 +6,14 @@
|
|||
.driver = "virtio-mmio",\
|
||||
.property = "format_transport_address",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = "virtio-pci",\
|
||||
.property = "disable-modern",\
|
||||
.value = "on",\
|
||||
},{\
|
||||
.driver = "virtio-pci",\
|
||||
.property = "disable-legacy",\
|
||||
.value = "off",\
|
||||
},
|
||||
|
||||
#define HW_COMPAT_2_5 \
|
||||
|
@ -80,6 +88,10 @@
|
|||
.driver = "virtio-rng-pci",\
|
||||
.property = "any_layout",\
|
||||
.value = "off",\
|
||||
},{\
|
||||
.driver = TYPE_PCI_DEVICE,\
|
||||
.property = "x-pcie-lnksta-dllla",\
|
||||
.value = "off",\
|
||||
},
|
||||
|
||||
#define HW_COMPAT_2_2 \
|
||||
|
|
|
@ -174,6 +174,9 @@ enum {
|
|||
/* PCI Express capability - Power Controller Present */
|
||||
#define QEMU_PCIE_SLTCAP_PCP_BITNR 7
|
||||
QEMU_PCIE_SLTCAP_PCP = (1 << QEMU_PCIE_SLTCAP_PCP_BITNR),
|
||||
/* Link active status in endpoint capability is always set */
|
||||
#define QEMU_PCIE_LNKSTA_DLLLA_BITNR 8
|
||||
QEMU_PCIE_LNKSTA_DLLLA = (1 << QEMU_PCIE_LNKSTA_DLLLA_BITNR),
|
||||
};
|
||||
|
||||
#define TYPE_PCI_DEVICE "pci-device"
|
||||
|
|
|
@ -86,4 +86,8 @@ uint64_t vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
|
|||
void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits,
|
||||
uint64_t features);
|
||||
bool vhost_has_free_slot(void);
|
||||
|
||||
int vhost_net_set_backend(struct vhost_dev *hdev,
|
||||
struct vhost_vring_file *file);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,6 +70,7 @@ struct CharDriverState {
|
|||
int (*get_msgfds)(struct CharDriverState *s, int* fds, int num);
|
||||
int (*set_msgfds)(struct CharDriverState *s, int *fds, int num);
|
||||
int (*chr_add_client)(struct CharDriverState *chr, int fd);
|
||||
int (*chr_wait_connected)(struct CharDriverState *chr, Error **errp);
|
||||
IOEventHandler *chr_event;
|
||||
IOCanReadHandler *chr_can_read;
|
||||
IOReadHandler *chr_read;
|
||||
|
@ -158,6 +159,13 @@ void qemu_chr_disconnect(CharDriverState *chr);
|
|||
*/
|
||||
void qemu_chr_cleanup(void);
|
||||
|
||||
/**
|
||||
* @qemu_chr_wait_connected:
|
||||
*
|
||||
* Wait for characted backend to be connected.
|
||||
*/
|
||||
int qemu_chr_wait_connected(CharDriverState *chr, Error **errp);
|
||||
|
||||
/**
|
||||
* @qemu_chr_new_noreplay:
|
||||
*
|
||||
|
|
|
@ -312,6 +312,7 @@ static void tap_cleanup(NetClientState *nc)
|
|||
|
||||
if (s->vhost_net) {
|
||||
vhost_net_cleanup(s->vhost_net);
|
||||
g_free(s->vhost_net);
|
||||
s->vhost_net = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ typedef struct VhostUserState {
|
|||
VHostNetState *vhost_net;
|
||||
guint watch;
|
||||
uint64_t acked_features;
|
||||
bool started;
|
||||
} VhostUserState;
|
||||
|
||||
typedef struct VhostUserChardevProps {
|
||||
|
@ -45,11 +46,6 @@ uint64_t vhost_user_get_acked_features(NetClientState *nc)
|
|||
return s->acked_features;
|
||||
}
|
||||
|
||||
static int vhost_user_running(VhostUserState *s)
|
||||
{
|
||||
return (s->vhost_net) ? 1 : 0;
|
||||
}
|
||||
|
||||
static void vhost_user_stop(int queues, NetClientState *ncs[])
|
||||
{
|
||||
VhostUserState *s;
|
||||
|
@ -59,15 +55,14 @@ static void vhost_user_stop(int queues, NetClientState *ncs[])
|
|||
assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
|
||||
|
||||
s = DO_UPCAST(VhostUserState, nc, ncs[i]);
|
||||
if (!vhost_user_running(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (s->vhost_net) {
|
||||
/* save acked features */
|
||||
s->acked_features = vhost_net_get_acked_features(s->vhost_net);
|
||||
uint64_t features = vhost_net_get_acked_features(s->vhost_net);
|
||||
if (features) {
|
||||
s->acked_features = features;
|
||||
}
|
||||
vhost_net_cleanup(s->vhost_net);
|
||||
s->vhost_net = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -75,6 +70,7 @@ static void vhost_user_stop(int queues, NetClientState *ncs[])
|
|||
static int vhost_user_start(int queues, NetClientState *ncs[])
|
||||
{
|
||||
VhostNetOptions options;
|
||||
struct vhost_net *net = NULL;
|
||||
VhostUserState *s;
|
||||
int max_queues;
|
||||
int i;
|
||||
|
@ -85,33 +81,39 @@ static int vhost_user_start(int queues, NetClientState *ncs[])
|
|||
assert(ncs[i]->info->type == NET_CLIENT_DRIVER_VHOST_USER);
|
||||
|
||||
s = DO_UPCAST(VhostUserState, nc, ncs[i]);
|
||||
if (vhost_user_running(s)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
options.net_backend = ncs[i];
|
||||
options.opaque = s->chr;
|
||||
options.busyloop_timeout = 0;
|
||||
s->vhost_net = vhost_net_init(&options);
|
||||
if (!s->vhost_net) {
|
||||
net = vhost_net_init(&options);
|
||||
if (!net) {
|
||||
error_report("failed to init vhost_net for queue %d", i);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (i == 0) {
|
||||
max_queues = vhost_net_get_max_queues(s->vhost_net);
|
||||
max_queues = vhost_net_get_max_queues(net);
|
||||
if (queues > max_queues) {
|
||||
error_report("you are asking more queues than supported: %d",
|
||||
max_queues);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (s->vhost_net) {
|
||||
vhost_net_cleanup(s->vhost_net);
|
||||
g_free(s->vhost_net);
|
||||
}
|
||||
s->vhost_net = net;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
vhost_user_stop(i + 1, ncs);
|
||||
if (net) {
|
||||
vhost_net_cleanup(net);
|
||||
}
|
||||
vhost_user_stop(i, ncs);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -150,6 +152,7 @@ static void vhost_user_cleanup(NetClientState *nc)
|
|||
|
||||
if (s->vhost_net) {
|
||||
vhost_net_cleanup(s->vhost_net);
|
||||
g_free(s->vhost_net);
|
||||
s->vhost_net = NULL;
|
||||
}
|
||||
if (s->chr) {
|
||||
|
@ -188,12 +191,8 @@ static gboolean net_vhost_user_watch(GIOChannel *chan, GIOCondition cond,
|
|||
void *opaque)
|
||||
{
|
||||
VhostUserState *s = opaque;
|
||||
uint8_t buf[1];
|
||||
|
||||
/* We don't actually want to read anything, but CHR_EVENT_CLOSED will be
|
||||
* raised as a side-effect of the read.
|
||||
*/
|
||||
qemu_chr_fe_read_all(s->chr, buf, sizeof(buf));
|
||||
qemu_chr_disconnect(s->chr);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
@ -222,6 +221,7 @@ static void net_vhost_user_event(void *opaque, int event)
|
|||
return;
|
||||
}
|
||||
qmp_set_link(name, true, &err);
|
||||
s->started = true;
|
||||
break;
|
||||
case CHR_EVENT_CLOSED:
|
||||
qmp_set_link(name, false, &err);
|
||||
|
@ -240,7 +240,7 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
|
|||
const char *name, CharDriverState *chr,
|
||||
int queues)
|
||||
{
|
||||
NetClientState *nc;
|
||||
NetClientState *nc, *nc0 = NULL;
|
||||
VhostUserState *s;
|
||||
int i;
|
||||
|
||||
|
@ -249,6 +249,9 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
|
|||
|
||||
for (i = 0; i < queues; i++) {
|
||||
nc = qemu_new_net_client(&net_vhost_user_info, peer, device, name);
|
||||
if (!nc0) {
|
||||
nc0 = nc;
|
||||
}
|
||||
|
||||
snprintf(nc->info_str, sizeof(nc->info_str), "vhost-user%d to %s",
|
||||
i, chr->label);
|
||||
|
@ -259,7 +262,18 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
|
|||
s->chr = chr;
|
||||
}
|
||||
|
||||
qemu_chr_add_handlers(chr, NULL, NULL, net_vhost_user_event, nc[0].name);
|
||||
s = DO_UPCAST(VhostUserState, nc, nc0);
|
||||
do {
|
||||
Error *err = NULL;
|
||||
if (qemu_chr_wait_connected(chr, &err) < 0) {
|
||||
error_report_err(err);
|
||||
return -1;
|
||||
}
|
||||
qemu_chr_add_handlers(chr, NULL, NULL,
|
||||
net_vhost_user_event, nc0->name);
|
||||
} while (!s->started);
|
||||
|
||||
assert(s->vhost_net);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -316,7 +330,6 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
|
|||
{
|
||||
const char *name = opaque;
|
||||
const char *driver, *netdev;
|
||||
const char virtio_name[] = "virtio-net-";
|
||||
|
||||
driver = qemu_opt_get(opts, "driver");
|
||||
netdev = qemu_opt_get(opts, "netdev");
|
||||
|
@ -326,7 +339,7 @@ static int net_vhost_check_net(void *opaque, QemuOpts *opts, Error **errp)
|
|||
}
|
||||
|
||||
if (strcmp(netdev, name) == 0 &&
|
||||
strncmp(driver, virtio_name, strlen(virtio_name)) != 0) {
|
||||
!g_str_has_prefix(driver, "virtio-net-")) {
|
||||
error_setg(errp, "vhost-user requires frontend driver virtio-net-*");
|
||||
return -1;
|
||||
}
|
||||
|
|
82
qemu-char.c
82
qemu-char.c
|
@ -2760,14 +2760,16 @@ static int tcp_set_msgfds(CharDriverState *chr, int *fds, int num)
|
|||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
|
||||
if (!qio_channel_has_feature(s->ioc,
|
||||
QIO_CHANNEL_FEATURE_FD_PASS)) {
|
||||
return -1;
|
||||
}
|
||||
/* clear old pending fd array */
|
||||
g_free(s->write_msgfds);
|
||||
s->write_msgfds = NULL;
|
||||
|
||||
if (!s->connected ||
|
||||
!qio_channel_has_feature(s->ioc,
|
||||
QIO_CHANNEL_FEATURE_FD_PASS)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (num) {
|
||||
s->write_msgfds = g_new(int, num);
|
||||
memcpy(s->write_msgfds, fds, num * sizeof(int));
|
||||
|
@ -3137,6 +3139,41 @@ static gboolean tcp_chr_accept(QIOChannel *channel,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static int tcp_chr_wait_connected(CharDriverState *chr, Error **errp)
|
||||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
QIOChannelSocket *sioc;
|
||||
|
||||
while (!s->connected) {
|
||||
if (s->is_listen) {
|
||||
fprintf(stderr, "QEMU waiting for connection on: %s\n",
|
||||
chr->filename);
|
||||
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), true, NULL);
|
||||
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
|
||||
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
|
||||
} else {
|
||||
sioc = qio_channel_socket_new();
|
||||
if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
|
||||
object_unref(OBJECT(sioc));
|
||||
return -1;
|
||||
}
|
||||
tcp_chr_new_client(chr, sioc);
|
||||
object_unref(OBJECT(sioc));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int qemu_chr_wait_connected(CharDriverState *chr, Error **errp)
|
||||
{
|
||||
if (chr->chr_wait_connected) {
|
||||
return chr->chr_wait_connected(chr, errp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tcp_chr_close(CharDriverState *chr)
|
||||
{
|
||||
TCPCharDriver *s = chr->opaque;
|
||||
|
@ -4391,6 +4428,7 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
|
|||
s->addr = QAPI_CLONE(SocketAddress, sock->addr);
|
||||
|
||||
chr->opaque = s;
|
||||
chr->chr_wait_connected = tcp_chr_wait_connected;
|
||||
chr->chr_write = tcp_chr_write;
|
||||
chr->chr_sync_read = tcp_chr_sync_read;
|
||||
chr->chr_close = tcp_chr_close;
|
||||
|
@ -4414,32 +4452,30 @@ static CharDriverState *qmp_chardev_open_socket(const char *id,
|
|||
s->reconnect_time = reconnect;
|
||||
}
|
||||
|
||||
sioc = qio_channel_socket_new();
|
||||
if (s->reconnect_time) {
|
||||
sioc = qio_channel_socket_new();
|
||||
qio_channel_socket_connect_async(sioc, s->addr,
|
||||
qemu_chr_socket_connected,
|
||||
chr, NULL);
|
||||
} else if (s->is_listen) {
|
||||
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
s->listen_ioc = sioc;
|
||||
if (is_waitconnect) {
|
||||
fprintf(stderr, "QEMU waiting for connection on: %s\n",
|
||||
chr->filename);
|
||||
tcp_chr_accept(QIO_CHANNEL(s->listen_ioc), G_IO_IN, chr);
|
||||
}
|
||||
qio_channel_set_blocking(QIO_CHANNEL(s->listen_ioc), false, NULL);
|
||||
if (!s->ioc) {
|
||||
s->listen_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(s->listen_ioc), G_IO_IN, tcp_chr_accept, chr, NULL);
|
||||
}
|
||||
} else {
|
||||
if (qio_channel_socket_connect_sync(sioc, s->addr, errp) < 0) {
|
||||
if (s->is_listen) {
|
||||
sioc = qio_channel_socket_new();
|
||||
if (qio_channel_socket_listen_sync(sioc, s->addr, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
s->listen_ioc = sioc;
|
||||
if (is_waitconnect &&
|
||||
qemu_chr_wait_connected(chr, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (!s->ioc) {
|
||||
s->listen_tag = qio_channel_add_watch(
|
||||
QIO_CHANNEL(s->listen_ioc), G_IO_IN,
|
||||
tcp_chr_accept, chr, NULL);
|
||||
}
|
||||
} else if (qemu_chr_wait_connected(chr, errp) < 0) {
|
||||
goto error;
|
||||
}
|
||||
tcp_chr_new_client(chr, sioc);
|
||||
object_unref(OBJECT(sioc));
|
||||
}
|
||||
|
||||
return chr;
|
||||
|
|
|
@ -683,6 +683,7 @@ static void test_reconnect(void)
|
|||
qtest_get_arch());
|
||||
g_test_trap_subprocess(path, 0, 0);
|
||||
g_test_trap_assert_passed();
|
||||
g_free(path);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -149,6 +149,7 @@ static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev,
|
|||
char test[] = "TEST";
|
||||
char buffer[64];
|
||||
int len = htonl(sizeof(test));
|
||||
QDict *rsp;
|
||||
struct iovec iov[] = {
|
||||
{
|
||||
.iov_base = &len,
|
||||
|
@ -165,7 +166,8 @@ static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev,
|
|||
free_head = qvirtqueue_add(vq, req_addr, 64, true, false);
|
||||
qvirtqueue_kick(bus, dev, vq, free_head);
|
||||
|
||||
qmp("{ 'execute' : 'stop'}");
|
||||
rsp = qmp("{ 'execute' : 'stop'}");
|
||||
QDECREF(rsp);
|
||||
|
||||
ret = iov_send(socket, iov, 2, 0, sizeof(len) + sizeof(test));
|
||||
g_assert_cmpint(ret, ==, sizeof(test) + sizeof(len));
|
||||
|
@ -173,8 +175,10 @@ static void rx_stop_cont_test(const QVirtioBus *bus, QVirtioDevice *dev,
|
|||
/* We could check the status, but this command is more importantly to
|
||||
* ensure the packet data gets queued in QEMU, before we do 'cont'.
|
||||
*/
|
||||
qmp("{ 'execute' : 'query-status'}");
|
||||
qmp("{ 'execute' : 'cont'}");
|
||||
rsp = qmp("{ 'execute' : 'query-status'}");
|
||||
QDECREF(rsp);
|
||||
rsp = qmp("{ 'execute' : 'cont'}");
|
||||
QDECREF(rsp);
|
||||
|
||||
qvirtio_wait_queue_isr(bus, dev, vq, QVIRTIO_NET_TIMEOUT_US);
|
||||
memread(req_addr + VNET_HDR_SIZE, buffer, sizeof(test));
|
||||
|
@ -230,8 +234,10 @@ static void pci_basic(gconstpointer data)
|
|||
/* End test */
|
||||
close(sv[0]);
|
||||
qvirtqueue_cleanup(&qvirtio_pci, &tx->vq, alloc);
|
||||
qvirtqueue_cleanup(&qvirtio_pci, &rx->vq, alloc);
|
||||
pc_alloc_uninit(alloc);
|
||||
qvirtio_pci_device_disable(dev);
|
||||
g_free(dev->pdev);
|
||||
g_free(dev);
|
||||
qpci_free_pc(bus);
|
||||
test_end();
|
||||
|
|
Loading…
Reference in New Issue