diff options
Diffstat (limited to 'hw')
-rw-r--r-- | hw/s390x/css.c | 173 | ||||
-rw-r--r-- | hw/s390x/event-facility.c | 35 | ||||
-rw-r--r-- | hw/s390x/s390-ccw.c | 11 | ||||
-rw-r--r-- | hw/s390x/s390-pci-bus.c | 4 | ||||
-rw-r--r-- | hw/s390x/s390-virtio-ccw.c | 32 | ||||
-rw-r--r-- | hw/s390x/virtio-ccw.c | 100 | ||||
-rw-r--r-- | hw/s390x/virtio-ccw.h | 22 | ||||
-rw-r--r-- | hw/vfio/ccw.c | 28 |
8 files changed, 255 insertions, 150 deletions
diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 35683d7..f6b5c80 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -488,7 +488,7 @@ int css_create_css_image(uint8_t cssid, bool default_image) if (channel_subsys.css[cssid]) { return -EBUSY; } - channel_subsys.css[cssid] = g_malloc0(sizeof(CssImage)); + channel_subsys.css[cssid] = g_new0(CssImage, 1); if (default_image) { channel_subsys.default_cssid = cssid; } @@ -1181,12 +1181,11 @@ static void sch_handle_start_func_virtual(SubchDev *sch) } -static int sch_handle_start_func_passthrough(SubchDev *sch) +static IOInstEnding sch_handle_start_func_passthrough(SubchDev *sch) { PMCW *p = &sch->curr_status.pmcw; SCSW *s = &sch->curr_status.scsw; - int ret; ORB *orb = &sch->orb; if (!(s->ctrl & SCSW_ACTL_SUSP)) { @@ -1200,31 +1199,12 @@ static int sch_handle_start_func_passthrough(SubchDev *sch) */ if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) || !(orb->ctrl0 & ORB_CTRL0_MASK_C64)) { - return -EINVAL; + warn_report("vfio-ccw requires PFCH and C64 flags set"); + sch_gen_unit_exception(sch); + css_inject_io_interrupt(sch); + return IOINST_CC_EXPECTED; } - - ret = s390_ccw_cmd_request(orb, s, sch->driver_data); - switch (ret) { - /* Currently we don't update control block and just return the cc code. */ - case 0: - break; - case -EBUSY: - break; - case -ENODEV: - break; - case -EACCES: - /* Let's reflect an inaccessible host device by cc 3. */ - ret = -ENODEV; - break; - default: - /* - * All other return codes will trigger a program check, - * or set cc to 1. - */ - break; - }; - - return ret; + return s390_ccw_cmd_request(sch); } /* @@ -1233,7 +1213,7 @@ static int sch_handle_start_func_passthrough(SubchDev *sch) * read/writes) asynchronous later on if we start supporting more than * our current very simple devices. */ -int do_subchannel_work_virtual(SubchDev *sch) +IOInstEnding do_subchannel_work_virtual(SubchDev *sch) { SCSW *s = &sch->curr_status.scsw; @@ -1245,44 +1225,35 @@ int do_subchannel_work_virtual(SubchDev *sch) } else if (s->ctrl & SCSW_FCTL_START_FUNC) { /* Triggered by both ssch and rsch. */ sch_handle_start_func_virtual(sch); - } else { - /* Cannot happen. */ - return 0; } css_inject_io_interrupt(sch); - return 0; + /* inst must succeed if this func is called */ + return IOINST_CC_EXPECTED; } -int do_subchannel_work_passthrough(SubchDev *sch) +IOInstEnding do_subchannel_work_passthrough(SubchDev *sch) { - int ret; SCSW *s = &sch->curr_status.scsw; if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) { /* TODO: Clear handling */ sch_handle_clear_func(sch); - ret = 0; } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { /* TODO: Halt handling */ sch_handle_halt_func(sch); - ret = 0; } else if (s->ctrl & SCSW_FCTL_START_FUNC) { - ret = sch_handle_start_func_passthrough(sch); - } else { - /* Cannot happen. */ - return -ENODEV; + return sch_handle_start_func_passthrough(sch); } - - return ret; + return IOINST_CC_EXPECTED; } -static int do_subchannel_work(SubchDev *sch) +static IOInstEnding do_subchannel_work(SubchDev *sch) { - if (sch->do_subchannel_work) { - return sch->do_subchannel_work(sch); - } else { - return -EINVAL; + if (!sch->do_subchannel_work) { + return IOINST_CC_STATUS_PRESENT; } + g_assert(sch->curr_status.scsw.ctrl & SCSW_CTRL_MASK_FCTL); + return sch->do_subchannel_work(sch); } static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) @@ -1376,28 +1347,24 @@ static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src) } } -int css_do_msch(SubchDev *sch, const SCHIB *orig_schib) +IOInstEnding css_do_msch(SubchDev *sch, const SCHIB *orig_schib) { SCSW *s = &sch->curr_status.scsw; PMCW *p = &sch->curr_status.pmcw; uint16_t oldflags; - int ret; SCHIB schib; if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_DNV)) { - ret = 0; - goto out; + return IOINST_CC_EXPECTED; } if (s->ctrl & SCSW_STCTL_STATUS_PEND) { - ret = -EINPROGRESS; - goto out; + return IOINST_CC_STATUS_PRESENT; } if (s->ctrl & (SCSW_FCTL_START_FUNC|SCSW_FCTL_HALT_FUNC|SCSW_FCTL_CLEAR_FUNC)) { - ret = -EBUSY; - goto out; + return IOINST_CC_BUSY; } copy_schib_from_guest(&schib, orig_schib); @@ -1424,27 +1391,20 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib) && (p->flags & PMCW_FLAGS_MASK_ENA) == 0) { sch->disable_cb(sch); } - - ret = 0; - -out: - return ret; + return IOINST_CC_EXPECTED; } -int css_do_xsch(SubchDev *sch) +IOInstEnding css_do_xsch(SubchDev *sch) { SCSW *s = &sch->curr_status.scsw; PMCW *p = &sch->curr_status.pmcw; - int ret; if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { - ret = -ENODEV; - goto out; + return IOINST_CC_NOT_OPERATIONAL; } if (s->ctrl & SCSW_CTRL_MASK_STCTL) { - ret = -EINPROGRESS; - goto out; + return IOINST_CC_STATUS_PRESENT; } if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) || @@ -1452,8 +1412,7 @@ int css_do_xsch(SubchDev *sch) (!(s->ctrl & (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) || (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) { - ret = -EBUSY; - goto out; + return IOINST_CC_BUSY; } /* Cancel the current operation. */ @@ -1465,56 +1424,43 @@ int css_do_xsch(SubchDev *sch) sch->last_cmd_valid = false; s->dstat = 0; s->cstat = 0; - ret = 0; - -out: - return ret; + return IOINST_CC_EXPECTED; } -int css_do_csch(SubchDev *sch) +IOInstEnding css_do_csch(SubchDev *sch) { SCSW *s = &sch->curr_status.scsw; PMCW *p = &sch->curr_status.pmcw; - int ret; if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { - ret = -ENODEV; - goto out; + return IOINST_CC_NOT_OPERATIONAL; } /* Trigger the clear function. */ s->ctrl &= ~(SCSW_CTRL_MASK_FCTL | SCSW_CTRL_MASK_ACTL); s->ctrl |= SCSW_FCTL_CLEAR_FUNC | SCSW_ACTL_CLEAR_PEND; - do_subchannel_work(sch); - ret = 0; - -out: - return ret; + return do_subchannel_work(sch); } -int css_do_hsch(SubchDev *sch) +IOInstEnding css_do_hsch(SubchDev *sch) { SCSW *s = &sch->curr_status.scsw; PMCW *p = &sch->curr_status.pmcw; - int ret; if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { - ret = -ENODEV; - goto out; + return IOINST_CC_NOT_OPERATIONAL; } if (((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_STATUS_PEND) || (s->ctrl & (SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | SCSW_STCTL_ALERT))) { - ret = -EINPROGRESS; - goto out; + return IOINST_CC_STATUS_PRESENT; } if (s->ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { - ret = -EBUSY; - goto out; + return IOINST_CC_BUSY; } /* Trigger the halt function. */ @@ -1527,11 +1473,7 @@ int css_do_hsch(SubchDev *sch) } s->ctrl |= SCSW_ACTL_HALT_PEND; - do_subchannel_work(sch); - ret = 0; - -out: - return ret; + return do_subchannel_work(sch); } static void css_update_chnmon(SubchDev *sch) @@ -1569,27 +1511,23 @@ static void css_update_chnmon(SubchDev *sch) } } -int css_do_ssch(SubchDev *sch, ORB *orb) +IOInstEnding css_do_ssch(SubchDev *sch, ORB *orb) { SCSW *s = &sch->curr_status.scsw; PMCW *p = &sch->curr_status.pmcw; - int ret; if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { - ret = -ENODEV; - goto out; + return IOINST_CC_NOT_OPERATIONAL; } if (s->ctrl & SCSW_STCTL_STATUS_PEND) { - ret = -EINPROGRESS; - goto out; + return IOINST_CC_STATUS_PRESENT; } if (s->ctrl & (SCSW_FCTL_START_FUNC | SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { - ret = -EBUSY; - goto out; + return IOINST_CC_BUSY; } /* If monitoring is active, update counter. */ @@ -1602,10 +1540,7 @@ int css_do_ssch(SubchDev *sch, ORB *orb) s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); s->flags &= ~SCSW_FLAGS_MASK_PNO; - ret = do_subchannel_work(sch); - -out: - return ret; + return do_subchannel_work(sch); } static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw, @@ -1778,7 +1713,7 @@ void css_undo_stcrw(CRW *crw) { CrwContainer *crw_cont; - crw_cont = g_try_malloc0(sizeof(CrwContainer)); + crw_cont = g_try_new0(CrwContainer, 1); if (!crw_cont) { channel_subsys.crws_lost = true; return; @@ -1852,27 +1787,23 @@ void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo) } } -int css_do_rsch(SubchDev *sch) +IOInstEnding css_do_rsch(SubchDev *sch) { SCSW *s = &sch->curr_status.scsw; PMCW *p = &sch->curr_status.pmcw; - int ret; if (~(p->flags) & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA)) { - ret = -ENODEV; - goto out; + return IOINST_CC_NOT_OPERATIONAL; } if (s->ctrl & SCSW_STCTL_STATUS_PEND) { - ret = -EINPROGRESS; - goto out; + return IOINST_CC_STATUS_PRESENT; } if (((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || (s->ctrl & SCSW_ACTL_RESUME_PEND) || (!(s->ctrl & SCSW_ACTL_SUSP))) { - ret = -EINVAL; - goto out; + return IOINST_CC_BUSY; } /* If monitoring is active, update counter. */ @@ -1881,11 +1812,7 @@ int css_do_rsch(SubchDev *sch) } s->ctrl |= SCSW_ACTL_RESUME_PEND; - do_subchannel_work(sch); - ret = 0; - -out: - return ret; + return do_subchannel_work(sch); } int css_do_rchp(uint8_t cssid, uint8_t chpid) @@ -2185,7 +2112,7 @@ void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, css = channel_subsys.css[cssid]; if (!css->sch_set[ssid]) { - css->sch_set[ssid] = g_malloc0(sizeof(SubchSet)); + css->sch_set[ssid] = g_new0(SubchSet, 1); } s_set = css->sch_set[ssid]; @@ -2206,7 +2133,7 @@ void css_queue_crw(uint8_t rsc, uint8_t erc, int solicited, trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : ""); /* TODO: Maybe use a static crw pool? */ - crw_cont = g_try_malloc0(sizeof(CrwContainer)); + crw_cont = g_try_new0(CrwContainer, 1); if (!crw_cont) { channel_subsys.crws_lost = true; return; @@ -2498,7 +2425,7 @@ SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, } } - sch = g_malloc0(sizeof(*sch)); + sch = g_new0(SubchDev, 1); sch->cssid = bus_id.cssid; sch->ssid = bus_id.ssid; sch->devno = bus_id.devid; diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 34b2faf..b0f71f4 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -259,23 +259,46 @@ out: return; } +/* copy up to dst_len bytes and fill the rest of dst with zeroes */ +static void copy_mask(uint8_t *dst, uint8_t *src, uint16_t dst_len, + uint16_t src_len) +{ + int i; + + for (i = 0; i < dst_len; i++) { + dst[i] = i < src_len ? src[i] : 0; + } +} + static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb) { WriteEventMask *we_mask = (WriteEventMask *) sccb; + uint16_t mask_length = be16_to_cpu(we_mask->mask_length); + uint32_t tmp_mask; - /* Attention: We assume that Linux uses 4-byte masks, what it actually - does. Architecture allows for masks of variable size, though */ - if (be16_to_cpu(we_mask->mask_length) != 4) { + if (!mask_length || (mask_length > SCLP_EVENT_MASK_LEN_MAX)) { sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH); goto out; } + /* + * Note: We currently only support masks up to 4 byte length; + * the remainder is filled up with zeroes. Linux uses + * a 4 byte mask length. + */ + /* keep track of the guest's capability masks */ - ef->receive_mask = be32_to_cpu(we_mask->cp_receive_mask); + copy_mask((uint8_t *)&tmp_mask, WEM_CP_RECEIVE_MASK(we_mask, mask_length), + sizeof(tmp_mask), mask_length); + ef->receive_mask = be32_to_cpu(tmp_mask); /* return the SCLP's capability masks to the guest */ - we_mask->send_mask = cpu_to_be32(get_host_send_mask(ef)); - we_mask->receive_mask = cpu_to_be32(get_host_receive_mask(ef)); + tmp_mask = cpu_to_be32(get_host_send_mask(ef)); + copy_mask(WEM_RECEIVE_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask, + mask_length, sizeof(tmp_mask)); + tmp_mask = cpu_to_be32(get_host_receive_mask(ef)); + copy_mask(WEM_SEND_MASK(we_mask, mask_length), (uint8_t *)&tmp_mask, + mask_length, sizeof(tmp_mask)); sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c index 8614dda..0ef232e 100644 --- a/hw/s390x/s390-ccw.c +++ b/hw/s390x/s390-ccw.c @@ -18,15 +18,14 @@ #include "hw/s390x/css-bridge.h" #include "hw/s390x/s390-ccw.h" -int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data) +IOInstEnding s390_ccw_cmd_request(SubchDev *sch) { - S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(data); + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(sch->driver_data); - if (cdc->handle_request) { - return cdc->handle_request(orb, scsw, data); - } else { - return -ENOSYS; + if (!cdc->handle_request) { + return IOINST_CC_STATUS_PRESENT; } + return cdc->handle_request(sch); } static void s390_ccw_get_dev_info(S390CCWDevice *cdev, diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 96116b7..e7a58e8 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -240,7 +240,7 @@ static void s390_pci_generate_event(uint8_t cc, uint16_t pec, uint32_t fh, SeiContainer *sei_cont; S390pciState *s = s390_get_phb(); - sei_cont = g_malloc0(sizeof(SeiContainer)); + sei_cont = g_new0(SeiContainer, 1); sei_cont->fh = fh; sei_cont->fid = fid; sei_cont->cc = cc; @@ -416,7 +416,7 @@ static S390PCIIOMMU *s390_pci_get_iommu(S390pciState *s, PCIBus *bus, S390PCIIOMMU *iommu; if (!table) { - table = g_malloc0(sizeof(S390PCIIOMMUTable)); + table = g_new0(S390PCIIOMMUTable, 1); table->key = key; g_hash_table_insert(s->iommu_table, &table->key, table); } diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index 32d3f11..baeafdc 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -52,15 +52,34 @@ S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) return S390_CPU(ms->possible_cpus->cpus[cpu_addr].cpu); } +static S390CPU *s390x_new_cpu(const char *typename, uint32_t core_id, + Error **errp) +{ + S390CPU *cpu = S390_CPU(object_new(typename)); + Error *err = NULL; + + object_property_set_int(OBJECT(cpu), core_id, "core-id", &err); + if (err != NULL) { + goto out; + } + object_property_set_bool(OBJECT(cpu), true, "realized", &err); + +out: + object_unref(OBJECT(cpu)); + if (err) { + error_propagate(errp, err); + cpu = NULL; + } + return cpu; +} + static void s390_init_cpus(MachineState *machine) { MachineClass *mc = MACHINE_GET_CLASS(machine); int i; if (tcg_enabled() && max_cpus > 1) { - error_report("Number of SMP CPUs requested (%d) exceeds max CPUs " - "supported by TCG (1) on s390x", max_cpus); - exit(1); + error_report("WARNING: SMP support on s390x is experimental!"); } /* initialize possible_cpus */ @@ -258,6 +277,9 @@ static void ccw_init(MachineState *machine) s390_flic_init(); + /* init the SIGP facility */ + s390_init_sigp(); + /* get a BUS */ css_bus = virtual_css_bus_init(); s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, @@ -397,9 +419,7 @@ static void s390_nmi(NMIState *n, int cpu_index, Error **errp) { CPUState *cs = qemu_get_cpu(cpu_index); - if (s390_cpu_restart(S390_CPU(cs))) { - error_setg(errp, QERR_UNSUPPORTED); - } + s390_cpu_restart(S390_CPU(cs)); } static void ccw_machine_class_init(ObjectClass *oc, void *data) diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index 085f17f..184515c 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -953,6 +953,15 @@ static void virtio_ccw_gpu_realize(VirtioCcwDevice *ccw_dev, Error **errp) object_property_set_bool(OBJECT(vdev), true, "realized", errp); } +static void virtio_ccw_input_realize(VirtioCcwDevice *ccw_dev, Error **errp) +{ + VirtIOInputCcw *dev = VIRTIO_INPUT_CCW(ccw_dev); + DeviceState *vdev = DEVICE(&dev->vdev); + + qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); + object_property_set_bool(OBJECT(vdev), true, "realized", errp); +} + /* DeviceState to VirtioCcwDevice. Note: used on datapath, * be careful and test performance if you change this. */ @@ -1601,6 +1610,92 @@ static const TypeInfo virtio_ccw_gpu = { .class_init = virtio_ccw_gpu_class_init, }; +static Property virtio_ccw_input_properties[] = { + DEFINE_PROP_BIT("ioeventfd", VirtioCcwDevice, flags, + VIRTIO_CCW_FLAG_USE_IOEVENTFD_BIT, true), + DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, + VIRTIO_CCW_MAX_REV), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_ccw_input_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); + + k->realize = virtio_ccw_input_realize; + k->exit = virtio_ccw_exit; + dc->reset = virtio_ccw_reset; + dc->props = virtio_ccw_input_properties; + set_bit(DEVICE_CATEGORY_INPUT, dc->categories); +} + +static void virtio_ccw_keyboard_instance_init(Object *obj) +{ + VirtIOInputHIDCcw *dev = VIRTIO_INPUT_HID_CCW(obj); + VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj); + + ccw_dev->force_revision_1 = true; + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_KEYBOARD); +} + +static void virtio_ccw_mouse_instance_init(Object *obj) +{ + VirtIOInputHIDCcw *dev = VIRTIO_INPUT_HID_CCW(obj); + VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj); + + ccw_dev->force_revision_1 = true; + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_MOUSE); +} + +static void virtio_ccw_tablet_instance_init(Object *obj) +{ + VirtIOInputHIDCcw *dev = VIRTIO_INPUT_HID_CCW(obj); + VirtioCcwDevice *ccw_dev = VIRTIO_CCW_DEVICE(obj); + + ccw_dev->force_revision_1 = true; + virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), + TYPE_VIRTIO_TABLET); +} + +static const TypeInfo virtio_ccw_input = { + .name = TYPE_VIRTIO_INPUT_CCW, + .parent = TYPE_VIRTIO_CCW_DEVICE, + .instance_size = sizeof(VirtIOInputCcw), + .class_init = virtio_ccw_input_class_init, + .abstract = true, +}; + +static const TypeInfo virtio_ccw_input_hid = { + .name = TYPE_VIRTIO_INPUT_HID_CCW, + .parent = TYPE_VIRTIO_INPUT_CCW, + .instance_size = sizeof(VirtIOInputHIDCcw), + .abstract = true, +}; + +static const TypeInfo virtio_ccw_keyboard = { + .name = TYPE_VIRTIO_KEYBOARD_CCW, + .parent = TYPE_VIRTIO_INPUT_HID_CCW, + .instance_size = sizeof(VirtIOInputHIDCcw), + .instance_init = virtio_ccw_keyboard_instance_init, +}; + +static const TypeInfo virtio_ccw_mouse = { + .name = TYPE_VIRTIO_MOUSE_CCW, + .parent = TYPE_VIRTIO_INPUT_HID_CCW, + .instance_size = sizeof(VirtIOInputHIDCcw), + .instance_init = virtio_ccw_mouse_instance_init, +}; + +static const TypeInfo virtio_ccw_tablet = { + .name = TYPE_VIRTIO_TABLET_CCW, + .parent = TYPE_VIRTIO_INPUT_HID_CCW, + .instance_size = sizeof(VirtIOInputHIDCcw), + .instance_init = virtio_ccw_tablet_instance_init, +}; + static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp) { VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; @@ -1801,6 +1896,11 @@ static void virtio_ccw_register(void) #endif type_register_static(&virtio_ccw_crypto); type_register_static(&virtio_ccw_gpu); + type_register_static(&virtio_ccw_input); + type_register_static(&virtio_ccw_input_hid); + type_register_static(&virtio_ccw_keyboard); + type_register_static(&virtio_ccw_mouse); + type_register_static(&virtio_ccw_tablet); } type_init(virtio_ccw_register) diff --git a/hw/s390x/virtio-ccw.h b/hw/s390x/virtio-ccw.h index 541fdd2..3905f3a 100644 --- a/hw/s390x/virtio-ccw.h +++ b/hw/s390x/virtio-ccw.h @@ -28,6 +28,7 @@ #include "hw/virtio/vhost-vsock.h" #endif /* CONFIG_VHOST_VSOCK */ #include "hw/virtio/virtio-gpu.h" +#include "hw/virtio/virtio-input.h" #include "hw/s390x/s390_flic.h" #include "hw/s390x/css.h" @@ -233,4 +234,25 @@ typedef struct VirtIOGPUCcw { VirtIOGPU vdev; } VirtIOGPUCcw; +#define TYPE_VIRTIO_INPUT_CCW "virtio-input-ccw" +#define VIRTIO_INPUT_CCW(obj) \ + OBJECT_CHECK(VirtIOInputCcw, (obj), TYPE_VIRTIO_INPUT_CCW) + +typedef struct VirtIOInputCcw { + VirtioCcwDevice parent_obj; + VirtIOInput vdev; +} VirtIOInputCcw; + +#define TYPE_VIRTIO_INPUT_HID_CCW "virtio-input-hid-ccw" +#define TYPE_VIRTIO_KEYBOARD_CCW "virtio-keyboard-ccw" +#define TYPE_VIRTIO_MOUSE_CCW "virtio-mouse-ccw" +#define TYPE_VIRTIO_TABLET_CCW "virtio-tablet-ccw" +#define VIRTIO_INPUT_HID_CCW(obj) \ + OBJECT_CHECK(VirtIOInputHIDCcw, (obj), TYPE_VIRTIO_INPUT_HID_CCW) + +typedef struct VirtIOInputHIDCcw { + VirtioCcwDevice parent_obj; + VirtIOInputHID vdev; +} VirtIOInputHIDCcw; + #endif diff --git a/hw/vfio/ccw.c b/hw/vfio/ccw.c index 76323c6..636729c 100644 --- a/hw/vfio/ccw.c +++ b/hw/vfio/ccw.c @@ -47,9 +47,9 @@ struct VFIODeviceOps vfio_ccw_ops = { .vfio_compute_needs_reset = vfio_ccw_compute_needs_reset, }; -static int vfio_ccw_handle_request(ORB *orb, SCSW *scsw, void *data) +static IOInstEnding vfio_ccw_handle_request(SubchDev *sch) { - S390CCWDevice *cdev = data; + S390CCWDevice *cdev = sch->driver_data; VFIOCCWDevice *vcdev = DO_UPCAST(VFIOCCWDevice, cdev, cdev); struct ccw_io_region *region = vcdev->io_region; int ret; @@ -60,8 +60,8 @@ static int vfio_ccw_handle_request(ORB *orb, SCSW *scsw, void *data) memset(region, 0, sizeof(*region)); - memcpy(region->orb_area, orb, sizeof(ORB)); - memcpy(region->scsw_area, scsw, sizeof(SCSW)); + memcpy(region->orb_area, &sch->orb, sizeof(ORB)); + memcpy(region->scsw_area, &sch->curr_status.scsw, sizeof(SCSW)); again: ret = pwrite(vcdev->vdev.fd, region, @@ -71,10 +71,24 @@ again: goto again; } error_report("vfio-ccw: wirte I/O region failed with errno=%d", errno); - return -errno; + ret = -errno; + } else { + ret = region->ret_code; + } + switch (ret) { + case 0: + return IOINST_CC_EXPECTED; + case -EBUSY: + return IOINST_CC_BUSY; + case -ENODEV: + case -EACCES: + return IOINST_CC_NOT_OPERATIONAL; + case -EFAULT: + default: + sch_gen_unit_exception(sch); + css_inject_io_interrupt(sch); + return IOINST_CC_EXPECTED; } - - return region->ret_code; } static void vfio_ccw_reset(DeviceState *dev) |