Message ID | 20200417023440.70514-8-farman@linux.ibm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | s390x/vfio-ccw: Channel Path Handling [QEMU] | expand |
On Fri, 17 Apr 2020 04:34:40 +0200 Eric Farman <farman@linux.ibm.com> wrote: > From: Farhan Ali <alifm@linux.ibm.com> > > The CRW irq will be used by vfio-ccw to notify the userspace > about any CRWs the userspace needs to handle. Let's add support > for it. > > Signed-off-by: Farhan Ali <alifm@linux.ibm.com> > Signed-off-by: Eric Farman <farman@linux.ibm.com> > --- > > Notes: > v2->v3: > - Remove "size==0" check in CRW notifier [CH] > - Remove intermediate rsc/erc variables, use css_queue_crw_cont() [CH] > - s/crw0/crw/ [CH] > > v1->v2: > - Add a loop to continually read region while data is > present, queueing CRWs as found [CH] > > v0->v1: [EF] > - Check vcdev->crw_region before registering the irq, > in case host kernel does not have matching support > - Split the refactoring changes to an earlier (new) patch > (and don't remove the "num_irqs" check in the register > routine, but adjust it to the check the input variable) > - Don't revert the cool vfio_set_irq_signaling() stuff > - Unregister CRW IRQ before IO IRQ in unrealize > - s/crw1/crw0/ > > hw/vfio/ccw.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 50 insertions(+) > (...) > @@ -264,6 +265,39 @@ static void vfio_ccw_reset(DeviceState *dev) > ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET); > } > > +static void vfio_ccw_crw_notifier_handler(void *opaque) > +{ > + VFIOCCWDevice *vcdev = opaque; > + struct ccw_crw_region *region = vcdev->crw_region; > + CRW crw; > + int size; > + > + if (!event_notifier_test_and_clear(&vcdev->crw_notifier)) { > + return; > + } > + > + do { > + memset(region, 0, sizeof(*region)); > + size = pread(vcdev->vdev.fd, region, vcdev->crw_region_size, > + vcdev->crw_region_offset); > + > + if (size == -1) { > + error_report("vfio-ccw: Read crw region failed with errno=%d", > + errno); > + break; > + } > + > + if (region->crw == 0) { > + /* No more CRWs to queue */ > + break; > + } > + > + memcpy(&crw, ®ion->crw, sizeof(CRW)); > + > + css_queue_crw_cont(crw); > + } while (1); Do you want to clear the notifier again at the end? If the kernel had queued more crws, it would have made the notifier pending again. > +} > + > static void vfio_ccw_io_notifier_handler(void *opaque) > { > VFIOCCWDevice *vcdev = opaque; (...) Else looks good to me.
diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index ee3415a64a..cb4a331ced 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -48,6 +48,7 @@ struct VFIOCCWDevice { uint64_t crw_region_offset; struct ccw_crw_region *crw_region; EventNotifier io_notifier; + EventNotifier crw_notifier; bool force_orb_pfch; bool warned_orb_pfch; }; @@ -264,6 +265,39 @@ static void vfio_ccw_reset(DeviceState *dev) ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET); } +static void vfio_ccw_crw_notifier_handler(void *opaque) +{ + VFIOCCWDevice *vcdev = opaque; + struct ccw_crw_region *region = vcdev->crw_region; + CRW crw; + int size; + + if (!event_notifier_test_and_clear(&vcdev->crw_notifier)) { + return; + } + + do { + memset(region, 0, sizeof(*region)); + size = pread(vcdev->vdev.fd, region, vcdev->crw_region_size, + vcdev->crw_region_offset); + + if (size == -1) { + error_report("vfio-ccw: Read crw region failed with errno=%d", + errno); + break; + } + + if (region->crw == 0) { + /* No more CRWs to queue */ + break; + } + + memcpy(&crw, ®ion->crw, sizeof(CRW)); + + css_queue_crw_cont(crw); + } while (1); +} + static void vfio_ccw_io_notifier_handler(void *opaque) { VFIOCCWDevice *vcdev = opaque; @@ -350,6 +384,10 @@ static void vfio_ccw_register_irq_notifier(VFIOCCWDevice *vcdev, notifier = &vcdev->io_notifier; fd_read = vfio_ccw_io_notifier_handler; break; + case VFIO_CCW_CRW_IRQ_INDEX: + notifier = &vcdev->crw_notifier; + fd_read = vfio_ccw_crw_notifier_handler; + break; default: error_setg(errp, "vfio: Unsupported device irq(%d)", irq); return; @@ -401,6 +439,9 @@ static void vfio_ccw_unregister_irq_notifier(VFIOCCWDevice *vcdev, case VFIO_CCW_IO_IRQ_INDEX: notifier = &vcdev->io_notifier; break; + case VFIO_CCW_CRW_IRQ_INDEX: + notifier = &vcdev->crw_notifier; + break; default: error_report("vfio: Unsupported device irq(%d)", irq); return; @@ -621,6 +662,14 @@ static void vfio_ccw_realize(DeviceState *dev, Error **errp) goto out_notifier_err; } + if (vcdev->crw_region) { + vfio_ccw_register_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX, &err); + if (err) { + vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); + goto out_notifier_err; + } + } + return; out_notifier_err: @@ -645,6 +694,7 @@ static void vfio_ccw_unrealize(DeviceState *dev, Error **errp) S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(cdev); VFIOGroup *group = vcdev->vdev.group; + vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_CRW_IRQ_INDEX); vfio_ccw_unregister_irq_notifier(vcdev, VFIO_CCW_IO_IRQ_INDEX); vfio_ccw_put_region(vcdev); vfio_ccw_put_device(vcdev);