aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-Philippe Brucker <jean-philippe.brucker@arm.com>2019-01-10 14:12:43 +0000
committerWill Deacon <will.deacon@arm.com>2019-01-22 06:55:26 +0000
commiteb34a8c274ba8c4e42f35252c80b57723c35e2ad (patch)
tree16fdde31cea72aaf29b2fc32594d65f633e20c4d
parentad346c2e67a13fb7abd1534864168b16423fb20b (diff)
downloadkvmtool-eb34a8c274ba8c4e42f35252c80b57723c35e2ad.tar.gz
virtio: Add reset() callback
When the guest writes a status of 0, the device should be reset. Add a reset() callback for the transport layer to reset all queues and their ioeventfd. Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com> Signed-off-by: Julien Thierry <julien.thierry@arm.com> Signed-off-by: Will Deacon <will.deacon@arm.com>
-rw-r--r--include/kvm/virtio-mmio.h1
-rw-r--r--include/kvm/virtio-pci.h1
-rw-r--r--include/kvm/virtio.h1
-rw-r--r--virtio/core.c9
-rw-r--r--virtio/mmio.c16
-rw-r--r--virtio/pci.c20
6 files changed, 37 insertions, 11 deletions
diff --git a/include/kvm/virtio-mmio.h b/include/kvm/virtio-mmio.h
index 835f421b..0528947a 100644
--- a/include/kvm/virtio-mmio.h
+++ b/include/kvm/virtio-mmio.h
@@ -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);
diff --git a/include/kvm/virtio-pci.h b/include/kvm/virtio-pci.h
index b70cadd8..278a2595 100644
--- a/include/kvm/virtio-pci.h
+++ b/include/kvm/virtio-pci.h
@@ -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);
diff --git a/include/kvm/virtio.h b/include/kvm/virtio.h
index f35c74df..19b91373 100644
--- a/include/kvm/virtio.h
+++ b/include/kvm/virtio.h
@@ -201,6 +201,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,
diff --git a/virtio/core.c b/virtio/core.c
index 67d41142..e10ec362 100644
--- a/virtio/core.c
+++ b/virtio/core.c
@@ -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:
diff --git a/virtio/mmio.c b/virtio/mmio.c
index 4b8c20ec..eff147aa 100644
--- a/virtio/mmio.c
+++ b/virtio/mmio.c
@@ -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;
}
diff --git a/virtio/pci.c b/virtio/pci.c
index 2da2d3f8..99653cad 100644
--- a/virtio/pci.c
+++ b/virtio/pci.c
@@ -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;
}