vfio-ccw: Wire in the request callback
authorEric Farman <farman@linux.ibm.com>
Thu, 3 Dec 2020 21:35:12 +0000 (22:35 +0100)
committerAlex Williamson <alex.williamson@redhat.com>
Thu, 3 Dec 2020 23:21:08 +0000 (16:21 -0700)
The device is being unplugged, so pass the request to userspace to
ask for a graceful cleanup. This should free up the thread that
would otherwise loop waiting for the device to be fully released.

Signed-off-by: Eric Farman <farman@linux.ibm.com>
Reviewed-by: Cornelia Huck <cohuck@redhat.com>
Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
drivers/s390/cio/vfio_ccw_ops.c
drivers/s390/cio/vfio_ccw_private.h
include/uapi/linux/vfio.h

index 8b3ed5b45277aca1f3083420cc532169f002715e..68106be4ba7a19b5fb182e820cf92cc132eb328e 100644 (file)
@@ -394,6 +394,7 @@ static int vfio_ccw_mdev_get_irq_info(struct vfio_irq_info *info)
        switch (info->index) {
        case VFIO_CCW_IO_IRQ_INDEX:
        case VFIO_CCW_CRW_IRQ_INDEX:
+       case VFIO_CCW_REQ_IRQ_INDEX:
                info->count = 1;
                info->flags = VFIO_IRQ_INFO_EVENTFD;
                break;
@@ -424,6 +425,9 @@ static int vfio_ccw_mdev_set_irqs(struct mdev_device *mdev,
        case VFIO_CCW_CRW_IRQ_INDEX:
                ctx = &private->crw_trigger;
                break;
+       case VFIO_CCW_REQ_IRQ_INDEX:
+               ctx = &private->req_trigger;
+               break;
        default:
                return -EINVAL;
        }
@@ -607,6 +611,27 @@ static ssize_t vfio_ccw_mdev_ioctl(struct mdev_device *mdev,
        }
 }
 
+/* Request removal of the device*/
+static void vfio_ccw_mdev_request(struct mdev_device *mdev, unsigned int count)
+{
+       struct vfio_ccw_private *private = dev_get_drvdata(mdev_parent_dev(mdev));
+
+       if (!private)
+               return;
+
+       if (private->req_trigger) {
+               if (!(count % 10))
+                       dev_notice_ratelimited(mdev_dev(private->mdev),
+                                              "Relaying device request to user (#%u)\n",
+                                              count);
+
+               eventfd_signal(private->req_trigger, 1);
+       } else if (count == 0) {
+               dev_notice(mdev_dev(private->mdev),
+                          "No device request channel registered, blocked until released by user\n");
+       }
+}
+
 static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
        .owner                  = THIS_MODULE,
        .supported_type_groups  = mdev_type_groups,
@@ -617,6 +642,7 @@ static const struct mdev_parent_ops vfio_ccw_mdev_ops = {
        .read                   = vfio_ccw_mdev_read,
        .write                  = vfio_ccw_mdev_write,
        .ioctl                  = vfio_ccw_mdev_ioctl,
+       .request                = vfio_ccw_mdev_request,
 };
 
 int vfio_ccw_mdev_reg(struct subchannel *sch)
index 8723156b29eac64dba9ca3392041f59757cf3034..b2c762eb42b9bb799b3b4d98bd3bd5ae634de6f5 100644 (file)
@@ -84,7 +84,10 @@ struct vfio_ccw_crw {
  * @irb: irb info received from interrupt
  * @scsw: scsw info
  * @io_trigger: eventfd ctx for signaling userspace I/O results
+ * @crw_trigger: eventfd ctx for signaling userspace CRW information
+ * @req_trigger: eventfd ctx for signaling userspace to return device
  * @io_work: work for deferral process of I/O handling
+ * @crw_work: work for deferral process of CRW handling
  */
 struct vfio_ccw_private {
        struct subchannel       *sch;
@@ -108,6 +111,7 @@ struct vfio_ccw_private {
 
        struct eventfd_ctx      *io_trigger;
        struct eventfd_ctx      *crw_trigger;
+       struct eventfd_ctx      *req_trigger;
        struct work_struct      io_work;
        struct work_struct      crw_work;
 } __aligned(8);
index 2f313a238a8f2e08d0d47733694690249deb9119..d1812777139f637c534727b852a3ac5e359dca8b 100644 (file)
@@ -820,6 +820,7 @@ enum {
 enum {
        VFIO_CCW_IO_IRQ_INDEX,
        VFIO_CCW_CRW_IRQ_INDEX,
+       VFIO_CCW_REQ_IRQ_INDEX,
        VFIO_CCW_NUM_IRQS
 };