diff options
author | Cornelia Huck <cornelia.huck@de.ibm.com> | 2013-02-19 13:48:17 +0100 |
---|---|---|
committer | Cornelia Huck <cornelia.huck@de.ibm.com> | 2013-06-25 17:11:12 +0200 |
commit | 320ce8503baf081725f74514d73d7bd65071a45e (patch) | |
tree | 33875a71c9a7fafe22cd91f66853232e0a5a414c | |
parent | b4436a0b4db0334c3157f71e9baa2944a133c4d4 (diff) |
virtio-ccw: Wire up guest and host notifies.
Guest and host notifiers are needed by vhost. We use ioeventfds for
the guest notifiers, but need to fall back on qemu injecting interrupts
for the host notifiers.
Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
-rw-r--r-- | hw/s390x/virtio-ccw.c | 88 | ||||
-rw-r--r-- | hw/s390x/virtio-ccw.h | 1 |
2 files changed, 89 insertions, 0 deletions
diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 4ad9d9a2e4..faef5ddf57 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -101,6 +101,7 @@ static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) int n, r; if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) || + dev->ioeventfd_disabled || dev->ioeventfd_started) { return; } @@ -911,6 +912,90 @@ static void virtio_ccw_vmstate_change(DeviceState *d, bool running) } } +static bool virtio_ccw_query_guest_notifiers(DeviceState *d) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + + return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA); +} + +static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + + /* Stop using the generic ioeventfd, we are doing eventfd handling + * ourselves below */ + dev->ioeventfd_disabled = assign; + if (assign) { + virtio_ccw_stop_ioeventfd(dev); + } + return virtio_ccw_set_guest2host_notifier(dev, n, assign, false); +} + +static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, + bool assign, bool with_irqfd) +{ + VirtQueue *vq = virtio_get_queue(dev->vdev, n); + EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); + VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(dev->vdev); + + if (assign) { + int r = event_notifier_init(notifier, 0); + + if (r < 0) { + return r; + } + virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); + /* We do not support irqfd for classic I/O interrupts, because the + * classic interrupts are intermixed with the subchannel status, that + * is queried with test subchannel. We want to use vhost, though. + * Lets make sure to have vhost running and wire up the irq fd to + * land in qemu (and only the irq fd) in this code. + */ + if (k->guest_notifier_mask) { + k->guest_notifier_mask(dev->vdev, n, false); + } + /* get lost events and re-inject */ + if (k->guest_notifier_pending && + k->guest_notifier_pending(dev->vdev, n)) { + event_notifier_set(notifier); + } + } else { + if (k->guest_notifier_mask) { + k->guest_notifier_mask(dev->vdev, n, true); + } + virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); + event_notifier_cleanup(notifier); + } + return 0; +} + +static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, + bool assigned) +{ + VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); + VirtIODevice *vdev = dev->vdev; + int r, n; + + for (n = 0; n < nvqs; n++) { + if (!virtio_queue_get_num(vdev, n)) { + break; + } + /* false -> true, as soon as irqfd works */ + r = virtio_ccw_set_guest_notifier(dev, n, assigned, false); + if (r < 0) { + goto assign_error; + } + } + return 0; + +assign_error: + while (--n >= 0) { + virtio_ccw_set_guest_notifier(dev, n, !assigned, false); + } + return r; +} + /**************** Virtio-ccw Bus Device Descriptions *******************/ static Property virtio_ccw_net_properties[] = { @@ -1224,6 +1309,9 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) k->notify = virtio_ccw_notify; k->get_features = virtio_ccw_get_features; k->vmstate_change = virtio_ccw_vmstate_change; + k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; + k->set_host_notifier = virtio_ccw_set_host_notifier; + k->set_guest_notifiers = virtio_ccw_set_guest_notifiers; } static const TypeInfo virtio_ccw_bus_info = { diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 433f27af4b..96d6f5d5b7 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -82,6 +82,7 @@ struct VirtioCcwDevice { uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE]; VirtioBusState bus; bool ioeventfd_started; + bool ioeventfd_disabled; uint32_t flags; /* Guest provided values: */ hwaddr indicators; |