Commit f030532f authored by Farhan Ali's avatar Farhan Ali Committed by Cornelia Huck
Browse files

vfio-ccw: Add support for the CRW region and IRQ



The crw region can be used to obtain information about
Channel Report Words (CRW) from vfio-ccw driver.

Currently only channel-path related CRWs are passed to
QEMU from vfio-ccw driver.

Signed-off-by: default avatarFarhan Ali <alifm@linux.ibm.com>
Signed-off-by: default avatarEric Farman <farman@linux.ibm.com>
Reviewed-by: default avatarCornelia Huck <cohuck@redhat.com>
Message-Id: <20200505125757.98209-7-farman@linux.ibm.com>
Signed-off-by: default avatarCornelia Huck <cohuck@redhat.com>
parent f6dde1b0
Loading
Loading
Loading
Loading
+73 −0
Original line number Diff line number Diff line
@@ -44,7 +44,11 @@ struct VFIOCCWDevice {
    uint64_t schib_region_size;
    uint64_t schib_region_offset;
    struct ccw_schib_region *schib_region;
    uint64_t crw_region_size;
    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;
};
@@ -254,6 +258,44 @@ static void vfio_ccw_reset(DeviceState *dev)
    ioctl(vcdev->vdev.fd, VFIO_DEVICE_RESET);
}

static void vfio_ccw_crw_read(VFIOCCWDevice *vcdev)
{
    struct ccw_crw_region *region = vcdev->crw_region;
    CRW crw;
    int size;

    /* Keep reading CRWs as long as data is returned */
    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, &region->crw, sizeof(CRW));

        css_crw_add_to_queue(crw);
    } while (1);
}

static void vfio_ccw_crw_notifier_handler(void *opaque)
{
    VFIOCCWDevice *vcdev = opaque;

    while (event_notifier_test_and_clear(&vcdev->crw_notifier)) {
        vfio_ccw_crw_read(vcdev);
    }
}

static void vfio_ccw_io_notifier_handler(void *opaque)
{
    VFIOCCWDevice *vcdev = opaque;
@@ -340,6 +382,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;
@@ -391,6 +437,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;
@@ -468,10 +517,24 @@ static void vfio_ccw_get_region(VFIOCCWDevice *vcdev, Error **errp)
        vcdev->schib_region = g_malloc(info->size);
    }

    ret = vfio_get_dev_region_info(vdev, VFIO_REGION_TYPE_CCW,
                                   VFIO_REGION_SUBTYPE_CCW_CRW, &info);

    if (!ret) {
        vcdev->crw_region_size = info->size;
        if (sizeof(*vcdev->crw_region) != vcdev->crw_region_size) {
            error_setg(errp, "vfio: Unexpected size of the CRW region");
            goto out_err;
        }
        vcdev->crw_region_offset = info->offset;
        vcdev->crw_region = g_malloc(info->size);
    }

    g_free(info);
    return;

out_err:
    g_free(vcdev->crw_region);
    g_free(vcdev->schib_region);
    g_free(vcdev->async_cmd_region);
    g_free(vcdev->io_region);
@@ -481,6 +544,7 @@ out_err:

static void vfio_ccw_put_region(VFIOCCWDevice *vcdev)
{
    g_free(vcdev->crw_region);
    g_free(vcdev->schib_region);
    g_free(vcdev->async_cmd_region);
    g_free(vcdev->io_region);
@@ -596,6 +660,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:
@@ -620,6 +692,7 @@ static void vfio_ccw_unrealize(DeviceState *dev)
    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);