@@ -54,6 +54,7 @@ struct virtio_mmio {
int virtio_mmio_signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq);
int virtio_mmio_signal_config(struct kvm *kvm, struct virtio_device *vdev);
int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_mmio_reset(struct kvm *kvm, struct virtio_device *vdev);
int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class);
void virtio_mmio_assign_irq(struct device_header *dev_hdr);
@@ -55,6 +55,7 @@ struct virtio_pci {
int virtio_pci__signal_vq(struct kvm *kvm, struct virtio_device *vdev, u32 vq);
int virtio_pci__signal_config(struct kvm *kvm, struct virtio_device *vdev);
int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev);
+int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev);
int virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class);
@@ -195,6 +195,7 @@ struct virtio_ops {
int (*init)(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class);
int (*exit)(struct kvm *kvm, struct virtio_device *vdev);
+ int (*reset)(struct kvm *kvm, struct virtio_device *vdev);
};
int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
@@ -241,6 +241,13 @@ void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
} else if (!status && (vdev->status & VIRTIO__STATUS_START)) {
vdev->status &= ~VIRTIO__STATUS_START;
ext_status |= VIRTIO__STATUS_STOP;
+
+ /*
+ * Reset virtqueues and stop all traffic now, so that the device
+ * can safely reset the backend in notify_status().
+ */
+ if (ext_status & VIRTIO__STATUS_STOP)
+ vdev->ops->reset(kvm, vdev);
}
if (vdev->ops->notify_status)
@@ -264,6 +271,7 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
vdev->ops->signal_config = virtio_pci__signal_config;
vdev->ops->init = virtio_pci__init;
vdev->ops->exit = virtio_pci__exit;
+ vdev->ops->reset = virtio_pci__reset;
vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
break;
case VIRTIO_MMIO:
@@ -276,6 +284,7 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
vdev->ops->signal_config = virtio_mmio_signal_config;
vdev->ops->init = virtio_mmio_init;
vdev->ops->exit = virtio_mmio_exit;
+ vdev->ops->reset = virtio_mmio_reset;
vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
break;
default:
@@ -326,15 +326,23 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
return 0;
}
+int virtio_mmio_reset(struct kvm *kvm, struct virtio_device *vdev)
+{
+ int vq;
+ struct virtio_mmio *vmmio = vdev->virtio;
+
+ for (vq = 0; vq < vdev->ops->get_vq_count(kvm, vmmio->dev); vq++)
+ virtio_mmio_exit_vq(kvm, vdev, vq);
+
+ return 0;
+}
+
int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev)
{
struct virtio_mmio *vmmio = vdev->virtio;
- int i;
+ virtio_mmio_reset(kvm, vdev);
kvm__deregister_mmio(kvm, vmmio->addr);
- for (i = 0; i < VIRTIO_MMIO_MAX_VQ; i++)
- ioeventfd__del_event(vmmio->addr + VIRTIO_MMIO_QUEUE_NOTIFY, i);
-
return 0;
}
@@ -77,8 +77,8 @@ static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev,
{
struct virtio_pci *vpci = vdev->virtio;
- ioeventfd__del_event(vpci->port_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq);
ioeventfd__del_event(vpci->mmio_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq);
+ ioeventfd__del_event(vpci->port_addr + VIRTIO_PCI_QUEUE_NOTIFY, vq);
virtio_exit_vq(kvm, vdev, vpci->dev, vq);
}
@@ -522,19 +522,25 @@ free_ioport:
return r;
}
+int virtio_pci__reset(struct kvm *kvm, struct virtio_device *vdev)
+{
+ int vq;
+ struct virtio_pci *vpci = vdev->virtio;
+
+ for (vq = 0; vq < vdev->ops->get_vq_count(kvm, vpci->dev); vq++)
+ virtio_pci_exit_vq(kvm, vdev, vq);
+
+ return 0;
+}
+
int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
{
struct virtio_pci *vpci = vdev->virtio;
- int i;
+ virtio_pci__reset(kvm, vdev);
kvm__deregister_mmio(kvm, vpci->mmio_addr);
kvm__deregister_mmio(kvm, vpci->msix_io_block);
ioport__unregister(kvm, vpci->port_addr);
- for (i = 0; i < VIRTIO_PCI_MAX_VQ; i++) {
- ioeventfd__del_event(vpci->port_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
- ioeventfd__del_event(vpci->mmio_addr + VIRTIO_PCI_QUEUE_NOTIFY, i);
- }
-
return 0;
}