Commit b4436a0b authored by Cornelia Huck's avatar Cornelia Huck
Browse files

virtio-ccw: Wire up ioeventfd.



On hosts that support ioeventfd, make use of it for host-to-guest
notifications via diagnose 500.

Signed-off-by: default avatarCornelia Huck <cornelia.huck@de.ibm.com>
parent 6504a930
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -68,7 +68,7 @@ int css_create_css_image(uint8_t cssid, bool default_image)
    return 0;
}

static uint16_t css_build_subchannel_id(SubchDev *sch)
uint16_t css_build_subchannel_id(SubchDev *sch)
{
    if (channel_subsys->max_cssid > 0) {
        return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1;
+1 −0
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno);
void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid,
                      uint16_t devno, SubchDev *sch);
void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type);
uint16_t css_build_subchannel_id(SubchDev *sch);
void css_reset(void);
void css_reset_sch(SubchDev *sch);
void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid);
+117 −0
Original line number Diff line number Diff line
@@ -63,6 +63,90 @@ VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch)
    return vdev;
}

static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n,
                                              bool assign, bool set_handler)
{
    VirtQueue *vq = virtio_get_queue(dev->vdev, n);
    EventNotifier *notifier = virtio_queue_get_host_notifier(vq);
    int r = 0;
    SubchDev *sch = dev->sch;
    uint32_t sch_id = (css_build_subchannel_id(sch) << 16) | sch->schid;

    if (assign) {
        r = event_notifier_init(notifier, 1);
        if (r < 0) {
            error_report("%s: unable to init event notifier: %d", __func__, r);
            return r;
        }
        virtio_queue_set_host_notifier_fd_handler(vq, true, set_handler);
        r = s390_assign_subch_ioeventfd(event_notifier_get_fd(notifier), sch_id,
                                        n, assign);
        if (r < 0) {
            error_report("%s: unable to assign ioeventfd: %d", __func__, r);
            virtio_queue_set_host_notifier_fd_handler(vq, false, false);
            event_notifier_cleanup(notifier);
            return r;
        }
    } else {
        virtio_queue_set_host_notifier_fd_handler(vq, false, false);
        s390_assign_subch_ioeventfd(event_notifier_get_fd(notifier), sch_id,
                                    n, assign);
        event_notifier_cleanup(notifier);
    }
    return r;
}

static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev)
{
    int n, r;

    if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) ||
        dev->ioeventfd_started) {
        return;
    }
    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
        if (!virtio_queue_get_num(dev->vdev, n)) {
            continue;
        }
        r = virtio_ccw_set_guest2host_notifier(dev, n, true, true);
        if (r < 0) {
            goto assign_error;
        }
    }
    dev->ioeventfd_started = true;
    return;

  assign_error:
    while (--n >= 0) {
        if (!virtio_queue_get_num(dev->vdev, n)) {
            continue;
        }
        r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
        assert(r >= 0);
    }
    dev->ioeventfd_started = false;
    /* Disable ioeventfd for this device. */
    dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD;
    error_report("%s: failed. Fallback to userspace (slower).", __func__);
}

static void virtio_ccw_stop_ioeventfd(VirtioCcwDevice *dev)
{
    int n, r;

    if (!dev->ioeventfd_started) {
        return;
    }
    for (n = 0; n < VIRTIO_PCI_QUEUE_MAX; n++) {
        if (!virtio_queue_get_num(dev->vdev, n)) {
            continue;
        }
        r = virtio_ccw_set_guest2host_notifier(dev, n, false, false);
        assert(r >= 0);
    }
    dev->ioeventfd_started = false;
}

VirtualCssBus *virtual_css_bus_init(void)
{
    VirtualCssBus *cbus;
@@ -187,6 +271,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
        }
        break;
    case CCW_CMD_VDEV_RESET:
        virtio_ccw_stop_ioeventfd(dev);
        virtio_reset(dev->vdev);
        ret = 0;
        break;
@@ -309,10 +394,16 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
            ret = -EFAULT;
        } else {
            status = ldub_phys(ccw.cda);
            if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) {
                virtio_ccw_stop_ioeventfd(dev);
            }
            virtio_set_status(dev->vdev, status);
            if (dev->vdev->status == 0) {
                virtio_reset(dev->vdev);
            }
            if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
                virtio_ccw_start_ioeventfd(dev);
            }
            sch->curr_status.scsw.count = ccw.count - sizeof(status);
            ret = 0;
        }
@@ -540,6 +631,7 @@ static int virtio_ccw_exit(VirtioCcwDevice *dev)
{
    SubchDev *sch = dev->sch;

    virtio_ccw_stop_ioeventfd(dev);
    if (sch) {
        css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
        g_free(sch);
@@ -801,12 +893,24 @@ static void virtio_ccw_reset(DeviceState *d)
{
    VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);

    virtio_ccw_stop_ioeventfd(dev);
    virtio_reset(dev->vdev);
    css_reset_sch(dev->sch);
    dev->indicators = 0;
    dev->indicators2 = 0;
}

static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
{
    VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);

    if (running) {
        virtio_ccw_start_ioeventfd(dev);
    } else {
        virtio_ccw_stop_ioeventfd(dev);
    }
}

/**************** Virtio-ccw Bus Device Descriptions *******************/

static Property virtio_ccw_net_properties[] = {
@@ -814,6 +918,8 @@ static Property virtio_ccw_net_properties[] = {
    DEFINE_VIRTIO_NET_FEATURES(VirtioCcwDevice, host_features[0]),
    DEFINE_VIRTIO_NET_PROPERTIES(VirtIONetCcw, vdev.net_conf),
    DEFINE_NIC_PROPERTIES(VirtIONetCcw, vdev.nic_conf),
    DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                    VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
    DEFINE_PROP_END_OF_LIST(),
};

@@ -840,6 +946,8 @@ static Property virtio_ccw_blk_properties[] = {
    DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
    DEFINE_VIRTIO_BLK_FEATURES(VirtioCcwDevice, host_features[0]),
    DEFINE_VIRTIO_BLK_PROPERTIES(VirtIOBlkCcw, blk),
    DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                    VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
    DEFINE_PROP_END_OF_LIST(),
};

@@ -866,6 +974,8 @@ static Property virtio_ccw_serial_properties[] = {
    DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
    DEFINE_VIRTIO_SERIAL_PROPERTIES(VirtioSerialCcw, vdev.serial),
    DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
    DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                    VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
    DEFINE_PROP_END_OF_LIST(),
};

@@ -891,6 +1001,8 @@ static const TypeInfo virtio_ccw_serial = {
static Property virtio_ccw_balloon_properties[] = {
    DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
    DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
    DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                    VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
    DEFINE_PROP_END_OF_LIST(),
};

@@ -917,6 +1029,8 @@ static Property virtio_ccw_scsi_properties[] = {
    DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
    DEFINE_VIRTIO_SCSI_PROPERTIES(VirtIOSCSICcw, vdev.parent_obj.conf),
    DEFINE_VIRTIO_SCSI_FEATURES(VirtioCcwDevice, host_features[0]),
    DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                    VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
    DEFINE_PROP_END_OF_LIST(),
};

@@ -980,6 +1094,8 @@ static Property virtio_ccw_rng_properties[] = {
    DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id),
    DEFINE_VIRTIO_COMMON_FEATURES(VirtioCcwDevice, host_features[0]),
    DEFINE_VIRTIO_RNG_PROPERTIES(VirtIORNGCcw, vdev.conf),
    DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags,
                    VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true),
    DEFINE_PROP_END_OF_LIST(),
};

@@ -1107,6 +1223,7 @@ static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data)
    bus_class->max_dev = 1;
    k->notify = virtio_ccw_notify;
    k->get_features = virtio_ccw_get_features;
    k->vmstate_change = virtio_ccw_vmstate_change;
}

static const TypeInfo virtio_ccw_bus_info = {
+7 −0
Original line number Diff line number Diff line
@@ -69,6 +69,11 @@ typedef struct VirtIOCCWDeviceClass {
/* Change here if we want to support more feature bits. */
#define VIRTIO_CCW_FEATURE_SIZE 1

/* Performance improves when virtqueue kick processing is decoupled from the
 * vcpu thread using ioeventfd for some devices. */
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT 1
#define VIRTIO_CCW_FLAG_USE_IOEVENTFD   (1 << VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT)

struct VirtioCcwDevice {
    DeviceState parent_obj;
    SubchDev *sch;
@@ -76,6 +81,8 @@ struct VirtioCcwDevice {
    char *bus_id;
    uint32_t host_features[VIRTIO_CCW_FEATURE_SIZE];
    VirtioBusState bus;
    bool ioeventfd_started;
    uint32_t flags;
    /* Guest provided values: */
    hwaddr indicators;
    hwaddr indicators2;
+16 −0
Original line number Diff line number Diff line
@@ -1081,6 +1081,7 @@ void kvm_s390_io_interrupt(S390CPU *cpu, uint16_t subchannel_id,
void kvm_s390_crw_mchk(S390CPU *cpu);
void kvm_s390_enable_css_support(S390CPU *cpu);
int kvm_s390_get_registers_partial(CPUState *cpu);
int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq, bool assign);
#else
static inline void kvm_s390_io_interrupt(S390CPU *cpu,
                                        uint16_t subchannel_id,
@@ -1099,6 +1100,11 @@ static inline int kvm_s390_get_registers_partial(CPUState *cpu)
{
    return -ENOSYS;
}
static inline int kvm_s390_assign_subch_ioeventfd(int fd, uint32_t sch, int vq,
                                                  bool assign)
{
    return -ENOSYS;
}
#endif

static inline void s390_io_interrupt(S390CPU *cpu,
@@ -1125,4 +1131,14 @@ static inline void s390_crw_mchk(S390CPU *cpu)
    }
}

static inline int s390_assign_subch_ioeventfd(int fd, uint32_t sch_id, int vq,
                                              bool assign)
{
    if (kvm_enabled()) {
        return kvm_s390_assign_subch_ioeventfd(fd, sch_id, vq, assign);
    } else {
        return -ENOSYS;
    }
}

#endif
Loading