diff options
-rw-r--r-- | hw/9pfs/virtio-9p-device.c | 43 | ||||
-rw-r--r-- | hw/block/dataplane/virtio-blk.c | 30 | ||||
-rw-r--r-- | hw/block/dataplane/virtio-blk.h | 5 | ||||
-rw-r--r-- | hw/block/virtio-blk.c | 47 | ||||
-rw-r--r-- | hw/char/virtio-serial-bus.c | 33 | ||||
-rw-r--r-- | hw/net/virtio-net.c | 36 | ||||
-rw-r--r-- | hw/s390x/virtio-ccw.c | 83 | ||||
-rw-r--r-- | hw/s390x/virtio-ccw.h | 1 | ||||
-rw-r--r-- | hw/scsi/vhost-scsi.c | 45 | ||||
-rw-r--r-- | hw/scsi/virtio-scsi.c | 57 | ||||
-rw-r--r-- | hw/virtio/virtio-balloon.c | 32 | ||||
-rw-r--r-- | hw/virtio/virtio-bus.c | 80 | ||||
-rw-r--r-- | hw/virtio/virtio-mmio.c | 9 | ||||
-rw-r--r-- | hw/virtio/virtio-pci.c | 122 | ||||
-rw-r--r-- | hw/virtio/virtio-pci.h | 1 | ||||
-rw-r--r-- | hw/virtio/virtio-rng.c | 43 | ||||
-rw-r--r-- | hw/virtio/virtio.c | 40 | ||||
-rw-r--r-- | include/hw/virtio/virtio-bus.h | 22 | ||||
-rw-r--r-- | include/hw/virtio/virtio-rng.h | 2 | ||||
-rw-r--r-- | include/hw/virtio/virtio-scsi.h | 4 | ||||
-rw-r--r-- | include/hw/virtio/virtio.h | 8 | ||||
-rw-r--r-- | tests/qdev-monitor-test.c | 4 |
22 files changed, 413 insertions, 334 deletions
diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index f0ffbe8c0d..15a4983eee 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -41,15 +41,16 @@ static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config) g_free(cfg); } -static int virtio_9p_device_init(VirtIODevice *vdev) +static void virtio_9p_device_realize(DeviceState *dev, Error **errp) { - V9fsState *s = VIRTIO_9P(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + V9fsState *s = VIRTIO_9P(dev); int i, len; struct stat stat; FsDriverEntry *fse; V9fsPath path; - virtio_init(VIRTIO_DEVICE(s), "virtio-9p", VIRTIO_ID_9P, + virtio_init(vdev, "virtio-9p", VIRTIO_ID_9P, sizeof(struct virtio_9p_config) + MAX_TAG_LEN); /* initialize pdu allocator */ @@ -67,16 +68,16 @@ static int virtio_9p_device_init(VirtIODevice *vdev) if (!fse) { /* We don't have a fsdev identified by fsdev_id */ - fprintf(stderr, "Virtio-9p device couldn't find fsdev with the " - "id = %s\n", - s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL"); + error_setg(errp, "Virtio-9p device couldn't find fsdev with the " + "id = %s", + s->fsconf.fsdev_id ? s->fsconf.fsdev_id : "NULL"); goto out; } if (!s->fsconf.tag) { /* we haven't specified a mount_tag */ - fprintf(stderr, "fsdev with id %s needs mount_tag arguments\n", - s->fsconf.fsdev_id); + error_setg(errp, "fsdev with id %s needs mount_tag arguments", + s->fsconf.fsdev_id); goto out; } @@ -85,8 +86,8 @@ static int virtio_9p_device_init(VirtIODevice *vdev) s->ctx.exops.get_st_gen = NULL; len = strlen(s->fsconf.tag); if (len > MAX_TAG_LEN - 1) { - fprintf(stderr, "mount tag '%s' (%d bytes) is longer than " - "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1); + error_setg(errp, "mount tag '%s' (%d bytes) is longer than " + "maximum (%d bytes)", s->fsconf.tag, len, MAX_TAG_LEN - 1); goto out; } @@ -99,12 +100,12 @@ static int virtio_9p_device_init(VirtIODevice *vdev) qemu_co_rwlock_init(&s->rename_lock); if (s->ops->init(&s->ctx) < 0) { - fprintf(stderr, "Virtio-9p Failed to initialize fs-driver with id:%s" - " and export path:%s\n", s->fsconf.fsdev_id, s->ctx.fs_root); + error_setg(errp, "Virtio-9p Failed to initialize fs-driver with id:%s" + " and export path:%s", s->fsconf.fsdev_id, s->ctx.fs_root); goto out; } if (v9fs_init_worker_threads() < 0) { - fprintf(stderr, "worker thread initialization failed\n"); + error_setg(errp, "worker thread initialization failed"); goto out; } @@ -114,28 +115,25 @@ static int virtio_9p_device_init(VirtIODevice *vdev) * use co-routines here. */ if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { - fprintf(stderr, - "error in converting name to path %s", strerror(errno)); + error_setg(errp, + "error in converting name to path %s", strerror(errno)); goto out; } if (s->ops->lstat(&s->ctx, &path, &stat)) { - fprintf(stderr, "share path %s does not exist\n", fse->path); + error_setg(errp, "share path %s does not exist", fse->path); goto out; } else if (!S_ISDIR(stat.st_mode)) { - fprintf(stderr, "share path %s is not a directory\n", fse->path); + error_setg(errp, "share path %s is not a directory", fse->path); goto out; } v9fs_path_free(&path); - return 0; + return; out: g_free(s->ctx.fs_root); g_free(s->tag); virtio_cleanup(vdev); v9fs_path_free(&path); - - return -1; - } /* virtio-9p device */ @@ -149,9 +147,10 @@ static void virtio_9p_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + dc->props = virtio_9p_properties; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - vdc->init = virtio_9p_device_init; + vdc->realize = virtio_9p_device_realize; vdc->get_features = virtio_9p_get_features; vdc->get_config = virtio_9p_get_config; } diff --git a/hw/block/dataplane/virtio-blk.c b/hw/block/dataplane/virtio-blk.c index f2d7350a50..1e57f3aabd 100644 --- a/hw/block/dataplane/virtio-blk.c +++ b/hw/block/dataplane/virtio-blk.c @@ -380,8 +380,9 @@ static void start_data_plane_bh(void *opaque) s, QEMU_THREAD_JOINABLE); } -bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, - VirtIOBlockDataPlane **dataplane) +void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, + VirtIOBlockDataPlane **dataplane, + Error **errp) { VirtIOBlockDataPlane *s; int fd; @@ -389,33 +390,35 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, *dataplane = NULL; if (!blk->data_plane) { - return true; + return; } if (blk->scsi) { - error_report("device is incompatible with x-data-plane, use scsi=off"); - return false; + error_setg(errp, + "device is incompatible with x-data-plane, use scsi=off"); + return; } if (blk->config_wce) { - error_report("device is incompatible with x-data-plane, " - "use config-wce=off"); - return false; + error_setg(errp, "device is incompatible with x-data-plane, " + "use config-wce=off"); + return; } /* If dataplane is (re-)enabled while the guest is running there could be * block jobs that can conflict. */ if (bdrv_in_use(blk->conf.bs)) { - error_report("cannot start dataplane thread while device is in use"); - return false; + error_setg(errp, + "cannot start dataplane thread while device is in use"); + return; } fd = raw_get_aio_fd(blk->conf.bs); if (fd < 0) { - error_report("drive is incompatible with x-data-plane, " - "use format=raw,cache=none,aio=native"); - return false; + error_setg(errp, "drive is incompatible with x-data-plane, " + "use format=raw,cache=none,aio=native"); + return; } s = g_new0(VirtIOBlockDataPlane, 1); @@ -427,7 +430,6 @@ bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, bdrv_set_in_use(blk->conf.bs, 1); *dataplane = s; - return true; } void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s) diff --git a/hw/block/dataplane/virtio-blk.h b/hw/block/dataplane/virtio-blk.h index c90e99f48f..1750c9905b 100644 --- a/hw/block/dataplane/virtio-blk.h +++ b/hw/block/dataplane/virtio-blk.h @@ -19,8 +19,9 @@ typedef struct VirtIOBlockDataPlane VirtIOBlockDataPlane; -bool virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, - VirtIOBlockDataPlane **dataplane); +void virtio_blk_data_plane_create(VirtIODevice *vdev, VirtIOBlkConf *blk, + VirtIOBlockDataPlane **dataplane, + Error **errp); void virtio_blk_data_plane_destroy(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_start(VirtIOBlockDataPlane *s); void virtio_blk_data_plane_stop(VirtIOBlockDataPlane *s); diff --git a/hw/block/virtio-blk.c b/hw/block/virtio-blk.c index 13f6d8276e..19d0961a47 100644 --- a/hw/block/virtio-blk.c +++ b/hw/block/virtio-blk.c @@ -657,6 +657,7 @@ static void virtio_blk_migration_state_changed(Notifier *notifier, void *data) VirtIOBlock *s = container_of(notifier, VirtIOBlock, migration_state_notifier); MigrationState *mig = data; + Error *err = NULL; if (migration_in_setup(mig)) { if (!s->dataplane) { @@ -671,31 +672,39 @@ static void virtio_blk_migration_state_changed(Notifier *notifier, void *data) } bdrv_drain_all(); /* complete in-flight non-dataplane requests */ virtio_blk_data_plane_create(VIRTIO_DEVICE(s), &s->blk, - &s->dataplane); + &s->dataplane, &err); + if (err != NULL) { + error_report("%s", error_get_pretty(err)); + error_free(err); + } } } #endif /* CONFIG_VIRTIO_BLK_DATA_PLANE */ -static int virtio_blk_device_init(VirtIODevice *vdev) +static void virtio_blk_device_realize(DeviceState *dev, Error **errp) { - DeviceState *qdev = DEVICE(vdev); - VirtIOBlock *s = VIRTIO_BLK(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOBlock *s = VIRTIO_BLK(dev); VirtIOBlkConf *blk = &(s->blk); +#ifdef CONFIG_VIRTIO_BLK_DATA_PLANE + Error *err = NULL; +#endif static int virtio_blk_id; if (!blk->conf.bs) { - error_report("drive property not set"); - return -1; + error_setg(errp, "drive property not set"); + return; } if (!bdrv_is_inserted(blk->conf.bs)) { - error_report("Device needs media, but drive is empty"); - return -1; + error_setg(errp, "Device needs media, but drive is empty"); + return; } blkconf_serial(&blk->conf, &blk->serial); s->original_wce = bdrv_enable_write_cache(blk->conf.bs); if (blkconf_geometry(&blk->conf, NULL, 65535, 255, 255) < 0) { - return -1; + error_setg(errp, "Error setting geometry"); + return; } virtio_init(vdev, "virtio-blk", VIRTIO_ID_BLOCK, @@ -708,30 +717,32 @@ static int virtio_blk_device_init(VirtIODevice *vdev) s->vq = virtio_add_queue(vdev, 128, virtio_blk_handle_output); #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE - if (!virtio_blk_data_plane_create(vdev, blk, &s->dataplane)) { + virtio_blk_data_plane_create(vdev, blk, &s->dataplane, &err); + if (err != NULL) { + error_propagate(errp, err); virtio_cleanup(vdev); - return -1; + return; } s->migration_state_notifier.notify = virtio_blk_migration_state_changed; add_migration_state_change_notifier(&s->migration_state_notifier); #endif s->change = qemu_add_vm_change_state_handler(virtio_blk_dma_restart_cb, s); - register_savevm(qdev, "virtio-blk", virtio_blk_id++, 2, + register_savevm(dev, "virtio-blk", virtio_blk_id++, 2, virtio_blk_save, virtio_blk_load, s); bdrv_set_dev_ops(s->bs, &virtio_block_ops, s); bdrv_set_buffer_alignment(s->bs, s->conf->logical_block_size); bdrv_iostatus_enable(s->bs); - add_boot_device_path(s->conf->bootindex, qdev, "/disk@0,0"); - return 0; + add_boot_device_path(s->conf->bootindex, dev, "/disk@0,0"); } -static int virtio_blk_device_exit(DeviceState *dev) +static void virtio_blk_device_unrealize(DeviceState *dev, Error **errp) { VirtIODevice *vdev = VIRTIO_DEVICE(dev); VirtIOBlock *s = VIRTIO_BLK(dev); + #ifdef CONFIG_VIRTIO_BLK_DATA_PLANE remove_migration_state_change_notifier(&s->migration_state_notifier); virtio_blk_data_plane_destroy(s->dataplane); @@ -741,7 +752,6 @@ static int virtio_blk_device_exit(DeviceState *dev) unregister_savevm(dev, "virtio-blk", s); blockdev_mark_auto_del(s->bs); virtio_cleanup(vdev); - return 0; } static Property virtio_blk_properties[] = { @@ -753,10 +763,11 @@ static void virtio_blk_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = virtio_blk_device_exit; + dc->props = virtio_blk_properties; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - vdc->init = virtio_blk_device_init; + vdc->realize = virtio_blk_device_realize; + vdc->unrealize = virtio_blk_device_unrealize; vdc->get_config = virtio_blk_update_config; vdc->set_config = virtio_blk_set_config; vdc->get_features = virtio_blk_get_features; diff --git a/hw/char/virtio-serial-bus.c b/hw/char/virtio-serial-bus.c index 703f026370..226e9f9a3c 100644 --- a/hw/char/virtio-serial-bus.c +++ b/hw/char/virtio-serial-bus.c @@ -889,22 +889,24 @@ static int virtser_port_qdev_exit(DeviceState *qdev) return 0; } -static int virtio_serial_device_init(VirtIODevice *vdev) +static void virtio_serial_device_realize(DeviceState *dev, Error **errp) { - DeviceState *qdev = DEVICE(vdev); - VirtIOSerial *vser = VIRTIO_SERIAL(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSerial *vser = VIRTIO_SERIAL(dev); + BusState *bus; uint32_t i, max_supported_ports; if (!vser->serial.max_virtserial_ports) { - return -1; + error_setg(errp, "Maximum number of serial ports not specified"); + return; } /* Each port takes 2 queues, and one pair is for the control queue */ max_supported_ports = VIRTIO_PCI_QUEUE_MAX / 2 - 1; if (vser->serial.max_virtserial_ports > max_supported_ports) { - error_report("maximum ports supported: %u", max_supported_ports); - return -1; + error_setg(errp, "maximum ports supported: %u", max_supported_ports); + return; } virtio_init(vdev, "virtio-serial", VIRTIO_ID_CONSOLE, @@ -912,8 +914,9 @@ static int virtio_serial_device_init(VirtIODevice *vdev) /* Spawn a new virtio-serial bus on which the ports will ride as devices */ qbus_create_inplace(&vser->bus, sizeof(vser->bus), TYPE_VIRTIO_SERIAL_BUS, - qdev, vdev->bus_name); - vser->bus.qbus.allow_hotplug = 1; + dev, vdev->bus_name); + bus = BUS(&vser->bus); + bus->allow_hotplug = 1; vser->bus.vser = vser; QTAILQ_INIT(&vser->ports); @@ -961,10 +964,8 @@ static int virtio_serial_device_init(VirtIODevice *vdev) * Register for the savevm section with the virtio-console name * to preserve backward compat */ - register_savevm(qdev, "virtio-console", -1, 3, virtio_serial_save, + register_savevm(dev, "virtio-console", -1, 3, virtio_serial_save, virtio_serial_load, vser); - - return 0; } static void virtio_serial_port_class_init(ObjectClass *klass, void *data) @@ -987,10 +988,10 @@ static const TypeInfo virtio_serial_port_type_info = { .class_init = virtio_serial_port_class_init, }; -static int virtio_serial_device_exit(DeviceState *dev) +static void virtio_serial_device_unrealize(DeviceState *dev, Error **errp) { - VirtIOSerial *vser = VIRTIO_SERIAL(dev); VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSerial *vser = VIRTIO_SERIAL(dev); unregister_savevm(dev, "virtio-console", vser); @@ -1004,7 +1005,6 @@ static int virtio_serial_device_exit(DeviceState *dev) g_free(vser->post_load); } virtio_cleanup(vdev); - return 0; } static Property virtio_serial_properties[] = { @@ -1016,10 +1016,11 @@ static void virtio_serial_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = virtio_serial_device_exit; + dc->props = virtio_serial_properties; set_bit(DEVICE_CATEGORY_INPUT, dc->categories); - vdc->init = virtio_serial_device_init; + vdc->realize = virtio_serial_device_realize; + vdc->unrealize = virtio_serial_device_unrealize; vdc->get_features = get_features; vdc->get_config = get_config; vdc->set_config = set_config; diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c index d312b9c83c..36266083b2 100644 --- a/hw/net/virtio-net.c +++ b/hw/net/virtio-net.c @@ -1491,16 +1491,14 @@ void virtio_net_set_netclient_name(VirtIONet *n, const char *name, n->netclient_type = g_strdup(type); } -static int virtio_net_device_init(VirtIODevice *vdev) +static void virtio_net_device_realize(DeviceState *dev, Error **errp) { - int i; - - DeviceState *qdev = DEVICE(vdev); - VirtIONet *n = VIRTIO_NET(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIONet *n = VIRTIO_NET(dev); NetClientState *nc; + int i; - virtio_init(VIRTIO_DEVICE(n), "virtio-net", VIRTIO_ID_NET, - n->config_size); + virtio_init(vdev, "virtio-net", VIRTIO_ID_NET, n->config_size); n->max_queues = MAX(n->nic_conf.queues, 1); n->vqs = g_malloc0(sizeof(VirtIONetQueue) * n->max_queues); @@ -1540,7 +1538,7 @@ static int virtio_net_device_init(VirtIODevice *vdev) n->netclient_type, n->netclient_name, n); } else { n->nic = qemu_new_nic(&net_virtio_info, &n->nic_conf, - object_get_typename(OBJECT(qdev)), qdev->id, n); + object_get_typename(OBJECT(dev)), dev->id, n); } peer_test_vnet_hdr(n); @@ -1567,24 +1565,23 @@ static int virtio_net_device_init(VirtIODevice *vdev) nc = qemu_get_queue(n->nic); nc->rxfilter_notify_enabled = 1; - n->qdev = qdev; - register_savevm(qdev, "virtio-net", -1, VIRTIO_NET_VM_VERSION, + n->qdev = dev; + register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION, virtio_net_save, virtio_net_load, n); - add_boot_device_path(n->nic_conf.bootindex, qdev, "/ethernet-phy@0"); - return 0; + add_boot_device_path(n->nic_conf.bootindex, dev, "/ethernet-phy@0"); } -static int virtio_net_device_exit(DeviceState *qdev) +static void virtio_net_device_unrealize(DeviceState *dev, Error **errp) { - VirtIONet *n = VIRTIO_NET(qdev); - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIONet *n = VIRTIO_NET(dev); int i; /* This will stop vhost backend if appropriate. */ virtio_net_set_status(vdev, 0); - unregister_savevm(qdev, "virtio-net", n); + unregister_savevm(dev, "virtio-net", n); if (n->netclient_name) { g_free(n->netclient_name); @@ -1615,8 +1612,6 @@ static int virtio_net_device_exit(DeviceState *qdev) g_free(n->vqs); qemu_del_nic(n->nic); virtio_cleanup(vdev); - - return 0; } static void virtio_net_instance_init(Object *obj) @@ -1643,10 +1638,11 @@ static void virtio_net_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = virtio_net_device_exit; + dc->props = virtio_net_properties; set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); - vdc->init = virtio_net_device_init; + vdc->realize = virtio_net_device_realize; + vdc->unrealize = virtio_net_device_unrealize; vdc->get_config = virtio_net_get_config; vdc->set_config = virtio_net_set_config; vdc->get_features = virtio_net_get_features; diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index f93a81c7cd..ecc80ecaf7 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -57,9 +57,10 @@ static const TypeInfo virtual_css_bus_info = { VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) { VirtIODevice *vdev = NULL; + VirtioCcwDevice *dev = sch->driver_data; - if (sch->driver_data) { - vdev = ((VirtioCcwDevice *)sch->driver_data)->vdev; + if (dev) { + vdev = virtio_bus_get_device(&dev->bus); } return vdev; } @@ -67,7 +68,8 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n, bool assign, bool set_handler) { - VirtQueue *vq = virtio_get_queue(dev->vdev, n); + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); EventNotifier *notifier = virtio_queue_get_host_notifier(vq); int r = 0; SubchDev *sch = dev->sch; @@ -97,6 +99,7 @@ static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n, static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) { + VirtIODevice *vdev; int n, r; if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) || @@ -104,8 +107,9 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) dev->ioeventfd_started) { return; } + vdev = virtio_bus_get_device(&dev->bus); for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(dev->vdev, n)) { + if (!virtio_queue_get_num(vdev, n)) { continue; } r = virtio_ccw_set_guest2host_notifier(dev, n, true, true); @@ -118,7 +122,7 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) assign_error: while (--n >= 0) { - if (!virtio_queue_get_num(dev->vdev, n)) { + if (!virtio_queue_get_num(vdev, n)) { continue; } r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); @@ -132,13 +136,15 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev) { + VirtIODevice *vdev; int n, r; if (!dev->ioeventfd_started) { return; } + vdev = virtio_bus_get_device(&dev->bus); for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(dev->vdev, n)) { + if (!virtio_queue_get_num(vdev, n)) { continue; } r = virtio_ccw_set_guest2host_notifier(dev, n, false, false); @@ -189,7 +195,7 @@ typedef struct VirtioFeatDesc { static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align, uint16_t index, uint16_t num) { - VirtioCcwDevice *dev = sch->driver_data; + VirtIODevice *vdev = virtio_ccw_get_vdev(sch); if (index > VIRTIO_PCI_QUEUE_MAX) { return -EINVAL; @@ -200,23 +206,23 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align, return -EINVAL; } - if (!dev) { + if (!vdev) { return -EINVAL; } - virtio_queue_set_addr(dev->vdev, index, addr); + virtio_queue_set_addr(vdev, index, addr); if (!addr) { - virtio_queue_set_vector(dev->vdev, index, 0); + virtio_queue_set_vector(vdev, index, 0); } else { /* Fail if we don't have a big enough queue. */ /* TODO: Add interface to handle vring.num changing */ - if (virtio_queue_get_num(dev->vdev, index) > num) { + if (virtio_queue_get_num(vdev, index) > num) { return -EINVAL; } - virtio_queue_set_vector(dev->vdev, index, index); + virtio_queue_set_vector(vdev, index, index); } /* tell notify handler in case of config change */ - dev->vdev->config_vector = VIRTIO_PCI_QUEUE_MAX; + vdev->config_vector = VIRTIO_PCI_QUEUE_MAX; return 0; } @@ -230,6 +236,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) hwaddr indicators; VqConfigBlock vq_config; VirtioCcwDevice *dev = sch->driver_data; + VirtIODevice *vdev = virtio_ccw_get_vdev(sch); bool check_len; int len; hwaddr hw_len; @@ -272,7 +279,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) break; case CCW_CMD_VDEV_RESET: virtio_ccw_stop_ioeventfd(dev); - virtio_reset(dev->vdev); + virtio_reset(vdev); ret = 0; break; case CCW_CMD_READ_FEAT: @@ -319,7 +326,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) features.features = ldl_le_phys(ccw.cda); if (features.index < ARRAY_SIZE(dev->host_features)) { virtio_bus_set_vdev_features(&dev->bus, features.features); - dev->vdev->guest_features = features.features; + vdev->guest_features = features.features; } else { /* * If the guest supports more feature bits, assert that it @@ -337,30 +344,30 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) break; case CCW_CMD_READ_CONF: if (check_len) { - if (ccw.count > dev->vdev->config_len) { + if (ccw.count > vdev->config_len) { ret = -EINVAL; break; } } - len = MIN(ccw.count, dev->vdev->config_len); + len = MIN(ccw.count, vdev->config_len); if (!ccw.cda) { ret = -EFAULT; } else { - virtio_bus_get_vdev_config(&dev->bus, dev->vdev->config); + virtio_bus_get_vdev_config(&dev->bus, vdev->config); /* XXX config space endianness */ - cpu_physical_memory_write(ccw.cda, dev->vdev->config, len); + cpu_physical_memory_write(ccw.cda, vdev->config, len); sch->curr_status.scsw.count = ccw.count - len; ret = 0; } break; case CCW_CMD_WRITE_CONF: if (check_len) { - if (ccw.count > dev->vdev->config_len) { + if (ccw.count > vdev->config_len) { ret = -EINVAL; break; } } - len = MIN(ccw.count, dev->vdev->config_len); + len = MIN(ccw.count, vdev->config_len); hw_len = len; if (!ccw.cda) { ret = -EFAULT; @@ -371,9 +378,9 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) } else { len = hw_len; /* XXX config space endianness */ - memcpy(dev->vdev->config, config, len); + memcpy(vdev->config, config, len); cpu_physical_memory_unmap(config, hw_len, 0, hw_len); - virtio_bus_set_vdev_config(&dev->bus, dev->vdev->config); + virtio_bus_set_vdev_config(&dev->bus, vdev->config); sch->curr_status.scsw.count = ccw.count - len; ret = 0; } @@ -397,9 +404,9 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { virtio_ccw_stop_ioeventfd(dev); } - virtio_set_status(dev->vdev, status); - if (dev->vdev->status == 0) { - virtio_reset(dev->vdev); + virtio_set_status(vdev, status); + if (vdev->status == 0) { + virtio_reset(vdev); } if (status & VIRTIO_CONFIG_S_DRIVER_OK) { virtio_ccw_start_ioeventfd(dev); @@ -463,7 +470,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) ret = -EFAULT; } else { vq_config.index = lduw_phys(ccw.cda); - vq_config.num_max = virtio_queue_get_num(dev->vdev, + vq_config.num_max = virtio_queue_get_num(vdev, vq_config.index); stw_phys(ccw.cda + sizeof(vq_config.index), vq_config.num_max); sch->curr_status.scsw.count = ccw.count - sizeof(vq_config); @@ -495,7 +502,6 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) sch->driver_data = dev; dev->sch = sch; - dev->vdev = vdev; dev->indicators = 0; /* Initialize subchannel structure. */ @@ -608,7 +614,7 @@ static int virtio_ccw_device_init(VirtioCcwDevice *dev, VirtIODevice *vdev) memset(&sch->id, 0, sizeof(SenseId)); sch->id.reserved = 0xff; sch->id.cu_type = VIRTIO_CCW_CU_TYPE; - sch->id.cu_model = dev->vdev->device_id; + sch->id.cu_model = vdev->device_id; /* Only the first 32 feature bits are used. */ dev->host_features[0] = virtio_bus_get_vdev_features(&dev->bus, @@ -631,7 +637,6 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev) { SubchDev *sch = dev->sch; - virtio_ccw_stop_ioeventfd(dev); if (sch) { css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); g_free(sch); @@ -892,9 +897,10 @@ static unsigned virtio_ccw_get_features(DeviceState *d) static void virtio_ccw_reset(DeviceState *d) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); virtio_ccw_stop_ioeventfd(dev); - virtio_reset(dev->vdev); + virtio_reset(vdev); css_reset_sch(dev->sch); dev->indicators = 0; dev->indicators2 = 0; @@ -934,9 +940,10 @@ static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign) static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, bool assign, bool with_irqfd) { - VirtQueue *vq = virtio_get_queue(dev->vdev, n); + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(dev->vdev); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); if (assign) { int r = event_notifier_init(notifier, 0); @@ -952,16 +959,16 @@ static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, * land in qemu (and only the irq fd) in this code. */ if (k->guest_notifier_mask) { - k->guest_notifier_mask(dev->vdev, n, false); + k->guest_notifier_mask(vdev, n, false); } /* get lost events and re-inject */ if (k->guest_notifier_pending && - k->guest_notifier_pending(dev->vdev, n)) { + k->guest_notifier_pending(vdev, n)) { event_notifier_set(notifier); } } else { if (k->guest_notifier_mask) { - k->guest_notifier_mask(dev->vdev, n, true); + k->guest_notifier_mask(vdev, n, true); } virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); event_notifier_cleanup(notifier); @@ -973,7 +980,7 @@ static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, bool assigned) { VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = dev->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); int r, n; for (n = 0; n < nvqs; n++) { @@ -1228,6 +1235,8 @@ static int virtio_ccw_busdev_unplug(DeviceState *dev) VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; SubchDev *sch = _dev->sch; + virtio_ccw_stop_ioeventfd(_dev); + /* * We should arrive here only for device_del, since we don't support * direct hot(un)plug of channels, but only through virtio. diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 96d6f5d5b7..00932c746d 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -77,7 +77,6 @@ typedef struct VirtIOCCWDeviceClass { struct VirtioCcwDevice { DeviceState parent_obj; SubchDev *sch; - VirtIODevice *vdev; char *bus_id; uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE]; VirtioBusState bus; diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c index 9e770fba98..3983a5b464 100644 --- a/hw/scsi/vhost-scsi.c +++ b/hw/scsi/vhost-scsi.c @@ -196,29 +196,31 @@ static void vhost_scsi_set_status(VirtIODevice *vdev, uint8_t val) } } -static int vhost_scsi_init(VirtIODevice *vdev) +static void vhost_scsi_realize(DeviceState *dev, Error **errp) { - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - VHostSCSI *s = VHOST_SCSI(vdev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); + VHostSCSI *s = VHOST_SCSI(dev); + Error *err = NULL; int vhostfd = -1; int ret; if (!vs->conf.wwpn) { - error_report("vhost-scsi: missing wwpn\n"); - return -EINVAL; + error_setg(errp, "vhost-scsi: missing wwpn"); + return; } if (vs->conf.vhostfd) { vhostfd = monitor_handle_fd_param(cur_mon, vs->conf.vhostfd); if (vhostfd == -1) { - error_report("vhost-scsi: unable to parse vhostfd\n"); - return -EINVAL; + error_setg(errp, "vhost-scsi: unable to parse vhostfd"); + return; } } - ret = virtio_scsi_common_init(vs); - if (ret < 0) { - return ret; + virtio_scsi_common_realize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; } s->dev.nvqs = VHOST_SCSI_VQ_NUM_FIXED + vs->conf.num_queues; @@ -227,24 +229,21 @@ static int vhost_scsi_init(VirtIODevice *vdev) ret = vhost_dev_init(&s->dev, vhostfd, "/dev/vhost-scsi", true); if (ret < 0) { - error_report("vhost-scsi: vhost initialization failed: %s\n", - strerror(-ret)); - return ret; + error_setg(errp, "vhost-scsi: vhost initialization failed: %s", + strerror(-ret)); + return; } s->dev.backend_features = 0; error_setg(&s->migration_blocker, "vhost-scsi does not support migration"); migrate_add_blocker(s->migration_blocker); - - return 0; } -static int vhost_scsi_exit(DeviceState *qdev) +static void vhost_scsi_unrealize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); - VHostSCSI *s = VHOST_SCSI(qdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VHostSCSI *s = VHOST_SCSI(dev); migrate_del_blocker(s->migration_blocker); error_free(s->migration_blocker); @@ -253,7 +252,8 @@ static int vhost_scsi_exit(DeviceState *qdev) vhost_scsi_set_status(vdev, 0); g_free(s->dev.vqs); - return virtio_scsi_common_exit(vs); + + virtio_scsi_common_unrealize(dev, errp); } static Property vhost_scsi_properties[] = { @@ -265,10 +265,11 @@ static void vhost_scsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = vhost_scsi_exit; + dc->props = vhost_scsi_properties; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - vdc->init = vhost_scsi_init; + vdc->realize = vhost_scsi_realize; + vdc->unrealize = vhost_scsi_unrealize; vdc->get_features = vhost_scsi_get_features; vdc->set_config = vhost_scsi_set_config; vdc->set_status = vhost_scsi_set_status; diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c index 26d95a14ec..6dcdd1b91c 100644 --- a/hw/scsi/virtio-scsi.c +++ b/hw/scsi/virtio-scsi.c @@ -589,12 +589,13 @@ static struct SCSIBusInfo virtio_scsi_scsi_info = { .load_request = virtio_scsi_load_request, }; -int virtio_scsi_common_init(VirtIOSCSICommon *s) +void virtio_scsi_common_realize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(s); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSCSICommon *s = VIRTIO_SCSI_COMMON(dev); int i; - virtio_init(VIRTIO_DEVICE(s), "virtio-scsi", VIRTIO_ID_SCSI, + virtio_init(vdev, "virtio-scsi", VIRTIO_ID_SCSI, sizeof(VirtIOSCSIConfig)); s->cmd_vqs = g_malloc0(s->conf.num_queues * sizeof(VirtQueue *)); @@ -609,57 +610,52 @@ int virtio_scsi_common_init(VirtIOSCSICommon *s) s->cmd_vqs[i] = virtio_add_queue(vdev, VIRTIO_SCSI_VQ_SIZE, virtio_scsi_handle_cmd); } - - return 0; } -static int virtio_scsi_device_init(VirtIODevice *vdev) +static void virtio_scsi_device_realize(DeviceState *dev, Error **errp) { - DeviceState *qdev = DEVICE(vdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(vdev); - VirtIOSCSI *s = VIRTIO_SCSI(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSCSI *s = VIRTIO_SCSI(dev); static int virtio_scsi_id; Error *err = NULL; - int ret; - ret = virtio_scsi_common_init(vs); - if (ret < 0) { - return ret; + virtio_scsi_common_realize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; } - scsi_bus_new(&s->bus, sizeof(s->bus), qdev, + scsi_bus_new(&s->bus, sizeof(s->bus), dev, &virtio_scsi_scsi_info, vdev->bus_name); - if (!qdev->hotplugged) { + if (!dev->hotplugged) { scsi_bus_legacy_handle_cmdline(&s->bus, &err); if (err != NULL) { - error_free(err); - return -1; + error_propagate(errp, err); + return; } } - register_savevm(qdev, "virtio-scsi", virtio_scsi_id++, 1, + register_savevm(dev, "virtio-scsi", virtio_scsi_id++, 1, virtio_scsi_save, virtio_scsi_load, s); - - return 0; } -int virtio_scsi_common_exit(VirtIOSCSICommon *vs) +void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(vs); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(dev); g_free(vs->cmd_vqs); virtio_cleanup(vdev); - return 0; } -static int virtio_scsi_device_exit(DeviceState *qdev) +static void virtio_scsi_device_unrealize(DeviceState *dev, Error **errp) { - VirtIOSCSI *s = VIRTIO_SCSI(qdev); - VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(qdev); + VirtIOSCSI *s = VIRTIO_SCSI(dev); + + unregister_savevm(dev, "virtio-scsi", s); - unregister_savevm(qdev, "virtio-scsi", s); - return virtio_scsi_common_exit(vs); + virtio_scsi_common_unrealize(dev, errp); } static Property virtio_scsi_properties[] = { @@ -680,10 +676,11 @@ static void virtio_scsi_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = virtio_scsi_device_exit; + dc->props = virtio_scsi_properties; set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); - vdc->init = virtio_scsi_device_init; + vdc->realize = virtio_scsi_device_realize; + vdc->unrealize = virtio_scsi_device_unrealize; vdc->set_config = virtio_scsi_set_config; vdc->get_features = virtio_scsi_get_features; vdc->reset = virtio_scsi_reset; diff --git a/hw/virtio/virtio-balloon.c b/hw/virtio/virtio-balloon.c index 9504877120..d9754dbd33 100644 --- a/hw/virtio/virtio-balloon.c +++ b/hw/virtio/virtio-balloon.c @@ -337,10 +337,10 @@ static int virtio_balloon_load(QEMUFile *f, void *opaque, int version_id) return 0; } -static int virtio_balloon_device_init(VirtIODevice *vdev) +static void virtio_balloon_device_realize(DeviceState *dev, Error **errp) { - DeviceState *qdev = DEVICE(vdev); - VirtIOBalloon *s = VIRTIO_BALLOON(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOBalloon *s = VIRTIO_BALLOON(dev); int ret; virtio_init(vdev, "virtio-balloon", VIRTIO_ID_BALLOON, 8); @@ -349,37 +349,36 @@ static int virtio_balloon_device_init(VirtIODevice *vdev) virtio_balloon_stat, s); if (ret < 0) { - virtio_cleanup(VIRTIO_DEVICE(s)); - return -1; + error_setg(errp, "Adding balloon handler failed"); + virtio_cleanup(vdev); + return; } s->ivq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->dvq = virtio_add_queue(vdev, 128, virtio_balloon_handle_output); s->svq = virtio_add_queue(vdev, 128, virtio_balloon_receive_stats); - register_savevm(qdev, "virtio-balloon", -1, 1, + register_savevm(dev, "virtio-balloon", -1, 1, virtio_balloon_save, virtio_balloon_load, s); - object_property_add(OBJECT(qdev), "guest-stats", "guest statistics", + object_property_add(OBJECT(dev), "guest-stats", "guest statistics", balloon_stats_get_all, NULL, NULL, s, NULL); - object_property_add(OBJECT(qdev), "guest-stats-polling-interval", "int", + object_property_add(OBJECT(dev), "guest-stats-polling-interval", "int", balloon_stats_get_poll_interval, balloon_stats_set_poll_interval, NULL, s, NULL); - return 0; } -static int virtio_balloon_device_exit(DeviceState *qdev) +static void virtio_balloon_device_unrealize(DeviceState *dev, Error **errp) { - VirtIOBalloon *s = VIRTIO_BALLOON(qdev); - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOBalloon *s = VIRTIO_BALLOON(dev); balloon_stats_destroy_timer(s); qemu_remove_balloon_handler(s); - unregister_savevm(qdev, "virtio-balloon", s); + unregister_savevm(dev, "virtio-balloon", s); virtio_cleanup(vdev); - return 0; } static Property virtio_balloon_properties[] = { @@ -390,10 +389,11 @@ static void virtio_balloon_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = virtio_balloon_device_exit; + dc->props = virtio_balloon_properties; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - vdc->init = virtio_balloon_device_init; + vdc->realize = virtio_balloon_device_realize; + vdc->unrealize = virtio_balloon_device_unrealize; vdc->get_config = virtio_balloon_get_config; vdc->set_config = virtio_balloon_set_config; vdc->get_features = virtio_balloon_get_features; diff --git a/hw/virtio/virtio-bus.c b/hw/virtio/virtio-bus.c index e6b103c991..eb77019267 100644 --- a/hw/virtio/virtio-bus.c +++ b/hw/virtio/virtio-bus.c @@ -37,8 +37,8 @@ do { printf("virtio_bus: " fmt , ## __VA_ARGS__); } while (0) #define DPRINTF(fmt, ...) do { } while (0) #endif -/* Plug the VirtIODevice */ -int virtio_bus_plug_device(VirtIODevice *vdev) +/* A VirtIODevice is being plugged */ +int virtio_bus_device_plugged(VirtIODevice *vdev) { DeviceState *qdev = DEVICE(vdev); BusState *qbus = BUS(qdev_get_parent_bus(qdev)); @@ -46,8 +46,6 @@ int virtio_bus_plug_device(VirtIODevice *vdev) VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); DPRINTF("%s: plug device.\n", qbus->name); - bus->vdev = vdev; - if (klass->device_plugged != NULL) { klass->device_plugged(qbus->parent); } @@ -58,73 +56,83 @@ int virtio_bus_plug_device(VirtIODevice *vdev) /* Reset the virtio_bus */ void virtio_bus_reset(VirtioBusState *bus) { + VirtIODevice *vdev = virtio_bus_get_device(bus); + DPRINTF("%s: reset device.\n", qbus->name); - if (bus->vdev != NULL) { - virtio_reset(bus->vdev); + if (vdev != NULL) { + virtio_reset(vdev); } } -/* Destroy the VirtIODevice */ -void virtio_bus_destroy_device(VirtioBusState *bus) +/* A VirtIODevice is being unplugged */ +void virtio_bus_device_unplugged(VirtIODevice *vdev) { - BusState *qbus = BUS(bus); - VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(bus); + DeviceState *qdev = DEVICE(vdev); + BusState *qbus = BUS(qdev_get_parent_bus(qdev)); + VirtioBusClass *klass = VIRTIO_BUS_GET_CLASS(qbus); + DPRINTF("%s: remove device.\n", qbus->name); - if (bus->vdev != NULL) { - if (klass->device_unplug != NULL) { - klass->device_unplug(qbus->parent); + if (vdev != NULL) { + if (klass->device_unplugged != NULL) { + klass->device_unplugged(qbus->parent); } - object_unparent(OBJECT(bus->vdev)); - bus->vdev = NULL; } } /* Get the device id of the plugged device. */ uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus) { - assert(bus->vdev != NULL); - return bus->vdev->device_id; + VirtIODevice *vdev = virtio_bus_get_device(bus); + assert(vdev != NULL); + return vdev->device_id; } /* Get the config_len field of the plugged device. */ size_t virtio_bus_get_vdev_config_len(VirtioBusState *bus) { - assert(bus->vdev != NULL); - return bus->vdev->config_len; + VirtIODevice *vdev = virtio_bus_get_device(bus); + assert(vdev != NULL); + return vdev->config_len; } /* Get the features of the plugged device. */ uint32_t virtio_bus_get_vdev_features(VirtioBusState *bus, uint32_t requested_features) { + VirtIODevice *vdev = virtio_bus_get_device(bus); VirtioDeviceClass *k; - assert(bus->vdev != NULL); - k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + + assert(vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(vdev); assert(k->get_features != NULL); - return k->get_features(bus->vdev, requested_features); + return k->get_features(vdev, requested_features); } /* Set the features of the plugged device. */ void virtio_bus_set_vdev_features(VirtioBusState *bus, uint32_t requested_features) { + VirtIODevice *vdev = virtio_bus_get_device(bus); VirtioDeviceClass *k; - assert(bus->vdev != NULL); - k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + + assert(vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(vdev); if (k->set_features != NULL) { - k->set_features(bus->vdev, requested_features); + k->set_features(vdev, requested_features); } } /* Get bad features of the plugged device. */ uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus) { + VirtIODevice *vdev = virtio_bus_get_device(bus); VirtioDeviceClass *k; - assert(bus->vdev != NULL); - k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + + assert(vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(vdev); if (k->bad_features != NULL) { - return k->bad_features(bus->vdev); + return k->bad_features(vdev); } else { return 0; } @@ -133,22 +141,26 @@ uint32_t virtio_bus_get_vdev_bad_features(VirtioBusState *bus) /* Get config of the plugged device. */ void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config) { + VirtIODevice *vdev = virtio_bus_get_device(bus); VirtioDeviceClass *k; - assert(bus->vdev != NULL); - k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + + assert(vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(vdev); if (k->get_config != NULL) { - k->get_config(bus->vdev, config); + k->get_config(vdev, config); } } /* Set config of the plugged device. */ void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config) { + VirtIODevice *vdev = virtio_bus_get_device(bus); VirtioDeviceClass *k; - assert(bus->vdev != NULL); - k = VIRTIO_DEVICE_GET_CLASS(bus->vdev); + + assert(vdev != NULL); + k = VIRTIO_DEVICE_GET_CLASS(vdev); if (k->set_config != NULL) { - k->set_config(bus->vdev, config); + k->set_config(vdev, config); } } diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c index 29cf284d12..8829eb0e26 100644 --- a/hw/virtio/virtio-mmio.c +++ b/hw/virtio/virtio-mmio.c @@ -95,7 +95,7 @@ static void virtio_mmio_bus_new(VirtioBusState *bus, size_t bus_size, static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size) { VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque; - VirtIODevice *vdev = proxy->bus.vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); DPRINTF("virtio_mmio_read offset 0x%x\n", (int)offset); @@ -185,7 +185,7 @@ static void virtio_mmio_write(void *opaque, hwaddr offset, uint64_t value, unsigned size) { VirtIOMMIOProxy *proxy = (VirtIOMMIOProxy *)opaque; - VirtIODevice *vdev = proxy->bus.vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); DPRINTF("virtio_mmio_write offset 0x%x value 0x%" PRIx64 "\n", (int)offset, value); @@ -298,12 +298,13 @@ static const MemoryRegionOps virtio_mem_ops = { static void virtio_mmio_update_irq(DeviceState *opaque, uint16_t vector) { VirtIOMMIOProxy *proxy = VIRTIO_MMIO(opaque); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); int level; - if (!proxy->bus.vdev) { + if (!vdev) { return; } - level = (proxy->bus.vdev->isr != 0); + level = (vdev->isr != 0); DPRINTF("virtio_mmio setting IRQ %d\n", level); qemu_set_irq(proxy->irq, level); } diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c index 7647be8a3c..30c9f2b698 100644 --- a/hw/virtio/virtio-pci.c +++ b/hw/virtio/virtio-pci.c @@ -113,31 +113,40 @@ static inline VirtIOPCIProxy *to_virtio_pci_proxy_fast(DeviceState *d) static void virtio_pci_notify(DeviceState *d, uint16_t vector) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy_fast(d); + if (msix_enabled(&proxy->pci_dev)) msix_notify(&proxy->pci_dev, vector); - else - pci_set_irq(&proxy->pci_dev, proxy->vdev->isr & 1); + else { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + pci_set_irq(&proxy->pci_dev, vdev->isr & 1); + } } static void virtio_pci_save_config(DeviceState *d, QEMUFile *f) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + pci_device_save(&proxy->pci_dev, f); msix_save(&proxy->pci_dev, f); if (msix_present(&proxy->pci_dev)) - qemu_put_be16(f, proxy->vdev->config_vector); + qemu_put_be16(f, vdev->config_vector); } static void virtio_pci_save_queue(DeviceState *d, int n, QEMUFile *f) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + if (msix_present(&proxy->pci_dev)) - qemu_put_be16(f, virtio_queue_vector(proxy->vdev, n)); + qemu_put_be16(f, virtio_queue_vector(vdev, n)); } static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + int ret; ret = pci_device_load(&proxy->pci_dev, f); if (ret) { @@ -146,12 +155,12 @@ static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) msix_unuse_all_vectors(&proxy->pci_dev); msix_load(&proxy->pci_dev, f); if (msix_present(&proxy->pci_dev)) { - qemu_get_be16s(f, &proxy->vdev->config_vector); + qemu_get_be16s(f, &vdev->config_vector); } else { - proxy->vdev->config_vector = VIRTIO_NO_VECTOR; + vdev->config_vector = VIRTIO_NO_VECTOR; } - if (proxy->vdev->config_vector != VIRTIO_NO_VECTOR) { - return msix_vector_use(&proxy->pci_dev, proxy->vdev->config_vector); + if (vdev->config_vector != VIRTIO_NO_VECTOR) { + return msix_vector_use(&proxy->pci_dev, vdev->config_vector); } return 0; } @@ -159,13 +168,15 @@ static int virtio_pci_load_config(DeviceState *d, QEMUFile *f) static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + uint16_t vector; if (msix_present(&proxy->pci_dev)) { qemu_get_be16s(f, &vector); } else { vector = VIRTIO_NO_VECTOR; } - virtio_queue_set_vector(proxy->vdev, n, vector); + virtio_queue_set_vector(vdev, n, vector); if (vector != VIRTIO_NO_VECTOR) { return msix_vector_use(&proxy->pci_dev, vector); } @@ -175,7 +186,8 @@ static int virtio_pci_load_queue(DeviceState *d, int n, QEMUFile *f) static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, int n, bool assign, bool set_handler) { - VirtQueue *vq = virtio_get_queue(proxy->vdev, n); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_get_queue(vdev, n); EventNotifier *notifier = virtio_queue_get_host_notifier(vq); int r = 0; @@ -200,6 +212,7 @@ static int virtio_pci_set_host_notifier_internal(VirtIOPCIProxy *proxy, static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy) { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); int n, r; if (!(proxy->flags & VIRTIO_PCI_FLAG_USE_IOEVENTFD) || @@ -209,7 +222,7 @@ static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy) } for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(proxy->vdev, n)) { + if (!virtio_queue_get_num(vdev, n)) { continue; } @@ -223,7 +236,7 @@ static void virtio_pci_start_ioeventfd(VirtIOPCIProxy *proxy) assign_error: while (--n >= 0) { - if (!virtio_queue_get_num(proxy->vdev, n)) { + if (!virtio_queue_get_num(vdev, n)) { continue; } @@ -236,6 +249,7 @@ assign_error: static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) { + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); int r; int n; @@ -244,7 +258,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) } for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(proxy->vdev, n)) { + if (!virtio_queue_get_num(vdev, n)) { continue; } @@ -257,7 +271,7 @@ static void virtio_pci_stop_ioeventfd(VirtIOPCIProxy *proxy) static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) { VirtIOPCIProxy *proxy = opaque; - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); hwaddr pa; switch (addr) { @@ -272,7 +286,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) pa = (hwaddr)val << VIRTIO_PCI_QUEUE_ADDR_SHIFT; if (pa == 0) { virtio_pci_stop_ioeventfd(proxy); - virtio_reset(proxy->vdev); + virtio_reset(vdev); msix_unuse_all_vectors(&proxy->pci_dev); } else @@ -299,7 +313,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) } if (vdev->status == 0) { - virtio_reset(proxy->vdev); + virtio_reset(vdev); msix_unuse_all_vectors(&proxy->pci_dev); } @@ -335,7 +349,7 @@ static void virtio_ioport_write(void *opaque, uint32_t addr, uint32_t val) static uint32_t virtio_ioport_read(VirtIOPCIProxy *proxy, uint32_t addr) { - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); uint32_t ret = 0xFFFFFFFF; switch (addr) { @@ -381,6 +395,7 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, unsigned size) { VirtIOPCIProxy *proxy = opaque; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); uint64_t val = 0; if (addr < config) { @@ -390,16 +405,16 @@ static uint64_t virtio_pci_config_read(void *opaque, hwaddr addr, switch (size) { case 1: - val = virtio_config_readb(proxy->vdev, addr); + val = virtio_config_readb(vdev, addr); break; case 2: - val = virtio_config_readw(proxy->vdev, addr); + val = virtio_config_readw(vdev, addr); if (virtio_is_big_endian()) { val = bswap16(val); } break; case 4: - val = virtio_config_readl(proxy->vdev, addr); + val = virtio_config_readl(vdev, addr); if (virtio_is_big_endian()) { val = bswap32(val); } @@ -413,6 +428,7 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr, { VirtIOPCIProxy *proxy = opaque; uint32_t config = VIRTIO_PCI_CONFIG(&proxy->pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); if (addr < config) { virtio_ioport_write(proxy, addr, val); return; @@ -424,19 +440,19 @@ static void virtio_pci_config_write(void *opaque, hwaddr addr, */ switch (size) { case 1: - virtio_config_writeb(proxy->vdev, addr, val); + virtio_config_writeb(vdev, addr, val); break; case 2: if (virtio_is_big_endian()) { val = bswap16(val); } - virtio_config_writew(proxy->vdev, addr, val); + virtio_config_writew(vdev, addr, val); break; case 4: if (virtio_is_big_endian()) { val = bswap32(val); } - virtio_config_writel(proxy->vdev, addr, val); + virtio_config_writel(vdev, addr, val); break; } } @@ -455,6 +471,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, uint32_t val, int len) { VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); pci_default_write_config(pci_dev, address, val, len); @@ -462,8 +479,7 @@ static void virtio_write_config(PCIDevice *pci_dev, uint32_t address, !(pci_dev->config[PCI_COMMAND] & PCI_COMMAND_MASTER) && !(proxy->flags & VIRTIO_PCI_FLAG_BUS_MASTER_BUG)) { virtio_pci_stop_ioeventfd(proxy); - virtio_set_status(proxy->vdev, - proxy->vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK); + virtio_set_status(vdev, vdev->status & ~VIRTIO_CONFIG_S_DRIVER_OK); } } @@ -506,7 +522,8 @@ static int kvm_virtio_pci_irqfd_use(VirtIOPCIProxy *proxy, unsigned int vector) { VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; - VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_get_queue(vdev, queue_no); EventNotifier *n = virtio_queue_get_guest_notifier(vq); int ret; ret = kvm_irqchip_add_irqfd_notifier(kvm_state, n, NULL, irqfd->virq); @@ -517,7 +534,8 @@ static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, unsigned int queue_no, unsigned int vector) { - VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtQueue *vq = virtio_get_queue(vdev, queue_no); EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd = &proxy->vector_irqfd[vector]; int ret; @@ -529,7 +547,7 @@ static void kvm_virtio_pci_irqfd_release(VirtIOPCIProxy *proxy, static int kvm_virtio_pci_vector_use(VirtIOPCIProxy *proxy, int nvqs) { PCIDevice *dev = &proxy->pci_dev; - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); unsigned int vector; int ret, queue_no; @@ -578,7 +596,7 @@ undo: static void kvm_virtio_pci_vector_release(VirtIOPCIProxy *proxy, int nvqs) { PCIDevice *dev = &proxy->pci_dev; - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); unsigned int vector; int queue_no; VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); @@ -606,8 +624,9 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, unsigned int vector, MSIMessage msg) { - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(proxy->vdev); - VirtQueue *vq = virtio_get_queue(proxy->vdev, queue_no); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); + VirtQueue *vq = virtio_get_queue(vdev, queue_no); EventNotifier *n = virtio_queue_get_guest_notifier(vq); VirtIOIRQFD *irqfd; int ret = 0; @@ -626,10 +645,10 @@ static int virtio_pci_vq_vector_unmask(VirtIOPCIProxy *proxy, * Otherwise, set it up now. */ if (k->guest_notifier_mask) { - k->guest_notifier_mask(proxy->vdev, queue_no, false); + k->guest_notifier_mask(vdev, queue_no, false); /* Test after unmasking to avoid losing events. */ if (k->guest_notifier_pending && - k->guest_notifier_pending(proxy->vdev, queue_no)) { + k->guest_notifier_pending(vdev, queue_no)) { event_notifier_set(n); } } else { @@ -642,13 +661,14 @@ static void virtio_pci_vq_vector_mask(VirtIOPCIProxy *proxy, unsigned int queue_no, unsigned int vector) { - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(proxy->vdev); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); /* If guest supports masking, keep irqfd but mask it. * Otherwise, clean it up now. */ if (k->guest_notifier_mask) { - k->guest_notifier_mask(proxy->vdev, queue_no, true); + k->guest_notifier_mask(vdev, queue_no, true); } else { kvm_virtio_pci_irqfd_release(proxy, queue_no, vector); } @@ -658,7 +678,7 @@ static int virtio_pci_vector_unmask(PCIDevice *dev, unsigned vector, MSIMessage msg) { VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); int ret, queue_no; for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { @@ -688,7 +708,7 @@ undo: static void virtio_pci_vector_mask(PCIDevice *dev, unsigned vector) { VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); int queue_no; for (queue_no = 0; queue_no < proxy->nvqs_with_notifiers; queue_no++) { @@ -707,7 +727,7 @@ static void virtio_pci_vector_poll(PCIDevice *dev, unsigned int vector_end) { VirtIOPCIProxy *proxy = container_of(dev, VirtIOPCIProxy, pci_dev); - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); int queue_no; unsigned int vector; @@ -739,8 +759,9 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, bool with_irqfd) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(proxy->vdev); - VirtQueue *vq = virtio_get_queue(proxy->vdev, n); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(vdev); + VirtQueue *vq = virtio_get_queue(vdev, n); EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); if (assign) { @@ -755,7 +776,7 @@ static int virtio_pci_set_guest_notifier(DeviceState *d, int n, bool assign, } if (!msix_enabled(&proxy->pci_dev) && vdc->guest_notifier_mask) { - vdc->guest_notifier_mask(proxy->vdev, n, !assign); + vdc->guest_notifier_mask(vdev, n, !assign); } return 0; @@ -770,7 +791,7 @@ static bool virtio_pci_query_guest_notifiers(DeviceState *d) static int virtio_pci_set_guest_notifiers(DeviceState *d, int nvqs, bool assign) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); - VirtIODevice *vdev = proxy->vdev; + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); int r, n; bool with_irqfd = msix_enabled(&proxy->pci_dev) && @@ -864,11 +885,12 @@ static int virtio_pci_set_host_notifier(DeviceState *d, int n, bool assign) static void virtio_pci_vmstate_change(DeviceState *d, bool running) { VirtIOPCIProxy *proxy = to_virtio_pci_proxy(d); + VirtIODevice *vdev = virtio_bus_get_device(&proxy->bus); if (running) { /* Try to find out if the guest has bus master disabled, but is in ready state. Then we have a buggy guest OS. */ - if ((proxy->vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && + if ((vdev->status & VIRTIO_CONFIG_S_DRIVER_OK) && !(proxy->pci_dev.config[PCI_COMMAND] & PCI_COMMAND_MASTER)) { proxy->flags |= VIRTIO_PCI_FLAG_BUS_MASTER_BUG; } @@ -943,8 +965,6 @@ static void virtio_pci_device_plugged(DeviceState *d) uint8_t *config; uint32_t size; - proxy->vdev = bus->vdev; - config = proxy->pci_dev.config; if (proxy->class_code) { pci_config_set_class(config, proxy->class_code); @@ -982,6 +1002,15 @@ static void virtio_pci_device_plugged(DeviceState *d) proxy->host_features); } +static void virtio_pci_device_unplugged(DeviceState *d) +{ + PCIDevice *pci_dev = PCI_DEVICE(d); + VirtIOPCIProxy *proxy = VIRTIO_PCI(d); + + virtio_pci_stop_ioeventfd(proxy); + msix_uninit_exclusive_bar(pci_dev); +} + static int virtio_pci_init(PCIDevice *pci_dev) { VirtIOPCIProxy *dev = VIRTIO_PCI(pci_dev); @@ -996,9 +1025,7 @@ static int virtio_pci_init(PCIDevice *pci_dev) static void virtio_pci_exit(PCIDevice *pci_dev) { VirtIOPCIProxy *proxy = VIRTIO_PCI(pci_dev); - virtio_pci_stop_ioeventfd(proxy); memory_region_destroy(&proxy->bar); - msix_uninit_exclusive_bar(pci_dev); } static void virtio_pci_reset(DeviceState *qdev) @@ -1533,6 +1560,7 @@ static void virtio_pci_bus_class_init(ObjectClass *klass, void *data) k->set_guest_notifiers = virtio_pci_set_guest_notifiers; k->vmstate_change = virtio_pci_vmstate_change; k->device_plugged = virtio_pci_device_plugged; + k->device_unplugged = virtio_pci_device_unplugged; } static const TypeInfo virtio_pci_bus_info = { diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h index 917bcc5348..dc332ae774 100644 --- a/hw/virtio/virtio-pci.h +++ b/hw/virtio/virtio-pci.h @@ -82,7 +82,6 @@ typedef struct VirtioPCIClass { struct VirtIOPCIProxy { PCIDevice pci_dev; - VirtIODevice *vdev; MemoryRegion bar; uint32_t flags; uint32_t class_code; diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c index b22ccf1008..755fdee628 100644 --- a/hw/virtio/virtio-rng.c +++ b/hw/virtio/virtio-rng.c @@ -133,27 +133,27 @@ static void check_rate_limit(void *opaque) qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vrng->conf.period_ms); } -static int virtio_rng_device_init(VirtIODevice *vdev) +static void virtio_rng_device_realize(DeviceState *dev, Error **errp) { - DeviceState *qdev = DEVICE(vdev); - VirtIORNG *vrng = VIRTIO_RNG(vdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIORNG *vrng = VIRTIO_RNG(dev); Error *local_err = NULL; if (!vrng->conf.period_ms > 0) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "period", - "a positive number"); - return -1; + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "period", + "a positive number"); + return; } if (vrng->conf.rng == NULL) { vrng->conf.default_backend = RNG_RANDOM(object_new(TYPE_RNG_RANDOM)); - object_property_add_child(OBJECT(qdev), + object_property_add_child(OBJECT(dev), "default-backend", OBJECT(vrng->conf.default_backend), NULL); - object_property_set_link(OBJECT(qdev), + object_property_set_link(OBJECT(dev), OBJECT(vrng->conf.default_backend), "rng", NULL); } @@ -162,15 +162,14 @@ static int virtio_rng_device_init(VirtIODevice *vdev) vrng->rng = vrng->conf.rng; if (vrng->rng == NULL) { - qerror_report(QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object"); - return -1; + error_set(errp, QERR_INVALID_PARAMETER_VALUE, "rng", "a valid object"); + return; } rng_backend_open(vrng->rng, &local_err); if (local_err) { - qerror_report_err(local_err); - error_free(local_err); - return -1; + error_propagate(errp, local_err); + return; } vrng->vq = virtio_add_queue(vdev, 8, handle_input); @@ -184,22 +183,19 @@ static int virtio_rng_device_init(VirtIODevice *vdev) timer_mod(vrng->rate_limit_timer, qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL) + vrng->conf.period_ms); - register_savevm(qdev, "virtio-rng", -1, 1, virtio_rng_save, + register_savevm(dev, "virtio-rng", -1, 1, virtio_rng_save, virtio_rng_load, vrng); - - return 0; } -static int virtio_rng_device_exit(DeviceState *qdev) +static void virtio_rng_device_unrealize(DeviceState *dev, Error **errp) { - VirtIORNG *vrng = VIRTIO_RNG(qdev); - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIORNG *vrng = VIRTIO_RNG(dev); timer_del(vrng->rate_limit_timer); timer_free(vrng->rate_limit_timer); - unregister_savevm(qdev, "virtio-rng", vrng); + unregister_savevm(dev, "virtio-rng", vrng); virtio_cleanup(vdev); - return 0; } static Property virtio_rng_properties[] = { @@ -211,10 +207,11 @@ static void virtio_rng_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); - dc->exit = virtio_rng_device_exit; + dc->props = virtio_rng_properties; set_bit(DEVICE_CATEGORY_MISC, dc->categories); - vdc->init = virtio_rng_device_init; + vdc->realize = virtio_rng_device_realize; + vdc->unrealize = virtio_rng_device_unrealize; vdc->get_features = get_features; } diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 2f1e73bc75..144b9ca2ef 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -1150,35 +1150,49 @@ void virtio_device_set_child_bus_name(VirtIODevice *vdev, char *bus_name) } } -static int virtio_device_init(DeviceState *qdev) +static void virtio_device_realize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(qdev); - assert(k->init != NULL); - if (k->init(vdev) < 0) { - return -1; + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev); + Error *err = NULL; + + if (vdc->realize != NULL) { + vdc->realize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } } - virtio_bus_plug_device(vdev); - return 0; + virtio_bus_device_plugged(vdev); } -static int virtio_device_exit(DeviceState *qdev) +static void virtio_device_unrealize(DeviceState *dev, Error **errp) { - VirtIODevice *vdev = VIRTIO_DEVICE(qdev); + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_GET_CLASS(dev); + Error *err = NULL; + + if (vdc->unrealize != NULL) { + vdc->unrealize(dev, &err); + if (err != NULL) { + error_propagate(errp, err); + return; + } + } if (vdev->bus_name) { g_free(vdev->bus_name); vdev->bus_name = NULL; } - return 0; } static void virtio_device_class_init(ObjectClass *klass, void *data) { /* Set the default value here. */ DeviceClass *dc = DEVICE_CLASS(klass); - dc->init = virtio_device_init; - dc->exit = virtio_device_exit; + + dc->realize = virtio_device_realize; + dc->unrealize = virtio_device_unrealize; dc->bus_type = TYPE_VIRTIO_BUS; } diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h index 9217f85abc..0756545d4d 100644 --- a/include/hw/virtio/virtio-bus.h +++ b/include/hw/virtio/virtio-bus.h @@ -61,7 +61,7 @@ typedef struct VirtioBusClass { * transport independent exit function. * This is called by virtio-bus just before the device is unplugged. */ - void (*device_unplug)(DeviceState *d); + void (*device_unplugged)(DeviceState *d); /* * Does the transport have variable vring alignment? * (ie can it ever call virtio_queue_set_align()?) @@ -72,15 +72,11 @@ typedef struct VirtioBusClass { struct VirtioBusState { BusState parent_obj; - /* - * Only one VirtIODevice can be plugged on the bus. - */ - VirtIODevice *vdev; }; -int virtio_bus_plug_device(VirtIODevice *vdev); +int virtio_bus_device_plugged(VirtIODevice *vdev); void virtio_bus_reset(VirtioBusState *bus); -void virtio_bus_destroy_device(VirtioBusState *bus); +void virtio_bus_device_unplugged(VirtIODevice *bus); /* Get the device id of the plugged device. */ uint16_t virtio_bus_get_vdev_id(VirtioBusState *bus); /* Get the config_len field of the plugged device. */ @@ -98,4 +94,16 @@ void virtio_bus_get_vdev_config(VirtioBusState *bus, uint8_t *config); /* Set config of the plugged device. */ void virtio_bus_set_vdev_config(VirtioBusState *bus, uint8_t *config); +static inline VirtIODevice *virtio_bus_get_device(VirtioBusState *bus) +{ + BusState *qbus = &bus->parent_obj; + BusChild *kid = QTAILQ_FIRST(&qbus->children); + DeviceState *qdev = kid ? kid->child : NULL; + + /* This is used on the data path, the cast is guaranteed + * to succeed by the qdev machinery. + */ + return (VirtIODevice *)qdev; +} + #endif /* VIRTIO_BUS_H */ diff --git a/include/hw/virtio/virtio-rng.h b/include/hw/virtio/virtio-rng.h index debaa15d5a..14e85a5a3a 100644 --- a/include/hw/virtio/virtio-rng.h +++ b/include/hw/virtio/virtio-rng.h @@ -18,6 +18,8 @@ #define TYPE_VIRTIO_RNG "virtio-rng-device" #define VIRTIO_RNG(obj) \ OBJECT_CHECK(VirtIORNG, (obj), TYPE_VIRTIO_RNG) +#define VIRTIO_RNG_GET_PARENT_CLASS(obj) \ + OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_RNG) /* The Virtio ID for the virtio rng device */ #define VIRTIO_ID_RNG 4 diff --git a/include/hw/virtio/virtio-scsi.h b/include/hw/virtio/virtio-scsi.h index 9a985403c2..42b102487a 100644 --- a/include/hw/virtio/virtio-scsi.h +++ b/include/hw/virtio/virtio-scsi.h @@ -186,7 +186,7 @@ typedef struct { DEFINE_PROP_BIT("param_change", _state, _feature_field, \ VIRTIO_SCSI_F_CHANGE, true) -int virtio_scsi_common_init(VirtIOSCSICommon *vs); -int virtio_scsi_common_exit(VirtIOSCSICommon *vs); +void virtio_scsi_common_realize(DeviceState *dev, Error **errp); +void virtio_scsi_common_unrealize(DeviceState *dev, Error **errp); #endif /* _QEMU_VIRTIO_SCSI_H */ diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h index a90522d6d6..3e54e90aad 100644 --- a/include/hw/virtio/virtio.h +++ b/include/hw/virtio/virtio.h @@ -124,9 +124,13 @@ struct VirtIODevice }; typedef struct VirtioDeviceClass { - /* This is what a VirtioDevice must implement */ + /*< private >*/ DeviceClass parent; - int (*init)(VirtIODevice *vdev); + /*< public >*/ + + /* This is what a VirtioDevice must implement */ + DeviceRealize realize; + DeviceUnrealize unrealize; uint32_t (*get_features)(VirtIODevice *vdev, uint32_t requested_features); uint32_t (*bad_features)(VirtIODevice *vdev); void (*set_features)(VirtIODevice *vdev, uint32_t val); diff --git a/tests/qdev-monitor-test.c b/tests/qdev-monitor-test.c index 33a8ea4b9c..ba7f9cc238 100644 --- a/tests/qdev-monitor-test.c +++ b/tests/qdev-monitor-test.c @@ -32,10 +32,8 @@ static void test_device_add(void) "}}"); g_assert(response); error = qdict_get_qdict(response, "error"); - g_assert(!strcmp(qdict_get_try_str(error, "class") ?: "", - "GenericError")); g_assert(!strcmp(qdict_get_try_str(error, "desc") ?: "", - "Device initialization failed.")); + "Device needs media, but drive is empty")); QDECREF(response); /* Delete the drive */ |