mirror of https://gitee.com/openkylin/qemu.git
Merge remote-tracking branch 'bonzini/virtio' into staging
# By Andreas Färber (18) and Paolo Bonzini (12) # Via Paolo Bonzini * bonzini/virtio: (30 commits) virtio: Convert exit to unrealize virtio: Complete converting VirtioDevice to QOM realize virtio-scsi: Convert to QOM realize virtio-rng: Convert to QOM realize virtio-balloon: Convert to QOM realize virtio-net: Convert to QOM realize virtio-serial: Convert to QOM realize virtio-blk: Convert to QOM realize virtio-9p: Convert to QOM realize virtio: Start converting VirtioDevice to QOM realize virtio-scsi: QOM realize preparations virtio-rng: QOM realize preparations virtio-balloon: QOM realize preparations virtio-net: QOM realize preparations virtio-serial: QOM realize preparations virtio-blk: QOM realize preparations virtio-9p: QOM realize preparations virtio-blk-dataplane: Improve error reporting virtio-pci: add device_unplugged callback virtio-rng: switch exit callback to VirtioDeviceClass ...
This commit is contained in:
commit
e157b8fdd4
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
VirtIONet *n = VIRTIO_NET(dev);
|
||||
NetClientState *nc;
|
||||
int i;
|
||||
|
||||
DeviceState *qdev = DEVICE(vdev);
|
||||
VirtIONet *n = VIRTIO_NET(vdev);
|
||||
NetClientState *nc;
|
||||
|
||||
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;
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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(qdev, "virtio-scsi", s);
|
||||
return virtio_scsi_common_exit(vs);
|
||||
unregister_savevm(dev, "virtio-scsi", s);
|
||||
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 = {
|
||||
|
|
|
@ -82,7 +82,6 @@ typedef struct VirtioPCIClass {
|
|||
|
||||
struct VirtIOPCIProxy {
|
||||
PCIDevice pci_dev;
|
||||
VirtIODevice *vdev;
|
||||
MemoryRegion bar;
|
||||
uint32_t flags;
|
||||
uint32_t class_code;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue