diff --git a/hw/virtio-net.c b/hw/virtio-net.c index ec1bf8dda7..ccb3e632a4 100644 --- a/hw/virtio-net.c +++ b/hw/virtio-net.c @@ -54,8 +54,6 @@ typedef struct VirtIONet uint8_t nouni; uint8_t nobcast; uint8_t vhost_started; - bool vm_running; - VMChangeStateEntry *vmstate; struct { int in_use; int first_multi; @@ -102,7 +100,7 @@ static void virtio_net_set_config(VirtIODevice *vdev, const uint8_t *config) static bool virtio_net_started(VirtIONet *n, uint8_t status) { return (status & VIRTIO_CONFIG_S_DRIVER_OK) && - (n->status & VIRTIO_NET_S_LINK_UP) && n->vm_running; + (n->status & VIRTIO_NET_S_LINK_UP) && n->vdev.vm_running; } static void virtio_net_vhost_status(VirtIONet *n, uint8_t status) @@ -453,7 +451,7 @@ static void virtio_net_handle_rx(VirtIODevice *vdev, VirtQueue *vq) static int virtio_net_can_receive(VLANClientState *nc) { VirtIONet *n = DO_UPCAST(NICState, nc, nc)->opaque; - if (!n->vm_running) { + if (!n->vdev.vm_running) { return 0; } @@ -708,7 +706,7 @@ static int32_t virtio_net_flush_tx(VirtIONet *n, VirtQueue *vq) return num_packets; } - assert(n->vm_running); + assert(n->vdev.vm_running); if (n->async_tx.elem.out_num) { virtio_queue_set_notification(n->tx_vq, 0); @@ -769,7 +767,7 @@ static void virtio_net_handle_tx_timer(VirtIODevice *vdev, VirtQueue *vq) VirtIONet *n = to_virtio_net(vdev); /* This happens when device was stopped but VCPU wasn't. */ - if (!n->vm_running) { + if (!n->vdev.vm_running) { n->tx_waiting = 1; return; } @@ -796,7 +794,7 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) } n->tx_waiting = 1; /* This happens when device was stopped but VCPU wasn't. */ - if (!n->vm_running) { + if (!n->vdev.vm_running) { return; } virtio_queue_set_notification(vq, 0); @@ -806,7 +804,7 @@ static void virtio_net_handle_tx_bh(VirtIODevice *vdev, VirtQueue *vq) static void virtio_net_tx_timer(void *opaque) { VirtIONet *n = opaque; - assert(n->vm_running); + assert(n->vdev.vm_running); n->tx_waiting = 0; @@ -823,7 +821,7 @@ static void virtio_net_tx_bh(void *opaque) VirtIONet *n = opaque; int32_t ret; - assert(n->vm_running); + assert(n->vdev.vm_running); n->tx_waiting = 0; @@ -988,16 +986,6 @@ static NetClientInfo net_virtio_info = { .link_status_changed = virtio_net_set_link_status, }; -static void virtio_net_vmstate_change(void *opaque, int running, int reason) -{ - VirtIONet *n = opaque; - n->vm_running = running; - /* This is called when vm is started/stopped, - * it will start/stop vhost backend if appropriate - * e.g. after migration. */ - virtio_net_set_status(&n->vdev, n->vdev.status); -} - VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, virtio_net_conf *net) { @@ -1052,7 +1040,6 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, n->qdev = dev; register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION, virtio_net_save, virtio_net_load, n); - n->vmstate = qemu_add_vm_change_state_handler(virtio_net_vmstate_change, n); add_boot_device_path(conf->bootindex, dev, "/ethernet-phy@0"); @@ -1062,7 +1049,6 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf, void virtio_net_exit(VirtIODevice *vdev) { VirtIONet *n = DO_UPCAST(VirtIONet, vdev, vdev); - qemu_del_vm_change_state_handler(n->vmstate); /* This will stop vhost backend if appropriate. */ virtio_net_set_status(vdev, 0); diff --git a/hw/virtio.c b/hw/virtio.c index 07dbf868fd..1d20be2ca3 100644 --- a/hw/virtio.c +++ b/hw/virtio.c @@ -743,11 +743,31 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f) void virtio_cleanup(VirtIODevice *vdev) { + qemu_del_vm_change_state_handler(vdev->vmstate); if (vdev->config) qemu_free(vdev->config); qemu_free(vdev->vq); } +static void virtio_vmstate_change(void *opaque, int running, int reason) +{ + VirtIODevice *vdev = opaque; + bool backend_run = running && (vdev->status & VIRTIO_CONFIG_S_DRIVER_OK); + vdev->vm_running = running; + + if (backend_run) { + virtio_set_status(vdev, vdev->status); + } + + if (vdev->binding->vmstate_change) { + vdev->binding->vmstate_change(vdev->binding_opaque, backend_run); + } + + if (!backend_run) { + virtio_set_status(vdev, vdev->status); + } +} + VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, size_t config_size, size_t struct_size) { @@ -774,6 +794,8 @@ VirtIODevice *virtio_common_init(const char *name, uint16_t device_id, else vdev->config = NULL; + vdev->vmstate = qemu_add_vm_change_state_handler(virtio_vmstate_change, vdev); + return vdev; } diff --git a/hw/virtio.h b/hw/virtio.h index 02fa312d3e..bd5274225e 100644 --- a/hw/virtio.h +++ b/hw/virtio.h @@ -95,6 +95,7 @@ typedef struct { unsigned (*get_features)(void * opaque); int (*set_guest_notifiers)(void * opaque, bool assigned); int (*set_host_notifier)(void * opaque, int n, bool assigned); + void (*vmstate_change)(void * opaque, bool running); } VirtIOBindings; #define VIRTIO_PCI_QUEUE_MAX 64 @@ -123,6 +124,8 @@ struct VirtIODevice const VirtIOBindings *binding; void *binding_opaque; uint16_t device_id; + bool vm_running; + VMChangeStateEntry *vmstate; }; static inline void virtio_set_status(VirtIODevice *vdev, uint8_t val)