diff options
Diffstat (limited to 'hw/s390x')
| -rw-r--r-- | hw/s390x/3270-ccw.c | 6 | ||||
| -rw-r--r-- | hw/s390x/Makefile.objs | 1 | ||||
| -rw-r--r-- | hw/s390x/css-bridge.c | 2 | ||||
| -rw-r--r-- | hw/s390x/css.c | 290 | ||||
| -rw-r--r-- | hw/s390x/ipl.c | 2 | ||||
| -rw-r--r-- | hw/s390x/s390-ccw.c | 153 | ||||
| -rw-r--r-- | hw/s390x/s390-pci-bus.c | 2 | ||||
| -rw-r--r-- | hw/s390x/s390-pci-inst.c | 2 | ||||
| -rw-r--r-- | hw/s390x/s390-virtio-ccw.c | 32 | ||||
| -rw-r--r-- | hw/s390x/virtio-ccw.c | 7 |
10 files changed, 471 insertions, 26 deletions
diff --git a/hw/s390x/3270-ccw.c b/hw/s390x/3270-ccw.c index a7a5b412e4..6e6eee4e90 100644 --- a/hw/s390x/3270-ccw.c +++ b/hw/s390x/3270-ccw.c @@ -98,9 +98,13 @@ static void emulated_ccw_3270_realize(DeviceState *ds, Error **errp) EmulatedCcw3270Class *ck = EMULATED_CCW_3270_GET_CLASS(dev); CcwDevice *cdev = CCW_DEVICE(ds); CCWDeviceClass *cdk = CCW_DEVICE_GET_CLASS(cdev); - SubchDev *sch = css_create_virtual_sch(cdev->devno, errp); + DeviceState *parent = DEVICE(cdev); + BusState *qbus = qdev_get_parent_bus(parent); + VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); + SubchDev *sch; Error *err = NULL; + sch = css_create_sch(cdev->devno, true, cbus->squash_mcss, errp); if (!sch) { return; } diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs index 36bd4b1645..a8e5575a8a 100644 --- a/hw/s390x/Makefile.objs +++ b/hw/s390x/Makefile.objs @@ -14,3 +14,4 @@ obj-y += ccw-device.o obj-y += s390-pci-bus.o s390-pci-inst.o obj-y += s390-skeys.o obj-$(CONFIG_KVM) += s390-skeys-kvm.o +obj-y += s390-ccw.o diff --git a/hw/s390x/css-bridge.c b/hw/s390x/css-bridge.c index b54ac01d37..823747fcd7 100644 --- a/hw/s390x/css-bridge.c +++ b/hw/s390x/css-bridge.c @@ -17,6 +17,7 @@ #include "hw/s390x/css.h" #include "ccw-device.h" #include "hw/s390x/css-bridge.h" +#include "cpu.h" /* * Invoke device-specific unplug handler, disable the subchannel @@ -103,6 +104,7 @@ VirtualCssBus *virtual_css_bus_init(void) /* Create bus on bridge device */ bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); cbus = VIRTUAL_CSS_BUS(bus); + cbus->squash_mcss = s390_get_squash_mcss(); /* Enable hotplugging */ qbus_set_hotplug_handler(bus, dev, &error_abort); diff --git a/hw/s390x/css.c b/hw/s390x/css.c index 15c4f4b249..1e2f26b65a 100644 --- a/hw/s390x/css.c +++ b/hw/s390x/css.c @@ -13,6 +13,7 @@ #include "qapi/error.h" #include "qapi/visitor.h" #include "hw/qdev.h" +#include "qemu/error-report.h" #include "qemu/bitops.h" #include "exec/address-spaces.h" #include "cpu.h" @@ -258,7 +259,7 @@ uint16_t css_build_subchannel_id(SubchDev *sch) return css_do_build_subchannel_id(sch->cssid, sch->ssid); } -static void css_inject_io_interrupt(SubchDev *sch) +void css_inject_io_interrupt(SubchDev *sch) { uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; @@ -523,7 +524,7 @@ static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, return ret; } -static void sch_handle_start_func(SubchDev *sch, ORB *orb) +static void sch_handle_start_func_virtual(SubchDev *sch, ORB *orb) { PMCW *p = &sch->curr_status.pmcw; @@ -625,13 +626,58 @@ static void sch_handle_start_func(SubchDev *sch, ORB *orb) } +static int sch_handle_start_func_passthrough(SubchDev *sch, ORB *orb) +{ + + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + int ret; + + if (!(s->ctrl & SCSW_ACTL_SUSP)) { + assert(orb != NULL); + p->intparm = orb->intparm; + } + + /* + * Only support prefetch enable mode. + * Only support 64bit addressing idal. + */ + if (!(orb->ctrl0 & ORB_CTRL0_MASK_PFCH) || + !(orb->ctrl0 & ORB_CTRL0_MASK_C64)) { + return -EINVAL; + } + + 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; +} + /* * On real machines, this would run asynchronously to the main vcpus. * We might want to make some parts of the ssch handling (interpreting * read/writes) asynchronous later on if we start supporting more than * our current very simple devices. */ -static void do_subchannel_work(SubchDev *sch, ORB *orb) +int do_subchannel_work_virtual(SubchDev *sch, ORB *orb) { SCSW *s = &sch->curr_status.scsw; @@ -642,12 +688,45 @@ static void do_subchannel_work(SubchDev *sch, ORB *orb) sch_handle_halt_func(sch); } else if (s->ctrl & SCSW_FCTL_START_FUNC) { /* Triggered by both ssch and rsch. */ - sch_handle_start_func(sch, orb); + sch_handle_start_func_virtual(sch, orb); } else { /* Cannot happen. */ - return; + return 0; } css_inject_io_interrupt(sch); + return 0; +} + +int do_subchannel_work_passthrough(SubchDev *sch, ORB *orb) +{ + 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, orb); + } else { + /* Cannot happen. */ + return -ENODEV; + } + + return ret; +} + +static int do_subchannel_work(SubchDev *sch, ORB *orb) +{ + if (sch->do_subchannel_work) { + return sch->do_subchannel_work(sch, orb); + } else { + return -EINVAL; + } } static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) @@ -670,7 +749,7 @@ static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) dest->chars = cpu_to_be32(src->chars); } -static void copy_scsw_to_guest(SCSW *dest, const SCSW *src) +void copy_scsw_to_guest(SCSW *dest, const SCSW *src) { dest->flags = cpu_to_be16(src->flags); dest->ctrl = cpu_to_be16(src->ctrl); @@ -966,8 +1045,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; - do_subchannel_work(sch, orb); - ret = 0; + ret = do_subchannel_work(sch, orb); out: return ret; @@ -1326,7 +1404,8 @@ unsigned int css_find_free_chpid(uint8_t cssid) return MAX_CHPID + 1; } -static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) +static int css_add_chpid(uint8_t cssid, uint8_t chpid, uint8_t type, + bool is_virt) { CssImage *css; @@ -1340,7 +1419,7 @@ static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) } css->chpids[chpid].in_use = 1; css->chpids[chpid].type = type; - css->chpids[chpid].is_virtual = 1; + css->chpids[chpid].is_virtual = is_virt; css_generate_chp_crws(cssid, chpid); @@ -1364,7 +1443,7 @@ void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type) p->pam = 0x80; p->chpid[0] = chpid; if (!css->chpids[chpid].in_use) { - css_add_virtual_chpid(sch->cssid, chpid, type); + css_add_chpid(sch->cssid, chpid, type, true); } memset(s, 0, sizeof(SCSW)); @@ -1946,28 +2025,59 @@ PropertyInfo css_devid_ro_propinfo = { .get = get_css_devid, }; -SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp) +SubchDev *css_create_sch(CssDevId bus_id, bool is_virtual, bool squash_mcss, + Error **errp) { uint16_t schid = 0; SubchDev *sch; if (bus_id.valid) { - /* Enforce use of virtual cssid. */ - if (bus_id.cssid != VIRTUAL_CSSID) { - error_setg(errp, "cssid %hhx not valid for virtual devices", - bus_id.cssid); + if (is_virtual != (bus_id.cssid == VIRTUAL_CSSID)) { + error_setg(errp, "cssid %hhx not valid for %s devices", + bus_id.cssid, + (is_virtual ? "virtual" : "non-virtual")); return NULL; } + } + + if (bus_id.valid) { + if (squash_mcss) { + bus_id.cssid = channel_subsys.default_cssid; + } else if (!channel_subsys.css[bus_id.cssid]) { + css_create_css_image(bus_id.cssid, false); + } + if (!css_find_free_subch_for_devno(bus_id.cssid, bus_id.ssid, bus_id.devid, &schid, errp)) { return NULL; } - } else { - bus_id.cssid = VIRTUAL_CSSID; + } else if (squash_mcss || is_virtual) { + bus_id.cssid = channel_subsys.default_cssid; + if (!css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, &bus_id.devid, &schid, errp)) { return NULL; } + } else { + for (bus_id.cssid = 0; bus_id.cssid < MAX_CSSID; ++bus_id.cssid) { + if (bus_id.cssid == VIRTUAL_CSSID) { + continue; + } + + if (!channel_subsys.css[bus_id.cssid]) { + css_create_css_image(bus_id.cssid, false); + } + + if (css_find_free_subch_and_devno(bus_id.cssid, &bus_id.ssid, + &bus_id.devid, &schid, + NULL)) { + break; + } + if (bus_id.cssid == MAX_CSSID) { + error_setg(errp, "Virtual channel subsystem is full!"); + return NULL; + } + } } sch = g_malloc0(sizeof(*sch)); @@ -1978,3 +2088,147 @@ SubchDev *css_create_virtual_sch(CssDevId bus_id, Error **errp) css_subch_assign(sch->cssid, sch->ssid, schid, sch->devno, sch); return sch; } + +static int css_sch_get_chpids(SubchDev *sch, CssDevId *dev_id) +{ + char *fid_path; + FILE *fd; + uint32_t chpid[8]; + int i; + PMCW *p = &sch->curr_status.pmcw; + + fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/chpids", + dev_id->cssid, dev_id->ssid, dev_id->devid); + fd = fopen(fid_path, "r"); + if (fd == NULL) { + error_report("%s: open %s failed", __func__, fid_path); + g_free(fid_path); + return -EINVAL; + } + + if (fscanf(fd, "%x %x %x %x %x %x %x %x", + &chpid[0], &chpid[1], &chpid[2], &chpid[3], + &chpid[4], &chpid[5], &chpid[6], &chpid[7]) != 8) { + fclose(fd); + g_free(fid_path); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(p->chpid); i++) { + p->chpid[i] = chpid[i]; + } + + fclose(fd); + g_free(fid_path); + + return 0; +} + +static int css_sch_get_path_masks(SubchDev *sch, CssDevId *dev_id) +{ + char *fid_path; + FILE *fd; + uint32_t pim, pam, pom; + PMCW *p = &sch->curr_status.pmcw; + + fid_path = g_strdup_printf("/sys/bus/css/devices/%x.%x.%04x/pimpampom", + dev_id->cssid, dev_id->ssid, dev_id->devid); + fd = fopen(fid_path, "r"); + if (fd == NULL) { + error_report("%s: open %s failed", __func__, fid_path); + g_free(fid_path); + return -EINVAL; + } + + if (fscanf(fd, "%x %x %x", &pim, &pam, &pom) != 3) { + fclose(fd); + g_free(fid_path); + return -EINVAL; + } + + p->pim = pim; + p->pam = pam; + p->pom = pom; + fclose(fd); + g_free(fid_path); + + return 0; +} + +static int css_sch_get_chpid_type(uint8_t chpid, uint32_t *type, + CssDevId *dev_id) +{ + char *fid_path; + FILE *fd; + + fid_path = g_strdup_printf("/sys/devices/css%x/chp0.%02x/type", + dev_id->cssid, chpid); + fd = fopen(fid_path, "r"); + if (fd == NULL) { + error_report("%s: open %s failed", __func__, fid_path); + g_free(fid_path); + return -EINVAL; + } + + if (fscanf(fd, "%x", type) != 1) { + fclose(fd); + g_free(fid_path); + return -EINVAL; + } + + fclose(fd); + g_free(fid_path); + + return 0; +} + +/* + * We currently retrieve the real device information from sysfs to build the + * guest subchannel information block without considering the migration feature. + * We need to revisit this problem when we want to add migration support. + */ +int css_sch_build_schib(SubchDev *sch, CssDevId *dev_id) +{ + CssImage *css = channel_subsys.css[sch->cssid]; + PMCW *p = &sch->curr_status.pmcw; + SCSW *s = &sch->curr_status.scsw; + uint32_t type; + int i, ret; + + assert(css != NULL); + memset(p, 0, sizeof(PMCW)); + p->flags |= PMCW_FLAGS_MASK_DNV; + /* We are dealing with I/O subchannels only. */ + p->devno = sch->devno; + + /* Grab path mask from sysfs. */ + ret = css_sch_get_path_masks(sch, dev_id); + if (ret) { + return ret; + } + + /* Grab chpids from sysfs. */ + ret = css_sch_get_chpids(sch, dev_id); + if (ret) { + return ret; + } + + /* Build chpid type. */ + for (i = 0; i < ARRAY_SIZE(p->chpid); i++) { + if (p->chpid[i] && !css->chpids[p->chpid[i]].in_use) { + ret = css_sch_get_chpid_type(p->chpid[i], &type, dev_id); + if (ret) { + return ret; + } + css_add_chpid(sch->cssid, p->chpid[i], type, false); + } + } + + memset(s, 0, sizeof(SCSW)); + sch->curr_status.mba = 0; + for (i = 0; i < ARRAY_SIZE(sch->curr_status.mda); i++) { + sch->curr_status.mda[i] = 0; + } + + return 0; +} diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c index 75d3c681a4..4e6469db0f 100644 --- a/hw/s390x/ipl.c +++ b/hw/s390x/ipl.c @@ -396,7 +396,7 @@ void s390_reipl_request(void) S390IPLState *ipl = get_ipl_device(); ipl->reipl_requested = true; - qemu_system_reset_request(); + qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET); } void s390_ipl_prepare_cpu(S390CPU *cpu) diff --git a/hw/s390x/s390-ccw.c b/hw/s390x/s390-ccw.c new file mode 100644 index 0000000000..8614dda6f8 --- /dev/null +++ b/hw/s390x/s390-ccw.c @@ -0,0 +1,153 @@ +/* + * s390 CCW Assignment Support + * + * Copyright 2017 IBM Corp + * Author(s): Dong Jia Shi <bjsdjshi@linux.vnet.ibm.com> + * Xiao Feng Ren <renxiaof@linux.vnet.ibm.com> + * Pierre Morel <pmorel@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2 + * or (at your option) any later version. See the COPYING file in the + * top-level directory. + */ +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "hw/sysbus.h" +#include "libgen.h" +#include "hw/s390x/css.h" +#include "hw/s390x/css-bridge.h" +#include "hw/s390x/s390-ccw.h" + +int s390_ccw_cmd_request(ORB *orb, SCSW *scsw, void *data) +{ + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_GET_CLASS(data); + + if (cdc->handle_request) { + return cdc->handle_request(orb, scsw, data); + } else { + return -ENOSYS; + } +} + +static void s390_ccw_get_dev_info(S390CCWDevice *cdev, + char *sysfsdev, + Error **errp) +{ + unsigned int cssid, ssid, devid; + char dev_path[PATH_MAX] = {0}, *tmp; + + if (!sysfsdev) { + error_setg(errp, "No host device provided"); + error_append_hint(errp, + "Use -device vfio-ccw,sysfsdev=PATH_TO_DEVICE\n"); + return; + } + + if (!realpath(sysfsdev, dev_path)) { + error_setg_errno(errp, errno, "Host device '%s' not found", sysfsdev); + return; + } + + cdev->mdevid = g_strdup(basename(dev_path)); + + tmp = basename(dirname(dev_path)); + if (sscanf(tmp, "%2x.%1x.%4x", &cssid, &ssid, &devid) != 3) { + error_setg_errno(errp, errno, "Failed to read %s", tmp); + return; + } + + cdev->hostid.cssid = cssid; + cdev->hostid.ssid = ssid; + cdev->hostid.devid = devid; + cdev->hostid.valid = true; +} + +static void s390_ccw_realize(S390CCWDevice *cdev, char *sysfsdev, Error **errp) +{ + CcwDevice *ccw_dev = CCW_DEVICE(cdev); + CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev); + DeviceState *parent = DEVICE(ccw_dev); + BusState *qbus = qdev_get_parent_bus(parent); + VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); + SubchDev *sch; + int ret; + Error *err = NULL; + + s390_ccw_get_dev_info(cdev, sysfsdev, &err); + if (err) { + goto out_err_propagate; + } + + sch = css_create_sch(ccw_dev->devno, false, cbus->squash_mcss, &err); + if (!sch) { + goto out_mdevid_free; + } + sch->driver_data = cdev; + sch->do_subchannel_work = do_subchannel_work_passthrough; + + ccw_dev->sch = sch; + ret = css_sch_build_schib(sch, &cdev->hostid); + if (ret) { + error_setg_errno(&err, -ret, "%s: Failed to build initial schib", + __func__); + goto out_err; + } + + ck->realize(ccw_dev, &err); + if (err) { + goto out_err; + } + + css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, + parent->hotplugged, 1); + return; + +out_err: + css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); + ccw_dev->sch = NULL; + g_free(sch); +out_mdevid_free: + g_free(cdev->mdevid); +out_err_propagate: + error_propagate(errp, err); +} + +static void s390_ccw_unrealize(S390CCWDevice *cdev, Error **errp) +{ + CcwDevice *ccw_dev = CCW_DEVICE(cdev); + SubchDev *sch = ccw_dev->sch; + + if (sch) { + css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); + g_free(sch); + ccw_dev->sch = NULL; + } + + g_free(cdev->mdevid); +} + +static void s390_ccw_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + S390CCWDeviceClass *cdc = S390_CCW_DEVICE_CLASS(klass); + + dc->bus_type = TYPE_VIRTUAL_CSS_BUS; + cdc->realize = s390_ccw_realize; + cdc->unrealize = s390_ccw_unrealize; +} + +static const TypeInfo s390_ccw_info = { + .name = TYPE_S390_CCW, + .parent = TYPE_CCW_DEVICE, + .instance_size = sizeof(S390CCWDevice), + .class_size = sizeof(S390CCWDeviceClass), + .class_init = s390_ccw_class_init, + .abstract = true, +}; + +static void register_s390_ccw_type(void) +{ + type_register_static(&s390_ccw_info); +} + +type_init(register_s390_ccw_type) diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c index 66a6fbeb8c..5651483781 100644 --- a/hw/s390x/s390-pci-bus.c +++ b/hw/s390x/s390-pci-bus.c @@ -357,7 +357,7 @@ out: } static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *mr, hwaddr addr, - bool is_write) + IOMMUAccessFlags flag) { uint64_t pte; uint32_t flags; diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 314a9cbad4..8bc7c98682 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -624,7 +624,7 @@ int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) mr = &iommu->iommu_mr; while (start < end) { - entry = mr->iommu_ops->translate(mr, start, 0); + entry = mr->iommu_ops->translate(mr, start, IOMMU_NONE); if (!entry.translated_addr) { pbdev->state = ZPCI_FS_ERROR; diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c index fdd4384ff0..c9021f2fa9 100644 --- a/hw/s390x/s390-virtio-ccw.c +++ b/hw/s390x/s390-virtio-ccw.c @@ -136,10 +136,15 @@ static void ccw_init(MachineState *machine) kvm_s390_enable_css_support(s390_cpu_addr2state(0)); } /* - * Create virtual css and set it as default so that non mcss-e - * enabled guests only see virtio devices. + * Non mcss-e enabled guests only see the devices from the default + * css, which is determined by the value of the squash_mcss property. + * Note: we must not squash non virtual devices to css 0xFE. */ - ret = css_create_css_image(VIRTUAL_CSSID, true); + if (css_bus->squash_mcss) { + ret = css_create_css_image(0, true); + } else { + ret = css_create_css_image(VIRTUAL_CSSID, true); + } assert(ret == 0); /* Create VirtIO network adapters */ @@ -303,6 +308,20 @@ static void machine_set_loadparm(Object *obj, const char *val, Error **errp) ms->loadparm[i] = ' '; /* pad right with spaces */ } } +static inline bool machine_get_squash_mcss(Object *obj, Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + return ms->s390_squash_mcss; +} + +static inline void machine_set_squash_mcss(Object *obj, bool value, + Error **errp) +{ + S390CcwMachineState *ms = S390_CCW_MACHINE(obj); + + ms->s390_squash_mcss = value; +} static inline void s390_machine_initfn(Object *obj) { @@ -328,6 +347,13 @@ static inline void s390_machine_initfn(Object *obj) " to upper case) to pass to machine loader, boot manager," " and guest kernel", NULL); + object_property_add_bool(obj, "s390-squash-mcss", + machine_get_squash_mcss, + machine_set_squash_mcss, NULL); + object_property_set_description(obj, "s390-squash-mcss", + "enable/disable squashing subchannels into the default css", + NULL); + object_property_set_bool(obj, false, "s390-squash-mcss", NULL); } static const TypeInfo ccw_machine_info = { diff --git a/hw/s390x/virtio-ccw.c b/hw/s390x/virtio-ccw.c index e7167e3d05..e6a6f74be3 100644 --- a/hw/s390x/virtio-ccw.c +++ b/hw/s390x/virtio-ccw.c @@ -680,9 +680,13 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); CcwDevice *ccw_dev = CCW_DEVICE(dev); CCWDeviceClass *ck = CCW_DEVICE_GET_CLASS(ccw_dev); - SubchDev *sch = css_create_virtual_sch(ccw_dev->devno, errp); + DeviceState *parent = DEVICE(ccw_dev); + BusState *qbus = qdev_get_parent_bus(parent); + VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus); + SubchDev *sch; Error *err = NULL; + sch = css_create_sch(ccw_dev->devno, true, cbus->squash_mcss, errp); if (!sch) { return; } @@ -697,6 +701,7 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) sch->disable_cb = virtio_sch_disable_cb; sch->id.reserved = 0xff; sch->id.cu_type = VIRTIO_CCW_CU_TYPE; + sch->do_subchannel_work = do_subchannel_work_virtual; ccw_dev->sch = sch; dev->indicators = NULL; dev->revision = -1; |