Commit eb34a8c2 authored by Jean-Philippe Brucker's avatar Jean-Philippe Brucker Committed by Will Deacon
Browse files

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: default avatarJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: default avatarJulien Thierry <julien.thierry@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent ad346c2e
...@@ -54,6 +54,7 @@ struct virtio_mmio { ...@@ -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_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_signal_config(struct kvm *kvm, struct virtio_device *vdev);
int virtio_mmio_exit(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 virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class); int device_id, int subsys_id, int class);
void virtio_mmio_assign_irq(struct device_header *dev_hdr); void virtio_mmio_assign_irq(struct device_header *dev_hdr);
......
...@@ -55,6 +55,7 @@ struct virtio_pci { ...@@ -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_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__signal_config(struct kvm *kvm, struct virtio_device *vdev);
int virtio_pci__exit(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 virtio_pci__init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class); int device_id, int subsys_id, int class);
......
...@@ -201,6 +201,7 @@ struct virtio_ops { ...@@ -201,6 +201,7 @@ struct virtio_ops {
int (*init)(struct kvm *kvm, void *dev, struct virtio_device *vdev, int (*init)(struct kvm *kvm, void *dev, struct virtio_device *vdev,
int device_id, int subsys_id, int class); int device_id, int subsys_id, int class);
int (*exit)(struct kvm *kvm, struct virtio_device *vdev); 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, 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, ...@@ -241,6 +241,13 @@ void virtio_notify_status(struct kvm *kvm, struct virtio_device *vdev,
} else if (!status && (vdev->status & VIRTIO__STATUS_START)) { } else if (!status && (vdev->status & VIRTIO__STATUS_START)) {
vdev->status &= ~VIRTIO__STATUS_START; vdev->status &= ~VIRTIO__STATUS_START;
ext_status |= VIRTIO__STATUS_STOP; 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) if (vdev->ops->notify_status)
...@@ -264,6 +271,7 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, ...@@ -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->signal_config = virtio_pci__signal_config;
vdev->ops->init = virtio_pci__init; vdev->ops->init = virtio_pci__init;
vdev->ops->exit = virtio_pci__exit; vdev->ops->exit = virtio_pci__exit;
vdev->ops->reset = virtio_pci__reset;
vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class); vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
break; break;
case VIRTIO_MMIO: case VIRTIO_MMIO:
...@@ -276,6 +284,7 @@ int virtio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, ...@@ -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->signal_config = virtio_mmio_signal_config;
vdev->ops->init = virtio_mmio_init; vdev->ops->init = virtio_mmio_init;
vdev->ops->exit = virtio_mmio_exit; vdev->ops->exit = virtio_mmio_exit;
vdev->ops->reset = virtio_mmio_reset;
vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class); vdev->ops->init(kvm, dev, vdev, device_id, subsys_id, class);
break; break;
default: default:
......
...@@ -326,15 +326,23 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev, ...@@ -326,15 +326,23 @@ int virtio_mmio_init(struct kvm *kvm, void *dev, struct virtio_device *vdev,
return 0; 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) int virtio_mmio_exit(struct kvm *kvm, struct virtio_device *vdev)
{ {
struct virtio_mmio *vmmio = vdev->virtio; struct virtio_mmio *vmmio = vdev->virtio;
int i;
virtio_mmio_reset(kvm, vdev);
kvm__deregister_mmio(kvm, vmmio->addr); 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; return 0;
} }
...@@ -77,8 +77,8 @@ static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev, ...@@ -77,8 +77,8 @@ static void virtio_pci_exit_vq(struct kvm *kvm, struct virtio_device *vdev,
{ {
struct virtio_pci *vpci = vdev->virtio; 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->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); virtio_exit_vq(kvm, vdev, vpci->dev, vq);
} }
...@@ -522,19 +522,25 @@ free_ioport: ...@@ -522,19 +522,25 @@ free_ioport:
return r; 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) int virtio_pci__exit(struct kvm *kvm, struct virtio_device *vdev)
{ {
struct virtio_pci *vpci = vdev->virtio; 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->mmio_addr);
kvm__deregister_mmio(kvm, vpci->msix_io_block); kvm__deregister_mmio(kvm, vpci->msix_io_block);
ioport__unregister(kvm, vpci->port_addr); 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; return 0;
} }
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment