diff options
author | RajithaY <rajithax.yerrumsetty@intel.com> | 2017-04-25 03:31:15 -0700 |
---|---|---|
committer | Rajitha Yerrumchetty <rajithax.yerrumsetty@intel.com> | 2017-05-22 06:48:08 +0000 |
commit | bb756eebdac6fd24e8919e2c43f7d2c8c4091f59 (patch) | |
tree | ca11e03542edf2d8f631efeca5e1626d211107e3 /qemu/hw/s390x | |
parent | a14b48d18a9ed03ec191cf16b162206998a895ce (diff) |
Adding qemu as a submodule of KVMFORNFV
This Patch includes the changes to add qemu as a submodule to
kvmfornfv repo and make use of the updated latest qemu for the
execution of all testcase
Change-Id: I1280af507a857675c7f81d30c95255635667bdd7
Signed-off-by:RajithaY<rajithax.yerrumsetty@intel.com>
Diffstat (limited to 'qemu/hw/s390x')
-rw-r--r-- | qemu/hw/s390x/Makefile.objs | 13 | ||||
-rw-r--r-- | qemu/hw/s390x/css.c | 1646 | ||||
-rw-r--r-- | qemu/hw/s390x/css.h | 126 | ||||
-rw-r--r-- | qemu/hw/s390x/event-facility.c | 449 | ||||
-rw-r--r-- | qemu/hw/s390x/ipl.c | 298 | ||||
-rw-r--r-- | qemu/hw/s390x/ipl.h | 53 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-pci-bus.c | 621 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-pci-bus.h | 256 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-pci-inst.c | 846 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-pci-inst.h | 289 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-skeys-kvm.c | 76 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-skeys.c | 415 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-virtio-ccw.c | 381 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-virtio-hcall.c | 41 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-virtio.c | 210 | ||||
-rw-r--r-- | qemu/hw/s390x/s390-virtio.h | 32 | ||||
-rw-r--r-- | qemu/hw/s390x/sclp.c | 618 | ||||
-rw-r--r-- | qemu/hw/s390x/sclpcpu.c | 101 | ||||
-rw-r--r-- | qemu/hw/s390x/sclpquiesce.c | 143 | ||||
-rw-r--r-- | qemu/hw/s390x/virtio-ccw.c | 1928 | ||||
-rw-r--r-- | qemu/hw/s390x/virtio-ccw.h | 211 |
21 files changed, 0 insertions, 8753 deletions
diff --git a/qemu/hw/s390x/Makefile.objs b/qemu/hw/s390x/Makefile.objs deleted file mode 100644 index 220361782..000000000 --- a/qemu/hw/s390x/Makefile.objs +++ /dev/null @@ -1,13 +0,0 @@ -obj-y += s390-virtio.o -obj-y += s390-virtio-hcall.o -obj-y += sclp.o -obj-y += event-facility.o -obj-y += sclpquiesce.o -obj-y += sclpcpu.o -obj-y += ipl.o -obj-y += css.o -obj-y += s390-virtio-ccw.o -obj-y += virtio-ccw.o -obj-y += s390-pci-bus.o s390-pci-inst.o -obj-y += s390-skeys.o -obj-$(CONFIG_KVM) += s390-skeys-kvm.o diff --git a/qemu/hw/s390x/css.c b/qemu/hw/s390x/css.c deleted file mode 100644 index 3a1d91958..000000000 --- a/qemu/hw/s390x/css.c +++ /dev/null @@ -1,1646 +0,0 @@ -/* - * Channel subsystem base support. - * - * Copyright 2012 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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 <hw/qdev.h> -#include "qemu/bitops.h" -#include "exec/address-spaces.h" -#include "cpu.h" -#include "ioinst.h" -#include "css.h" -#include "trace.h" -#include "hw/s390x/s390_flic.h" - -typedef struct CrwContainer { - CRW crw; - QTAILQ_ENTRY(CrwContainer) sibling; -} CrwContainer; - -typedef struct ChpInfo { - uint8_t in_use; - uint8_t type; - uint8_t is_virtual; -} ChpInfo; - -typedef struct SubchSet { - SubchDev *sch[MAX_SCHID + 1]; - unsigned long schids_used[BITS_TO_LONGS(MAX_SCHID + 1)]; - unsigned long devnos_used[BITS_TO_LONGS(MAX_SCHID + 1)]; -} SubchSet; - -typedef struct CssImage { - SubchSet *sch_set[MAX_SSID + 1]; - ChpInfo chpids[MAX_CHPID + 1]; -} CssImage; - -typedef struct IoAdapter { - uint32_t id; - uint8_t type; - uint8_t isc; - QTAILQ_ENTRY(IoAdapter) sibling; -} IoAdapter; - -typedef struct ChannelSubSys { - QTAILQ_HEAD(, CrwContainer) pending_crws; - bool sei_pending; - bool do_crw_mchk; - bool crws_lost; - uint8_t max_cssid; - uint8_t max_ssid; - bool chnmon_active; - uint64_t chnmon_area; - CssImage *css[MAX_CSSID + 1]; - uint8_t default_cssid; - QTAILQ_HEAD(, IoAdapter) io_adapters; - QTAILQ_HEAD(, IndAddr) indicator_addresses; -} ChannelSubSys; - -static ChannelSubSys channel_subsys = { - .pending_crws = QTAILQ_HEAD_INITIALIZER(channel_subsys.pending_crws), - .do_crw_mchk = true, - .sei_pending = false, - .do_crw_mchk = true, - .crws_lost = false, - .chnmon_active = false, - .io_adapters = QTAILQ_HEAD_INITIALIZER(channel_subsys.io_adapters), - .indicator_addresses = - QTAILQ_HEAD_INITIALIZER(channel_subsys.indicator_addresses), -}; - -IndAddr *get_indicator(hwaddr ind_addr, int len) -{ - IndAddr *indicator; - - QTAILQ_FOREACH(indicator, &channel_subsys.indicator_addresses, sibling) { - if (indicator->addr == ind_addr) { - indicator->refcnt++; - return indicator; - } - } - indicator = g_new0(IndAddr, 1); - indicator->addr = ind_addr; - indicator->len = len; - indicator->refcnt = 1; - QTAILQ_INSERT_TAIL(&channel_subsys.indicator_addresses, - indicator, sibling); - return indicator; -} - -static int s390_io_adapter_map(AdapterInfo *adapter, uint64_t map_addr, - bool do_map) -{ - S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); - - return fsc->io_adapter_map(fs, adapter->adapter_id, map_addr, do_map); -} - -void release_indicator(AdapterInfo *adapter, IndAddr *indicator) -{ - assert(indicator->refcnt > 0); - indicator->refcnt--; - if (indicator->refcnt > 0) { - return; - } - QTAILQ_REMOVE(&channel_subsys.indicator_addresses, indicator, sibling); - if (indicator->map) { - s390_io_adapter_map(adapter, indicator->map, false); - } - g_free(indicator); -} - -int map_indicator(AdapterInfo *adapter, IndAddr *indicator) -{ - int ret; - - if (indicator->map) { - return 0; /* already mapped is not an error */ - } - indicator->map = indicator->addr; - ret = s390_io_adapter_map(adapter, indicator->map, true); - if ((ret != 0) && (ret != -ENOSYS)) { - goto out_err; - } - return 0; - -out_err: - indicator->map = 0; - return ret; -} - -int css_create_css_image(uint8_t cssid, bool default_image) -{ - trace_css_new_image(cssid, default_image ? "(default)" : ""); - if (cssid > MAX_CSSID) { - return -EINVAL; - } - if (channel_subsys.css[cssid]) { - return -EBUSY; - } - channel_subsys.css[cssid] = g_malloc0(sizeof(CssImage)); - if (default_image) { - channel_subsys.default_cssid = cssid; - } - return 0; -} - -int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap, - bool maskable, uint32_t *id) -{ - IoAdapter *adapter; - bool found = false; - int ret; - S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); - - *id = 0; - QTAILQ_FOREACH(adapter, &channel_subsys.io_adapters, sibling) { - if ((adapter->type == type) && (adapter->isc == isc)) { - *id = adapter->id; - found = true; - ret = 0; - break; - } - if (adapter->id >= *id) { - *id = adapter->id + 1; - } - } - if (found) { - goto out; - } - adapter = g_new0(IoAdapter, 1); - ret = fsc->register_io_adapter(fs, *id, isc, swap, maskable); - if (ret == 0) { - adapter->id = *id; - adapter->isc = isc; - adapter->type = type; - QTAILQ_INSERT_TAIL(&channel_subsys.io_adapters, adapter, sibling); - } else { - g_free(adapter); - fprintf(stderr, "Unexpected error %d when registering adapter %d\n", - ret, *id); - } -out: - return ret; -} - -uint16_t css_build_subchannel_id(SubchDev *sch) -{ - if (channel_subsys.max_cssid > 0) { - return (sch->cssid << 8) | (1 << 3) | (sch->ssid << 1) | 1; - } - return (sch->ssid << 1) | 1; -} - -static void css_inject_io_interrupt(SubchDev *sch) -{ - uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; - - trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, - sch->curr_status.pmcw.intparm, isc, ""); - s390_io_interrupt(css_build_subchannel_id(sch), - sch->schid, - sch->curr_status.pmcw.intparm, - isc << 27); -} - -void css_conditional_io_interrupt(SubchDev *sch) -{ - /* - * If the subchannel is not currently status pending, make it pending - * with alert status. - */ - if (!(sch->curr_status.scsw.ctrl & SCSW_STCTL_STATUS_PEND)) { - uint8_t isc = (sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ISC) >> 11; - - trace_css_io_interrupt(sch->cssid, sch->ssid, sch->schid, - sch->curr_status.pmcw.intparm, isc, - "(unsolicited)"); - sch->curr_status.scsw.ctrl &= ~SCSW_CTRL_MASK_STCTL; - sch->curr_status.scsw.ctrl |= - SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - /* Inject an I/O interrupt. */ - s390_io_interrupt(css_build_subchannel_id(sch), - sch->schid, - sch->curr_status.pmcw.intparm, - isc << 27); - } -} - -void css_adapter_interrupt(uint8_t isc) -{ - uint32_t io_int_word = (isc << 27) | IO_INT_WORD_AI; - - trace_css_adapter_interrupt(isc); - s390_io_interrupt(0, 0, 0, io_int_word); -} - -static void sch_handle_clear_func(SubchDev *sch) -{ - PMCW *p = &sch->curr_status.pmcw; - SCSW *s = &sch->curr_status.scsw; - int path; - - /* Path management: In our simple css, we always choose the only path. */ - path = 0x80; - - /* Reset values prior to 'issuing the clear signal'. */ - p->lpum = 0; - p->pom = 0xff; - s->flags &= ~SCSW_FLAGS_MASK_PNO; - - /* We always 'attempt to issue the clear signal', and we always succeed. */ - sch->channel_prog = 0x0; - sch->last_cmd_valid = false; - s->ctrl &= ~SCSW_ACTL_CLEAR_PEND; - s->ctrl |= SCSW_STCTL_STATUS_PEND; - - s->dstat = 0; - s->cstat = 0; - p->lpum = path; - -} - -static void sch_handle_halt_func(SubchDev *sch) -{ - - PMCW *p = &sch->curr_status.pmcw; - SCSW *s = &sch->curr_status.scsw; - hwaddr curr_ccw = sch->channel_prog; - int path; - - /* Path management: In our simple css, we always choose the only path. */ - path = 0x80; - - /* We always 'attempt to issue the halt signal', and we always succeed. */ - sch->channel_prog = 0x0; - sch->last_cmd_valid = false; - s->ctrl &= ~SCSW_ACTL_HALT_PEND; - s->ctrl |= SCSW_STCTL_STATUS_PEND; - - if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) || - !((s->ctrl & SCSW_ACTL_START_PEND) || - (s->ctrl & SCSW_ACTL_SUSP))) { - s->dstat = SCSW_DSTAT_DEVICE_END; - } - if ((s->ctrl & (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) || - (s->ctrl & SCSW_ACTL_SUSP)) { - s->cpa = curr_ccw + 8; - } - s->cstat = 0; - p->lpum = path; - -} - -static void copy_sense_id_to_guest(SenseId *dest, SenseId *src) -{ - int i; - - dest->reserved = src->reserved; - dest->cu_type = cpu_to_be16(src->cu_type); - dest->cu_model = src->cu_model; - dest->dev_type = cpu_to_be16(src->dev_type); - dest->dev_model = src->dev_model; - dest->unused = src->unused; - for (i = 0; i < ARRAY_SIZE(dest->ciw); i++) { - dest->ciw[i].type = src->ciw[i].type; - dest->ciw[i].command = src->ciw[i].command; - dest->ciw[i].count = cpu_to_be16(src->ciw[i].count); - } -} - -static CCW1 copy_ccw_from_guest(hwaddr addr, bool fmt1) -{ - CCW0 tmp0; - CCW1 tmp1; - CCW1 ret; - - if (fmt1) { - cpu_physical_memory_read(addr, &tmp1, sizeof(tmp1)); - ret.cmd_code = tmp1.cmd_code; - ret.flags = tmp1.flags; - ret.count = be16_to_cpu(tmp1.count); - ret.cda = be32_to_cpu(tmp1.cda); - } else { - cpu_physical_memory_read(addr, &tmp0, sizeof(tmp0)); - ret.cmd_code = tmp0.cmd_code; - ret.flags = tmp0.flags; - ret.count = be16_to_cpu(tmp0.count); - ret.cda = be16_to_cpu(tmp0.cda1) | (tmp0.cda0 << 16); - if ((ret.cmd_code & 0x0f) == CCW_CMD_TIC) { - ret.cmd_code &= 0x0f; - } - } - return ret; -} - -static int css_interpret_ccw(SubchDev *sch, hwaddr ccw_addr, - bool suspend_allowed) -{ - int ret; - bool check_len; - int len; - CCW1 ccw; - - if (!ccw_addr) { - return -EIO; - } - - /* Translate everything to format-1 ccws - the information is the same. */ - ccw = copy_ccw_from_guest(ccw_addr, sch->ccw_fmt_1); - - /* Check for invalid command codes. */ - if ((ccw.cmd_code & 0x0f) == 0) { - return -EINVAL; - } - if (((ccw.cmd_code & 0x0f) == CCW_CMD_TIC) && - ((ccw.cmd_code & 0xf0) != 0)) { - return -EINVAL; - } - if (!sch->ccw_fmt_1 && (ccw.count == 0) && - (ccw.cmd_code != CCW_CMD_TIC)) { - return -EINVAL; - } - - if (ccw.flags & CCW_FLAG_SUSPEND) { - return suspend_allowed ? -EINPROGRESS : -EINVAL; - } - - check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); - - if (!ccw.cda) { - if (sch->ccw_no_data_cnt == 255) { - return -EINVAL; - } - sch->ccw_no_data_cnt++; - } - - /* Look at the command. */ - switch (ccw.cmd_code) { - case CCW_CMD_NOOP: - /* Nothing to do. */ - ret = 0; - break; - case CCW_CMD_BASIC_SENSE: - if (check_len) { - if (ccw.count != sizeof(sch->sense_data)) { - ret = -EINVAL; - break; - } - } - len = MIN(ccw.count, sizeof(sch->sense_data)); - cpu_physical_memory_write(ccw.cda, sch->sense_data, len); - sch->curr_status.scsw.count = ccw.count - len; - memset(sch->sense_data, 0, sizeof(sch->sense_data)); - ret = 0; - break; - case CCW_CMD_SENSE_ID: - { - SenseId sense_id; - - copy_sense_id_to_guest(&sense_id, &sch->id); - /* Sense ID information is device specific. */ - if (check_len) { - if (ccw.count != sizeof(sense_id)) { - ret = -EINVAL; - break; - } - } - len = MIN(ccw.count, sizeof(sense_id)); - /* - * Only indicate 0xff in the first sense byte if we actually - * have enough place to store at least bytes 0-3. - */ - if (len >= 4) { - sense_id.reserved = 0xff; - } else { - sense_id.reserved = 0; - } - cpu_physical_memory_write(ccw.cda, &sense_id, len); - sch->curr_status.scsw.count = ccw.count - len; - ret = 0; - break; - } - case CCW_CMD_TIC: - if (sch->last_cmd_valid && (sch->last_cmd.cmd_code == CCW_CMD_TIC)) { - ret = -EINVAL; - break; - } - if (ccw.flags & (CCW_FLAG_CC | CCW_FLAG_DC)) { - ret = -EINVAL; - break; - } - sch->channel_prog = ccw.cda; - ret = -EAGAIN; - break; - default: - if (sch->ccw_cb) { - /* Handle device specific commands. */ - ret = sch->ccw_cb(sch, ccw); - } else { - ret = -ENOSYS; - } - break; - } - sch->last_cmd = ccw; - sch->last_cmd_valid = true; - if (ret == 0) { - if (ccw.flags & CCW_FLAG_CC) { - sch->channel_prog += 8; - ret = -EAGAIN; - } - } - - return ret; -} - -static void sch_handle_start_func(SubchDev *sch, ORB *orb) -{ - - PMCW *p = &sch->curr_status.pmcw; - SCSW *s = &sch->curr_status.scsw; - int path; - int ret; - bool suspend_allowed; - - /* Path management: In our simple css, we always choose the only path. */ - path = 0x80; - - if (!(s->ctrl & SCSW_ACTL_SUSP)) { - s->cstat = 0; - s->dstat = 0; - /* Look at the orb and try to execute the channel program. */ - assert(orb != NULL); /* resume does not pass an orb */ - p->intparm = orb->intparm; - if (!(orb->lpm & path)) { - /* Generate a deferred cc 3 condition. */ - s->flags |= SCSW_FLAGS_MASK_CC; - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= (SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND); - return; - } - sch->ccw_fmt_1 = !!(orb->ctrl0 & ORB_CTRL0_MASK_FMT); - sch->ccw_no_data_cnt = 0; - suspend_allowed = !!(orb->ctrl0 & ORB_CTRL0_MASK_SPND); - } else { - s->ctrl &= ~(SCSW_ACTL_SUSP | SCSW_ACTL_RESUME_PEND); - /* The channel program had been suspended before. */ - suspend_allowed = true; - } - sch->last_cmd_valid = false; - do { - ret = css_interpret_ccw(sch, sch->channel_prog, suspend_allowed); - switch (ret) { - case -EAGAIN: - /* ccw chain, continue processing */ - break; - case 0: - /* success */ - s->ctrl &= ~SCSW_ACTL_START_PEND; - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | - SCSW_STCTL_STATUS_PEND; - s->dstat = SCSW_DSTAT_CHANNEL_END | SCSW_DSTAT_DEVICE_END; - s->cpa = sch->channel_prog + 8; - break; - case -ENOSYS: - /* unsupported command, generate unit check (command reject) */ - s->ctrl &= ~SCSW_ACTL_START_PEND; - s->dstat = SCSW_DSTAT_UNIT_CHECK; - /* Set sense bit 0 in ecw0. */ - sch->sense_data[0] = 0x80; - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | - SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - s->cpa = sch->channel_prog + 8; - break; - case -EFAULT: - /* memory problem, generate channel data check */ - s->ctrl &= ~SCSW_ACTL_START_PEND; - s->cstat = SCSW_CSTAT_DATA_CHECK; - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | - SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - s->cpa = sch->channel_prog + 8; - break; - case -EBUSY: - /* subchannel busy, generate deferred cc 1 */ - s->flags &= ~SCSW_FLAGS_MASK_CC; - s->flags |= (1 << 8); - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - break; - case -EINPROGRESS: - /* channel program has been suspended */ - s->ctrl &= ~SCSW_ACTL_START_PEND; - s->ctrl |= SCSW_ACTL_SUSP; - break; - default: - /* error, generate channel program check */ - s->ctrl &= ~SCSW_ACTL_START_PEND; - s->cstat = SCSW_CSTAT_PROG_CHECK; - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - s->ctrl |= SCSW_STCTL_PRIMARY | SCSW_STCTL_SECONDARY | - SCSW_STCTL_ALERT | SCSW_STCTL_STATUS_PEND; - s->cpa = sch->channel_prog + 8; - break; - } - } while (ret == -EAGAIN); - -} - -/* - * 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) -{ - - SCSW *s = &sch->curr_status.scsw; - - if (s->ctrl & SCSW_FCTL_CLEAR_FUNC) { - sch_handle_clear_func(sch); - } else if (s->ctrl & SCSW_FCTL_HALT_FUNC) { - sch_handle_halt_func(sch); - } else if (s->ctrl & SCSW_FCTL_START_FUNC) { - sch_handle_start_func(sch, orb); - } else { - /* Cannot happen. */ - return; - } - css_inject_io_interrupt(sch); -} - -static void copy_pmcw_to_guest(PMCW *dest, const PMCW *src) -{ - int i; - - dest->intparm = cpu_to_be32(src->intparm); - dest->flags = cpu_to_be16(src->flags); - dest->devno = cpu_to_be16(src->devno); - dest->lpm = src->lpm; - dest->pnom = src->pnom; - dest->lpum = src->lpum; - dest->pim = src->pim; - dest->mbi = cpu_to_be16(src->mbi); - dest->pom = src->pom; - dest->pam = src->pam; - for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) { - dest->chpid[i] = src->chpid[i]; - } - dest->chars = cpu_to_be32(src->chars); -} - -static void copy_scsw_to_guest(SCSW *dest, const SCSW *src) -{ - dest->flags = cpu_to_be16(src->flags); - dest->ctrl = cpu_to_be16(src->ctrl); - dest->cpa = cpu_to_be32(src->cpa); - dest->dstat = src->dstat; - dest->cstat = src->cstat; - dest->count = cpu_to_be16(src->count); -} - -static void copy_schib_to_guest(SCHIB *dest, const SCHIB *src) -{ - int i; - - copy_pmcw_to_guest(&dest->pmcw, &src->pmcw); - copy_scsw_to_guest(&dest->scsw, &src->scsw); - dest->mba = cpu_to_be64(src->mba); - for (i = 0; i < ARRAY_SIZE(dest->mda); i++) { - dest->mda[i] = src->mda[i]; - } -} - -int css_do_stsch(SubchDev *sch, SCHIB *schib) -{ - /* Use current status. */ - copy_schib_to_guest(schib, &sch->curr_status); - return 0; -} - -static void copy_pmcw_from_guest(PMCW *dest, const PMCW *src) -{ - int i; - - dest->intparm = be32_to_cpu(src->intparm); - dest->flags = be16_to_cpu(src->flags); - dest->devno = be16_to_cpu(src->devno); - dest->lpm = src->lpm; - dest->pnom = src->pnom; - dest->lpum = src->lpum; - dest->pim = src->pim; - dest->mbi = be16_to_cpu(src->mbi); - dest->pom = src->pom; - dest->pam = src->pam; - for (i = 0; i < ARRAY_SIZE(dest->chpid); i++) { - dest->chpid[i] = src->chpid[i]; - } - dest->chars = be32_to_cpu(src->chars); -} - -static void copy_scsw_from_guest(SCSW *dest, const SCSW *src) -{ - dest->flags = be16_to_cpu(src->flags); - dest->ctrl = be16_to_cpu(src->ctrl); - dest->cpa = be32_to_cpu(src->cpa); - dest->dstat = src->dstat; - dest->cstat = src->cstat; - dest->count = be16_to_cpu(src->count); -} - -static void copy_schib_from_guest(SCHIB *dest, const SCHIB *src) -{ - int i; - - copy_pmcw_from_guest(&dest->pmcw, &src->pmcw); - copy_scsw_from_guest(&dest->scsw, &src->scsw); - dest->mba = be64_to_cpu(src->mba); - for (i = 0; i < ARRAY_SIZE(dest->mda); i++) { - dest->mda[i] = src->mda[i]; - } -} - -int 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; - } - - if (s->ctrl & SCSW_STCTL_STATUS_PEND) { - ret = -EINPROGRESS; - goto out; - } - - if (s->ctrl & - (SCSW_FCTL_START_FUNC|SCSW_FCTL_HALT_FUNC|SCSW_FCTL_CLEAR_FUNC)) { - ret = -EBUSY; - goto out; - } - - copy_schib_from_guest(&schib, orig_schib); - /* Only update the program-modifiable fields. */ - p->intparm = schib.pmcw.intparm; - oldflags = p->flags; - p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | - PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | - PMCW_FLAGS_MASK_MP); - p->flags |= schib.pmcw.flags & - (PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | - PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | - PMCW_FLAGS_MASK_MP); - p->lpm = schib.pmcw.lpm; - p->mbi = schib.pmcw.mbi; - p->pom = schib.pmcw.pom; - p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE); - p->chars |= schib.pmcw.chars & - (PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_CSENSE); - sch->curr_status.mba = schib.mba; - - /* Has the channel been disabled? */ - if (sch->disable_cb && (oldflags & PMCW_FLAGS_MASK_ENA) != 0 - && (p->flags & PMCW_FLAGS_MASK_ENA) == 0) { - sch->disable_cb(sch); - } - - ret = 0; - -out: - return ret; -} - -int 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; - } - - if (!(s->ctrl & SCSW_CTRL_MASK_FCTL) || - ((s->ctrl & SCSW_CTRL_MASK_FCTL) != SCSW_FCTL_START_FUNC) || - (!(s->ctrl & - (SCSW_ACTL_RESUME_PEND | SCSW_ACTL_START_PEND | SCSW_ACTL_SUSP))) || - (s->ctrl & SCSW_ACTL_SUBCH_ACTIVE)) { - ret = -EINPROGRESS; - goto out; - } - - if (s->ctrl & SCSW_CTRL_MASK_STCTL) { - ret = -EBUSY; - goto out; - } - - /* Cancel the current operation. */ - s->ctrl &= ~(SCSW_FCTL_START_FUNC | - SCSW_ACTL_RESUME_PEND | - SCSW_ACTL_START_PEND | - SCSW_ACTL_SUSP); - sch->channel_prog = 0x0; - sch->last_cmd_valid = false; - s->dstat = 0; - s->cstat = 0; - ret = 0; - -out: - return ret; -} - -int 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; - } - - /* 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, NULL); - ret = 0; - -out: - return ret; -} - -int 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; - } - - 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; - } - - if (s->ctrl & (SCSW_FCTL_HALT_FUNC | SCSW_FCTL_CLEAR_FUNC)) { - ret = -EBUSY; - goto out; - } - - /* Trigger the halt function. */ - s->ctrl |= SCSW_FCTL_HALT_FUNC; - s->ctrl &= ~SCSW_FCTL_START_FUNC; - if (((s->ctrl & SCSW_CTRL_MASK_ACTL) == - (SCSW_ACTL_SUBCH_ACTIVE | SCSW_ACTL_DEVICE_ACTIVE)) && - ((s->ctrl & SCSW_CTRL_MASK_STCTL) == SCSW_STCTL_INTERMEDIATE)) { - s->ctrl &= ~SCSW_STCTL_STATUS_PEND; - } - s->ctrl |= SCSW_ACTL_HALT_PEND; - - do_subchannel_work(sch, NULL); - ret = 0; - -out: - return ret; -} - -static void css_update_chnmon(SubchDev *sch) -{ - if (!(sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_MME)) { - /* Not active. */ - return; - } - /* The counter is conveniently located at the beginning of the struct. */ - if (sch->curr_status.pmcw.chars & PMCW_CHARS_MASK_MBFC) { - /* Format 1, per-subchannel area. */ - uint32_t count; - - count = address_space_ldl(&address_space_memory, - sch->curr_status.mba, - MEMTXATTRS_UNSPECIFIED, - NULL); - count++; - address_space_stl(&address_space_memory, sch->curr_status.mba, count, - MEMTXATTRS_UNSPECIFIED, NULL); - } else { - /* Format 0, global area. */ - uint32_t offset; - uint16_t count; - - offset = sch->curr_status.pmcw.mbi << 5; - count = address_space_lduw(&address_space_memory, - channel_subsys.chnmon_area + offset, - MEMTXATTRS_UNSPECIFIED, - NULL); - count++; - address_space_stw(&address_space_memory, - channel_subsys.chnmon_area + offset, count, - MEMTXATTRS_UNSPECIFIED, NULL); - } -} - -int 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; - } - - if (s->ctrl & SCSW_STCTL_STATUS_PEND) { - ret = -EINPROGRESS; - goto out; - } - - if (s->ctrl & (SCSW_FCTL_START_FUNC | - SCSW_FCTL_HALT_FUNC | - SCSW_FCTL_CLEAR_FUNC)) { - ret = -EBUSY; - goto out; - } - - /* If monitoring is active, update counter. */ - if (channel_subsys.chnmon_active) { - css_update_chnmon(sch); - } - sch->channel_prog = orb->cpa; - /* Trigger the start function. */ - s->ctrl |= (SCSW_FCTL_START_FUNC | SCSW_ACTL_START_PEND); - s->flags &= ~SCSW_FLAGS_MASK_PNO; - - do_subchannel_work(sch, orb); - ret = 0; - -out: - return ret; -} - -static void copy_irb_to_guest(IRB *dest, const IRB *src, PMCW *pmcw, - int *irb_len) -{ - int i; - uint16_t stctl = src->scsw.ctrl & SCSW_CTRL_MASK_STCTL; - uint16_t actl = src->scsw.ctrl & SCSW_CTRL_MASK_ACTL; - - copy_scsw_to_guest(&dest->scsw, &src->scsw); - - for (i = 0; i < ARRAY_SIZE(dest->esw); i++) { - dest->esw[i] = cpu_to_be32(src->esw[i]); - } - for (i = 0; i < ARRAY_SIZE(dest->ecw); i++) { - dest->ecw[i] = cpu_to_be32(src->ecw[i]); - } - *irb_len = sizeof(*dest) - sizeof(dest->emw); - - /* extended measurements enabled? */ - if ((src->scsw.flags & SCSW_FLAGS_MASK_ESWF) || - !(pmcw->flags & PMCW_FLAGS_MASK_TF) || - !(pmcw->chars & PMCW_CHARS_MASK_XMWME)) { - return; - } - /* extended measurements pending? */ - if (!(stctl & SCSW_STCTL_STATUS_PEND)) { - return; - } - if ((stctl & SCSW_STCTL_PRIMARY) || - (stctl == SCSW_STCTL_SECONDARY) || - ((stctl & SCSW_STCTL_INTERMEDIATE) && (actl & SCSW_ACTL_SUSP))) { - for (i = 0; i < ARRAY_SIZE(dest->emw); i++) { - dest->emw[i] = cpu_to_be32(src->emw[i]); - } - } - *irb_len = sizeof(*dest); -} - -int css_do_tsch_get_irb(SubchDev *sch, IRB *target_irb, int *irb_len) -{ - SCSW *s = &sch->curr_status.scsw; - PMCW *p = &sch->curr_status.pmcw; - uint16_t stctl; - IRB irb; - - if (!(p->flags & (PMCW_FLAGS_MASK_DNV | PMCW_FLAGS_MASK_ENA))) { - return 3; - } - - stctl = s->ctrl & SCSW_CTRL_MASK_STCTL; - - /* Prepare the irb for the guest. */ - memset(&irb, 0, sizeof(IRB)); - - /* Copy scsw from current status. */ - memcpy(&irb.scsw, s, sizeof(SCSW)); - if (stctl & SCSW_STCTL_STATUS_PEND) { - if (s->cstat & (SCSW_CSTAT_DATA_CHECK | - SCSW_CSTAT_CHN_CTRL_CHK | - SCSW_CSTAT_INTF_CTRL_CHK)) { - irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF; - irb.esw[0] = 0x04804000; - } else { - irb.esw[0] = 0x00800000; - } - /* If a unit check is pending, copy sense data. */ - if ((s->dstat & SCSW_DSTAT_UNIT_CHECK) && - (p->chars & PMCW_CHARS_MASK_CSENSE)) { - int i; - - irb.scsw.flags |= SCSW_FLAGS_MASK_ESWF | SCSW_FLAGS_MASK_ECTL; - /* Attention: sense_data is already BE! */ - memcpy(irb.ecw, sch->sense_data, sizeof(sch->sense_data)); - for (i = 0; i < ARRAY_SIZE(irb.ecw); i++) { - irb.ecw[i] = be32_to_cpu(irb.ecw[i]); - } - irb.esw[1] = 0x01000000 | (sizeof(sch->sense_data) << 8); - } - } - /* Store the irb to the guest. */ - copy_irb_to_guest(target_irb, &irb, p, irb_len); - - return ((stctl & SCSW_STCTL_STATUS_PEND) == 0); -} - -void css_do_tsch_update_subch(SubchDev *sch) -{ - SCSW *s = &sch->curr_status.scsw; - PMCW *p = &sch->curr_status.pmcw; - uint16_t stctl; - uint16_t fctl; - uint16_t actl; - - stctl = s->ctrl & SCSW_CTRL_MASK_STCTL; - fctl = s->ctrl & SCSW_CTRL_MASK_FCTL; - actl = s->ctrl & SCSW_CTRL_MASK_ACTL; - - /* Clear conditions on subchannel, if applicable. */ - if (stctl & SCSW_STCTL_STATUS_PEND) { - s->ctrl &= ~SCSW_CTRL_MASK_STCTL; - if ((stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) || - ((fctl & SCSW_FCTL_HALT_FUNC) && - (actl & SCSW_ACTL_SUSP))) { - s->ctrl &= ~SCSW_CTRL_MASK_FCTL; - } - if (stctl != (SCSW_STCTL_INTERMEDIATE | SCSW_STCTL_STATUS_PEND)) { - s->flags &= ~SCSW_FLAGS_MASK_PNO; - s->ctrl &= ~(SCSW_ACTL_RESUME_PEND | - SCSW_ACTL_START_PEND | - SCSW_ACTL_HALT_PEND | - SCSW_ACTL_CLEAR_PEND | - SCSW_ACTL_SUSP); - } else { - if ((actl & SCSW_ACTL_SUSP) && - (fctl & SCSW_FCTL_START_FUNC)) { - s->flags &= ~SCSW_FLAGS_MASK_PNO; - if (fctl & SCSW_FCTL_HALT_FUNC) { - s->ctrl &= ~(SCSW_ACTL_RESUME_PEND | - SCSW_ACTL_START_PEND | - SCSW_ACTL_HALT_PEND | - SCSW_ACTL_CLEAR_PEND | - SCSW_ACTL_SUSP); - } else { - s->ctrl &= ~SCSW_ACTL_RESUME_PEND; - } - } - } - /* Clear pending sense data. */ - if (p->chars & PMCW_CHARS_MASK_CSENSE) { - memset(sch->sense_data, 0 , sizeof(sch->sense_data)); - } - } -} - -static void copy_crw_to_guest(CRW *dest, const CRW *src) -{ - dest->flags = cpu_to_be16(src->flags); - dest->rsid = cpu_to_be16(src->rsid); -} - -int css_do_stcrw(CRW *crw) -{ - CrwContainer *crw_cont; - int ret; - - crw_cont = QTAILQ_FIRST(&channel_subsys.pending_crws); - if (crw_cont) { - QTAILQ_REMOVE(&channel_subsys.pending_crws, crw_cont, sibling); - copy_crw_to_guest(crw, &crw_cont->crw); - g_free(crw_cont); - ret = 0; - } else { - /* List was empty, turn crw machine checks on again. */ - memset(crw, 0, sizeof(*crw)); - channel_subsys.do_crw_mchk = true; - ret = 1; - } - - return ret; -} - -static void copy_crw_from_guest(CRW *dest, const CRW *src) -{ - dest->flags = be16_to_cpu(src->flags); - dest->rsid = be16_to_cpu(src->rsid); -} - -void css_undo_stcrw(CRW *crw) -{ - CrwContainer *crw_cont; - - crw_cont = g_try_malloc0(sizeof(CrwContainer)); - if (!crw_cont) { - channel_subsys.crws_lost = true; - return; - } - copy_crw_from_guest(&crw_cont->crw, crw); - - QTAILQ_INSERT_HEAD(&channel_subsys.pending_crws, crw_cont, sibling); -} - -int css_do_tpi(IOIntCode *int_code, int lowcore) -{ - /* No pending interrupts for !KVM. */ - return 0; - } - -int css_collect_chp_desc(int m, uint8_t cssid, uint8_t f_chpid, uint8_t l_chpid, - int rfmt, void *buf) -{ - int i, desc_size; - uint32_t words[8]; - uint32_t chpid_type_word; - CssImage *css; - - if (!m && !cssid) { - css = channel_subsys.css[channel_subsys.default_cssid]; - } else { - css = channel_subsys.css[cssid]; - } - if (!css) { - return 0; - } - desc_size = 0; - for (i = f_chpid; i <= l_chpid; i++) { - if (css->chpids[i].in_use) { - chpid_type_word = 0x80000000 | (css->chpids[i].type << 8) | i; - if (rfmt == 0) { - words[0] = cpu_to_be32(chpid_type_word); - words[1] = 0; - memcpy(buf + desc_size, words, 8); - desc_size += 8; - } else if (rfmt == 1) { - words[0] = cpu_to_be32(chpid_type_word); - words[1] = 0; - words[2] = 0; - words[3] = 0; - words[4] = 0; - words[5] = 0; - words[6] = 0; - words[7] = 0; - memcpy(buf + desc_size, words, 32); - desc_size += 32; - } - } - } - return desc_size; -} - -void css_do_schm(uint8_t mbk, int update, int dct, uint64_t mbo) -{ - /* dct is currently ignored (not really meaningful for our devices) */ - /* TODO: Don't ignore mbk. */ - if (update && !channel_subsys.chnmon_active) { - /* Enable measuring. */ - channel_subsys.chnmon_area = mbo; - channel_subsys.chnmon_active = true; - } - if (!update && channel_subsys.chnmon_active) { - /* Disable measuring. */ - channel_subsys.chnmon_area = 0; - channel_subsys.chnmon_active = false; - } -} - -int 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; - } - - if (s->ctrl & SCSW_STCTL_STATUS_PEND) { - ret = -EINPROGRESS; - goto out; - } - - 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; - } - - /* If monitoring is active, update counter. */ - if (channel_subsys.chnmon_active) { - css_update_chnmon(sch); - } - - s->ctrl |= SCSW_ACTL_RESUME_PEND; - do_subchannel_work(sch, NULL); - ret = 0; - -out: - return ret; -} - -int css_do_rchp(uint8_t cssid, uint8_t chpid) -{ - uint8_t real_cssid; - - if (cssid > channel_subsys.max_cssid) { - return -EINVAL; - } - if (channel_subsys.max_cssid == 0) { - real_cssid = channel_subsys.default_cssid; - } else { - real_cssid = cssid; - } - if (!channel_subsys.css[real_cssid]) { - return -EINVAL; - } - - if (!channel_subsys.css[real_cssid]->chpids[chpid].in_use) { - return -ENODEV; - } - - if (!channel_subsys.css[real_cssid]->chpids[chpid].is_virtual) { - fprintf(stderr, - "rchp unsupported for non-virtual chpid %x.%02x!\n", - real_cssid, chpid); - return -ENODEV; - } - - /* We don't really use a channel path, so we're done here. */ - css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, - channel_subsys.max_cssid > 0 ? 1 : 0, chpid); - if (channel_subsys.max_cssid > 0) { - css_queue_crw(CRW_RSC_CHP, CRW_ERC_INIT, 0, real_cssid << 8); - } - return 0; -} - -bool css_schid_final(int m, uint8_t cssid, uint8_t ssid, uint16_t schid) -{ - SubchSet *set; - uint8_t real_cssid; - - real_cssid = (!m && (cssid == 0)) ? channel_subsys.default_cssid : cssid; - if (real_cssid > MAX_CSSID || ssid > MAX_SSID || - !channel_subsys.css[real_cssid] || - !channel_subsys.css[real_cssid]->sch_set[ssid]) { - return true; - } - set = channel_subsys.css[real_cssid]->sch_set[ssid]; - return schid > find_last_bit(set->schids_used, - (MAX_SCHID + 1) / sizeof(unsigned long)); -} - -static int css_add_virtual_chpid(uint8_t cssid, uint8_t chpid, uint8_t type) -{ - CssImage *css; - - trace_css_chpid_add(cssid, chpid, type); - if (cssid > MAX_CSSID) { - return -EINVAL; - } - css = channel_subsys.css[cssid]; - if (!css) { - return -EINVAL; - } - if (css->chpids[chpid].in_use) { - return -EEXIST; - } - css->chpids[chpid].in_use = 1; - css->chpids[chpid].type = type; - css->chpids[chpid].is_virtual = 1; - - css_generate_chp_crws(cssid, chpid); - - return 0; -} - -void css_sch_build_virtual_schib(SubchDev *sch, uint8_t chpid, uint8_t type) -{ - PMCW *p = &sch->curr_status.pmcw; - SCSW *s = &sch->curr_status.scsw; - int i; - CssImage *css = channel_subsys.css[sch->cssid]; - - assert(css != NULL); - memset(p, 0, sizeof(PMCW)); - p->flags |= PMCW_FLAGS_MASK_DNV; - p->devno = sch->devno; - /* single path */ - p->pim = 0x80; - p->pom = 0xff; - p->pam = 0x80; - p->chpid[0] = chpid; - if (!css->chpids[chpid].in_use) { - css_add_virtual_chpid(sch->cssid, chpid, type); - } - - 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; - } -} - -SubchDev *css_find_subch(uint8_t m, uint8_t cssid, uint8_t ssid, uint16_t schid) -{ - uint8_t real_cssid; - - real_cssid = (!m && (cssid == 0)) ? channel_subsys.default_cssid : cssid; - - if (!channel_subsys.css[real_cssid]) { - return NULL; - } - - if (!channel_subsys.css[real_cssid]->sch_set[ssid]) { - return NULL; - } - - return channel_subsys.css[real_cssid]->sch_set[ssid]->sch[schid]; -} - -bool css_subch_visible(SubchDev *sch) -{ - if (sch->ssid > channel_subsys.max_ssid) { - return false; - } - - if (sch->cssid != channel_subsys.default_cssid) { - return (channel_subsys.max_cssid > 0); - } - - return true; -} - -bool css_present(uint8_t cssid) -{ - return (channel_subsys.css[cssid] != NULL); -} - -bool css_devno_used(uint8_t cssid, uint8_t ssid, uint16_t devno) -{ - if (!channel_subsys.css[cssid]) { - return false; - } - if (!channel_subsys.css[cssid]->sch_set[ssid]) { - return false; - } - - return !!test_bit(devno, - channel_subsys.css[cssid]->sch_set[ssid]->devnos_used); -} - -void css_subch_assign(uint8_t cssid, uint8_t ssid, uint16_t schid, - uint16_t devno, SubchDev *sch) -{ - CssImage *css; - SubchSet *s_set; - - trace_css_assign_subch(sch ? "assign" : "deassign", cssid, ssid, schid, - devno); - if (!channel_subsys.css[cssid]) { - fprintf(stderr, - "Suspicious call to %s (%x.%x.%04x) for non-existing css!\n", - __func__, cssid, ssid, schid); - return; - } - css = channel_subsys.css[cssid]; - - if (!css->sch_set[ssid]) { - css->sch_set[ssid] = g_malloc0(sizeof(SubchSet)); - } - s_set = css->sch_set[ssid]; - - s_set->sch[schid] = sch; - if (sch) { - set_bit(schid, s_set->schids_used); - set_bit(devno, s_set->devnos_used); - } else { - clear_bit(schid, s_set->schids_used); - clear_bit(devno, s_set->devnos_used); - } -} - -void css_queue_crw(uint8_t rsc, uint8_t erc, int chain, uint16_t rsid) -{ - CrwContainer *crw_cont; - - trace_css_crw(rsc, erc, rsid, chain ? "(chained)" : ""); - /* TODO: Maybe use a static crw pool? */ - crw_cont = g_try_malloc0(sizeof(CrwContainer)); - if (!crw_cont) { - channel_subsys.crws_lost = true; - return; - } - crw_cont->crw.flags = (rsc << 8) | erc; - if (chain) { - crw_cont->crw.flags |= CRW_FLAGS_MASK_C; - } - crw_cont->crw.rsid = rsid; - if (channel_subsys.crws_lost) { - crw_cont->crw.flags |= CRW_FLAGS_MASK_R; - channel_subsys.crws_lost = false; - } - - QTAILQ_INSERT_TAIL(&channel_subsys.pending_crws, crw_cont, sibling); - - if (channel_subsys.do_crw_mchk) { - channel_subsys.do_crw_mchk = false; - /* Inject crw pending machine check. */ - s390_crw_mchk(); - } -} - -void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, - int hotplugged, int add) -{ - uint8_t guest_cssid; - bool chain_crw; - - if (add && !hotplugged) { - return; - } - if (channel_subsys.max_cssid == 0) { - /* Default cssid shows up as 0. */ - guest_cssid = (cssid == channel_subsys.default_cssid) ? 0 : cssid; - } else { - /* Show real cssid to the guest. */ - guest_cssid = cssid; - } - /* - * Only notify for higher subchannel sets/channel subsystems if the - * guest has enabled it. - */ - if ((ssid > channel_subsys.max_ssid) || - (guest_cssid > channel_subsys.max_cssid) || - ((channel_subsys.max_cssid == 0) && - (cssid != channel_subsys.default_cssid))) { - return; - } - chain_crw = (channel_subsys.max_ssid > 0) || - (channel_subsys.max_cssid > 0); - css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, chain_crw ? 1 : 0, schid); - if (chain_crw) { - css_queue_crw(CRW_RSC_SUBCH, CRW_ERC_IPI, 0, - (guest_cssid << 8) | (ssid << 4)); - } -} - -void css_generate_chp_crws(uint8_t cssid, uint8_t chpid) -{ - /* TODO */ -} - -void css_generate_css_crws(uint8_t cssid) -{ - if (!channel_subsys.sei_pending) { - css_queue_crw(CRW_RSC_CSS, 0, 0, cssid); - } - channel_subsys.sei_pending = true; -} - -void css_clear_sei_pending(void) -{ - channel_subsys.sei_pending = false; -} - -int css_enable_mcsse(void) -{ - trace_css_enable_facility("mcsse"); - channel_subsys.max_cssid = MAX_CSSID; - return 0; -} - -int css_enable_mss(void) -{ - trace_css_enable_facility("mss"); - channel_subsys.max_ssid = MAX_SSID; - return 0; -} - -void subch_device_save(SubchDev *s, QEMUFile *f) -{ - int i; - - qemu_put_byte(f, s->cssid); - qemu_put_byte(f, s->ssid); - qemu_put_be16(f, s->schid); - qemu_put_be16(f, s->devno); - qemu_put_byte(f, s->thinint_active); - /* SCHIB */ - /* PMCW */ - qemu_put_be32(f, s->curr_status.pmcw.intparm); - qemu_put_be16(f, s->curr_status.pmcw.flags); - qemu_put_be16(f, s->curr_status.pmcw.devno); - qemu_put_byte(f, s->curr_status.pmcw.lpm); - qemu_put_byte(f, s->curr_status.pmcw.pnom); - qemu_put_byte(f, s->curr_status.pmcw.lpum); - qemu_put_byte(f, s->curr_status.pmcw.pim); - qemu_put_be16(f, s->curr_status.pmcw.mbi); - qemu_put_byte(f, s->curr_status.pmcw.pom); - qemu_put_byte(f, s->curr_status.pmcw.pam); - qemu_put_buffer(f, s->curr_status.pmcw.chpid, 8); - qemu_put_be32(f, s->curr_status.pmcw.chars); - /* SCSW */ - qemu_put_be16(f, s->curr_status.scsw.flags); - qemu_put_be16(f, s->curr_status.scsw.ctrl); - qemu_put_be32(f, s->curr_status.scsw.cpa); - qemu_put_byte(f, s->curr_status.scsw.dstat); - qemu_put_byte(f, s->curr_status.scsw.cstat); - qemu_put_be16(f, s->curr_status.scsw.count); - qemu_put_be64(f, s->curr_status.mba); - qemu_put_buffer(f, s->curr_status.mda, 4); - /* end SCHIB */ - qemu_put_buffer(f, s->sense_data, 32); - qemu_put_be64(f, s->channel_prog); - /* last cmd */ - qemu_put_byte(f, s->last_cmd.cmd_code); - qemu_put_byte(f, s->last_cmd.flags); - qemu_put_be16(f, s->last_cmd.count); - qemu_put_be32(f, s->last_cmd.cda); - qemu_put_byte(f, s->last_cmd_valid); - qemu_put_byte(f, s->id.reserved); - qemu_put_be16(f, s->id.cu_type); - qemu_put_byte(f, s->id.cu_model); - qemu_put_be16(f, s->id.dev_type); - qemu_put_byte(f, s->id.dev_model); - qemu_put_byte(f, s->id.unused); - for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) { - qemu_put_byte(f, s->id.ciw[i].type); - qemu_put_byte(f, s->id.ciw[i].command); - qemu_put_be16(f, s->id.ciw[i].count); - } - qemu_put_byte(f, s->ccw_fmt_1); - qemu_put_byte(f, s->ccw_no_data_cnt); -} - -int subch_device_load(SubchDev *s, QEMUFile *f) -{ - int i; - - s->cssid = qemu_get_byte(f); - s->ssid = qemu_get_byte(f); - s->schid = qemu_get_be16(f); - s->devno = qemu_get_be16(f); - s->thinint_active = qemu_get_byte(f); - /* SCHIB */ - /* PMCW */ - s->curr_status.pmcw.intparm = qemu_get_be32(f); - s->curr_status.pmcw.flags = qemu_get_be16(f); - s->curr_status.pmcw.devno = qemu_get_be16(f); - s->curr_status.pmcw.lpm = qemu_get_byte(f); - s->curr_status.pmcw.pnom = qemu_get_byte(f); - s->curr_status.pmcw.lpum = qemu_get_byte(f); - s->curr_status.pmcw.pim = qemu_get_byte(f); - s->curr_status.pmcw.mbi = qemu_get_be16(f); - s->curr_status.pmcw.pom = qemu_get_byte(f); - s->curr_status.pmcw.pam = qemu_get_byte(f); - qemu_get_buffer(f, s->curr_status.pmcw.chpid, 8); - s->curr_status.pmcw.chars = qemu_get_be32(f); - /* SCSW */ - s->curr_status.scsw.flags = qemu_get_be16(f); - s->curr_status.scsw.ctrl = qemu_get_be16(f); - s->curr_status.scsw.cpa = qemu_get_be32(f); - s->curr_status.scsw.dstat = qemu_get_byte(f); - s->curr_status.scsw.cstat = qemu_get_byte(f); - s->curr_status.scsw.count = qemu_get_be16(f); - s->curr_status.mba = qemu_get_be64(f); - qemu_get_buffer(f, s->curr_status.mda, 4); - /* end SCHIB */ - qemu_get_buffer(f, s->sense_data, 32); - s->channel_prog = qemu_get_be64(f); - /* last cmd */ - s->last_cmd.cmd_code = qemu_get_byte(f); - s->last_cmd.flags = qemu_get_byte(f); - s->last_cmd.count = qemu_get_be16(f); - s->last_cmd.cda = qemu_get_be32(f); - s->last_cmd_valid = qemu_get_byte(f); - s->id.reserved = qemu_get_byte(f); - s->id.cu_type = qemu_get_be16(f); - s->id.cu_model = qemu_get_byte(f); - s->id.dev_type = qemu_get_be16(f); - s->id.dev_model = qemu_get_byte(f); - s->id.unused = qemu_get_byte(f); - for (i = 0; i < ARRAY_SIZE(s->id.ciw); i++) { - s->id.ciw[i].type = qemu_get_byte(f); - s->id.ciw[i].command = qemu_get_byte(f); - s->id.ciw[i].count = qemu_get_be16(f); - } - s->ccw_fmt_1 = qemu_get_byte(f); - s->ccw_no_data_cnt = qemu_get_byte(f); - /* - * Hack alert. We don't migrate the channel subsystem status (no - * device!), but we need to find out if the guest enabled mss/mcss-e. - * If the subchannel is enabled, it certainly was able to access it, - * so adjust the max_ssid/max_cssid values for relevant ssid/cssid - * values. This is not watertight, but better than nothing. - */ - if (s->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA) { - if (s->ssid) { - channel_subsys.max_ssid = MAX_SSID; - } - if (s->cssid != channel_subsys.default_cssid) { - channel_subsys.max_cssid = MAX_CSSID; - } - } - return 0; -} - -void css_reset_sch(SubchDev *sch) -{ - PMCW *p = &sch->curr_status.pmcw; - - if ((p->flags & PMCW_FLAGS_MASK_ENA) != 0 && sch->disable_cb) { - sch->disable_cb(sch); - } - - p->intparm = 0; - p->flags &= ~(PMCW_FLAGS_MASK_ISC | PMCW_FLAGS_MASK_ENA | - PMCW_FLAGS_MASK_LM | PMCW_FLAGS_MASK_MME | - PMCW_FLAGS_MASK_MP | PMCW_FLAGS_MASK_TF); - p->flags |= PMCW_FLAGS_MASK_DNV; - p->devno = sch->devno; - p->pim = 0x80; - p->lpm = p->pim; - p->pnom = 0; - p->lpum = 0; - p->mbi = 0; - p->pom = 0xff; - p->pam = 0x80; - p->chars &= ~(PMCW_CHARS_MASK_MBFC | PMCW_CHARS_MASK_XMWME | - PMCW_CHARS_MASK_CSENSE); - - memset(&sch->curr_status.scsw, 0, sizeof(sch->curr_status.scsw)); - sch->curr_status.mba = 0; - - sch->channel_prog = 0x0; - sch->last_cmd_valid = false; - sch->thinint_active = false; -} - -void css_reset(void) -{ - CrwContainer *crw_cont; - - /* Clean up monitoring. */ - channel_subsys.chnmon_active = false; - channel_subsys.chnmon_area = 0; - - /* Clear pending CRWs. */ - while ((crw_cont = QTAILQ_FIRST(&channel_subsys.pending_crws))) { - QTAILQ_REMOVE(&channel_subsys.pending_crws, crw_cont, sibling); - g_free(crw_cont); - } - channel_subsys.sei_pending = false; - channel_subsys.do_crw_mchk = true; - channel_subsys.crws_lost = false; - - /* Reset maximum ids. */ - channel_subsys.max_cssid = 0; - channel_subsys.max_ssid = 0; -} diff --git a/qemu/hw/s390x/css.h b/qemu/hw/s390x/css.h deleted file mode 100644 index a320eea59..000000000 --- a/qemu/hw/s390x/css.h +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Channel subsystem structures and definitions. - * - * Copyright 2012 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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. - */ - -#ifndef CSS_H -#define CSS_H - -#include "hw/s390x/adapter.h" -#include "hw/s390x/s390_flic.h" -#include "ioinst.h" - -/* Channel subsystem constants. */ -#define MAX_SCHID 65535 -#define MAX_SSID 3 -#define MAX_CSSID 254 /* 255 is reserved */ -#define MAX_CHPID 255 - -#define MAX_CIWS 62 - -typedef struct CIW { - uint8_t type; - uint8_t command; - uint16_t count; -} QEMU_PACKED CIW; - -typedef struct SenseId { - /* common part */ - uint8_t reserved; /* always 0x'FF' */ - uint16_t cu_type; /* control unit type */ - uint8_t cu_model; /* control unit model */ - uint16_t dev_type; /* device type */ - uint8_t dev_model; /* device model */ - uint8_t unused; /* padding byte */ - /* extended part */ - CIW ciw[MAX_CIWS]; /* variable # of CIWs */ -} QEMU_PACKED SenseId; - -/* Channel measurements, from linux/drivers/s390/cio/cmf.c. */ -typedef struct CMB { - uint16_t ssch_rsch_count; - uint16_t sample_count; - uint32_t device_connect_time; - uint32_t function_pending_time; - uint32_t device_disconnect_time; - uint32_t control_unit_queuing_time; - uint32_t device_active_only_time; - uint32_t reserved[2]; -} QEMU_PACKED CMB; - -typedef struct CMBE { - uint32_t ssch_rsch_count; - uint32_t sample_count; - uint32_t device_connect_time; - uint32_t function_pending_time; - uint32_t device_disconnect_time; - uint32_t control_unit_queuing_time; - uint32_t device_active_only_time; - uint32_t device_busy_time; - uint32_t initial_command_response_time; - uint32_t reserved[7]; -} QEMU_PACKED CMBE; - -struct SubchDev { - /* channel-subsystem related things: */ - uint8_t cssid; - uint8_t ssid; - uint16_t schid; - uint16_t devno; - SCHIB curr_status; - uint8_t sense_data[32]; - hwaddr channel_prog; - CCW1 last_cmd; - bool last_cmd_valid; - bool ccw_fmt_1; - bool thinint_active; - uint8_t ccw_no_data_cnt; - /* transport-provided data: */ - int (*ccw_cb) (SubchDev *, CCW1); - void (*disable_cb)(SubchDev *); - SenseId id; - void *driver_data; -}; - -typedef struct IndAddr { - hwaddr addr; - uint64_t map; - unsigned long refcnt; - int len; - QTAILQ_ENTRY(IndAddr) sibling; -} IndAddr; - -IndAddr *get_indicator(hwaddr ind_addr, int len); -void release_indicator(AdapterInfo *adapter, IndAddr *indicator); -int map_indicator(AdapterInfo *adapter, IndAddr *indicator); - -typedef SubchDev *(*css_subch_cb_func)(uint8_t m, uint8_t cssid, uint8_t ssid, - uint16_t schid); -void subch_device_save(SubchDev *s, QEMUFile *f); -int subch_device_load(SubchDev *s, QEMUFile *f); -int css_create_css_image(uint8_t cssid, bool default_image); -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); -void css_generate_sch_crws(uint8_t cssid, uint8_t ssid, uint16_t schid, - int hotplugged, int add); -void css_generate_chp_crws(uint8_t cssid, uint8_t chpid); -void css_generate_css_crws(uint8_t cssid); -void css_clear_sei_pending(void); -void css_adapter_interrupt(uint8_t isc); - -#define CSS_IO_ADAPTER_VIRTIO 1 -int css_register_io_adapter(uint8_t type, uint8_t isc, bool swap, - bool maskable, uint32_t *id); -#endif diff --git a/qemu/hw/s390x/event-facility.c b/qemu/hw/s390x/event-facility.c deleted file mode 100644 index 34b2faf01..000000000 --- a/qemu/hw/s390x/event-facility.c +++ /dev/null @@ -1,449 +0,0 @@ -/* - * SCLP - * Event Facility - * handles SCLP event types - * - Signal Quiesce - system power down - * - ASCII Console Data - VT220 read and write - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Heinz Graalfs <graalfs@de.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 "sysemu/sysemu.h" - -#include "hw/s390x/sclp.h" -#include "hw/s390x/event-facility.h" - -typedef struct SCLPEventsBus { - BusState qbus; -} SCLPEventsBus; - -struct SCLPEventFacility { - SysBusDevice parent_obj; - SCLPEventsBus sbus; - /* guest' receive mask */ - unsigned int receive_mask; -}; - -/* return true if any child has event pending set */ -static bool event_pending(SCLPEventFacility *ef) -{ - BusChild *kid; - SCLPEvent *event; - SCLPEventClass *event_class; - - QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { - DeviceState *qdev = kid->child; - event = DO_UPCAST(SCLPEvent, qdev, qdev); - event_class = SCLP_EVENT_GET_CLASS(event); - if (event->event_pending && - event_class->get_send_mask() & ef->receive_mask) { - return true; - } - } - return false; -} - -static unsigned int get_host_send_mask(SCLPEventFacility *ef) -{ - unsigned int mask; - BusChild *kid; - SCLPEventClass *child; - - mask = 0; - - QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { - DeviceState *qdev = kid->child; - child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev); - mask |= child->get_send_mask(); - } - return mask; -} - -static unsigned int get_host_receive_mask(SCLPEventFacility *ef) -{ - unsigned int mask; - BusChild *kid; - SCLPEventClass *child; - - mask = 0; - - QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { - DeviceState *qdev = kid->child; - child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev); - mask |= child->get_receive_mask(); - } - return mask; -} - -static uint16_t write_event_length_check(SCCB *sccb) -{ - int slen; - unsigned elen = 0; - EventBufferHeader *event; - WriteEventData *wed = (WriteEventData *) sccb; - - event = (EventBufferHeader *) &wed->ebh; - for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) { - elen = be16_to_cpu(event->length); - if (elen < sizeof(*event) || elen > slen) { - return SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR; - } - event = (void *) event + elen; - } - if (slen) { - return SCLP_RC_INCONSISTENT_LENGTHS; - } - return SCLP_RC_NORMAL_COMPLETION; -} - -static uint16_t handle_write_event_buf(SCLPEventFacility *ef, - EventBufferHeader *event_buf, SCCB *sccb) -{ - uint16_t rc; - BusChild *kid; - SCLPEvent *event; - SCLPEventClass *ec; - - rc = SCLP_RC_INVALID_FUNCTION; - - QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { - DeviceState *qdev = kid->child; - event = (SCLPEvent *) qdev; - ec = SCLP_EVENT_GET_CLASS(event); - - if (ec->write_event_data && - ec->can_handle_event(event_buf->type)) { - rc = ec->write_event_data(event, event_buf); - break; - } - } - return rc; -} - -static uint16_t handle_sccb_write_events(SCLPEventFacility *ef, SCCB *sccb) -{ - uint16_t rc; - int slen; - unsigned elen = 0; - EventBufferHeader *event_buf; - WriteEventData *wed = (WriteEventData *) sccb; - - event_buf = &wed->ebh; - rc = SCLP_RC_NORMAL_COMPLETION; - - /* loop over all contained event buffers */ - for (slen = sccb_data_len(sccb); slen > 0; slen -= elen) { - elen = be16_to_cpu(event_buf->length); - - /* in case of a previous error mark all trailing buffers - * as not accepted */ - if (rc != SCLP_RC_NORMAL_COMPLETION) { - event_buf->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED); - } else { - rc = handle_write_event_buf(ef, event_buf, sccb); - } - event_buf = (void *) event_buf + elen; - } - return rc; -} - -static void write_event_data(SCLPEventFacility *ef, SCCB *sccb) -{ - if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION); - goto out; - } - if (be16_to_cpu(sccb->h.length) < 8) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); - goto out; - } - /* first do a sanity check of the write events */ - sccb->h.response_code = cpu_to_be16(write_event_length_check(sccb)); - - /* if no early error, then execute */ - if (sccb->h.response_code == be16_to_cpu(SCLP_RC_NORMAL_COMPLETION)) { - sccb->h.response_code = - cpu_to_be16(handle_sccb_write_events(ef, sccb)); - } - -out: - return; -} - -static uint16_t handle_sccb_read_events(SCLPEventFacility *ef, SCCB *sccb, - unsigned int mask) -{ - uint16_t rc; - int slen; - unsigned elen; - BusChild *kid; - SCLPEvent *event; - SCLPEventClass *ec; - EventBufferHeader *event_buf; - ReadEventData *red = (ReadEventData *) sccb; - - event_buf = &red->ebh; - event_buf->length = 0; - slen = sizeof(sccb->data); - - rc = SCLP_RC_NO_EVENT_BUFFERS_STORED; - - QTAILQ_FOREACH(kid, &ef->sbus.qbus.children, sibling) { - DeviceState *qdev = kid->child; - event = (SCLPEvent *) qdev; - ec = SCLP_EVENT_GET_CLASS(event); - - if (mask & ec->get_send_mask()) { - if (ec->read_event_data(event, event_buf, &slen)) { - elen = be16_to_cpu(event_buf->length); - event_buf = (EventBufferHeader *) ((char *)event_buf + elen); - rc = SCLP_RC_NORMAL_COMPLETION; - } - } - } - - if (sccb->h.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE) { - /* architecture suggests to reset variable-length-response bit */ - sccb->h.control_mask[2] &= ~SCLP_VARIABLE_LENGTH_RESPONSE; - /* with a new length value */ - sccb->h.length = cpu_to_be16(SCCB_SIZE - slen); - } - return rc; -} - -static void read_event_data(SCLPEventFacility *ef, SCCB *sccb) -{ - unsigned int sclp_active_selection_mask; - unsigned int sclp_cp_receive_mask; - - ReadEventData *red = (ReadEventData *) sccb; - - if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH); - goto out; - } - - sclp_cp_receive_mask = ef->receive_mask; - - /* get active selection mask */ - switch (sccb->h.function_code) { - case SCLP_UNCONDITIONAL_READ: - sclp_active_selection_mask = sclp_cp_receive_mask; - break; - case SCLP_SELECTIVE_READ: - sclp_active_selection_mask = be32_to_cpu(red->mask); - if (!sclp_cp_receive_mask || - (sclp_active_selection_mask & ~sclp_cp_receive_mask)) { - sccb->h.response_code = - cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK); - goto out; - } - break; - default: - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION); - goto out; - } - sccb->h.response_code = cpu_to_be16( - handle_sccb_read_events(ef, sccb, sclp_active_selection_mask)); - -out: - return; -} - -static void write_event_mask(SCLPEventFacility *ef, SCCB *sccb) -{ - WriteEventMask *we_mask = (WriteEventMask *) sccb; - - /* 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) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH); - goto out; - } - - /* keep track of the guest's capability masks */ - ef->receive_mask = be32_to_cpu(we_mask->cp_receive_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)); - - sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); - -out: - return; -} - -/* qemu object creation and initialization functions */ - -#define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus" - -static void sclp_events_bus_realize(BusState *bus, Error **errp) -{ - BusChild *kid; - - /* TODO: recursive realization has to be done in common code */ - QTAILQ_FOREACH(kid, &bus->children, sibling) { - DeviceState *dev = kid->child; - - object_property_set_bool(OBJECT(dev), true, "realized", errp); - if (*errp) { - return; - } - } -} - -static void sclp_events_bus_class_init(ObjectClass *klass, void *data) -{ - BusClass *bc = BUS_CLASS(klass); - - bc->realize = sclp_events_bus_realize; -} - -static const TypeInfo sclp_events_bus_info = { - .name = TYPE_SCLP_EVENTS_BUS, - .parent = TYPE_BUS, - .class_init = sclp_events_bus_class_init, -}; - -static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code) -{ - switch (code & SCLP_CMD_CODE_MASK) { - case SCLP_CMD_READ_EVENT_DATA: - read_event_data(ef, sccb); - break; - case SCLP_CMD_WRITE_EVENT_DATA: - write_event_data(ef, sccb); - break; - case SCLP_CMD_WRITE_EVENT_MASK: - write_event_mask(ef, sccb); - break; - default: - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - break; - } -} - -static const VMStateDescription vmstate_event_facility = { - .name = "vmstate-event-facility", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT32(receive_mask, SCLPEventFacility), - VMSTATE_END_OF_LIST() - } -}; - -static void init_event_facility(Object *obj) -{ - SCLPEventFacility *event_facility = EVENT_FACILITY(obj); - DeviceState *sdev = DEVICE(obj); - Object *new; - - /* Spawn a new bus for SCLP events */ - qbus_create_inplace(&event_facility->sbus, sizeof(event_facility->sbus), - TYPE_SCLP_EVENTS_BUS, sdev, NULL); - - new = object_new(TYPE_SCLP_QUIESCE); - object_property_add_child(obj, TYPE_SCLP_QUIESCE, new, NULL); - object_unref(new); - qdev_set_parent_bus(DEVICE(new), &event_facility->sbus.qbus); - - new = object_new(TYPE_SCLP_CPU_HOTPLUG); - object_property_add_child(obj, TYPE_SCLP_CPU_HOTPLUG, new, NULL); - object_unref(new); - qdev_set_parent_bus(DEVICE(new), &event_facility->sbus.qbus); - /* the facility will automatically realize the devices via the bus */ -} - -static void reset_event_facility(DeviceState *dev) -{ - SCLPEventFacility *sdev = EVENT_FACILITY(dev); - - sdev->receive_mask = 0; -} - -static void init_event_facility_class(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *sbdc = SYS_BUS_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(sbdc); - SCLPEventFacilityClass *k = EVENT_FACILITY_CLASS(dc); - - dc->reset = reset_event_facility; - dc->vmsd = &vmstate_event_facility; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - k->command_handler = command_handler; - k->event_pending = event_pending; -} - -static const TypeInfo sclp_event_facility_info = { - .name = TYPE_SCLP_EVENT_FACILITY, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_init = init_event_facility, - .instance_size = sizeof(SCLPEventFacility), - .class_init = init_event_facility_class, - .class_size = sizeof(SCLPEventFacilityClass), -}; - -static void event_realize(DeviceState *qdev, Error **errp) -{ - SCLPEvent *event = SCLP_EVENT(qdev); - SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event); - - if (child->init) { - int rc = child->init(event); - if (rc < 0) { - error_setg(errp, "SCLP event initialization failed."); - return; - } - } -} - -static void event_unrealize(DeviceState *qdev, Error **errp) -{ - SCLPEvent *event = SCLP_EVENT(qdev); - SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event); - if (child->exit) { - int rc = child->exit(event); - if (rc < 0) { - error_setg(errp, "SCLP event exit failed."); - return; - } - } -} - -static void event_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->bus_type = TYPE_SCLP_EVENTS_BUS; - dc->realize = event_realize; - dc->unrealize = event_unrealize; -} - -static const TypeInfo sclp_event_type_info = { - .name = TYPE_SCLP_EVENT, - .parent = TYPE_DEVICE, - .instance_size = sizeof(SCLPEvent), - .class_init = event_class_init, - .class_size = sizeof(SCLPEventClass), - .abstract = true, -}; - -static void register_types(void) -{ - type_register_static(&sclp_events_bus_info); - type_register_static(&sclp_event_facility_info); - type_register_static(&sclp_event_type_info); -} - -type_init(register_types) diff --git a/qemu/hw/s390x/ipl.c b/qemu/hw/s390x/ipl.c deleted file mode 100644 index f10420027..000000000 --- a/qemu/hw/s390x/ipl.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * bootloader support - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Christian Borntraeger <borntraeger@de.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 "sysemu/sysemu.h" -#include "cpu.h" -#include "elf.h" -#include "hw/loader.h" -#include "hw/s390x/virtio-ccw.h" -#include "hw/s390x/css.h" -#include "ipl.h" - -#define KERN_IMAGE_START 0x010000UL -#define KERN_PARM_AREA 0x010480UL -#define INITRD_START 0x800000UL -#define INITRD_PARM_START 0x010408UL -#define INITRD_PARM_SIZE 0x010410UL -#define PARMFILE_START 0x001000UL -#define ZIPL_IMAGE_START 0x009000UL -#define IPL_PSW_MASK (PSW_MASK_32 | PSW_MASK_64) - -static const VMStateDescription vmstate_iplb = { - .name = "ipl/iplb", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT8_ARRAY(reserved1, IplParameterBlock, 110), - VMSTATE_UINT16(devno, IplParameterBlock), - VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88), - VMSTATE_END_OF_LIST() - } -}; - -static const VMStateDescription vmstate_ipl = { - .name = "ipl", - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_UINT64(start_addr, S390IPLState), - VMSTATE_UINT64(bios_start_addr, S390IPLState), - VMSTATE_STRUCT(iplb, S390IPLState, 0, vmstate_iplb, IplParameterBlock), - VMSTATE_BOOL(iplb_valid, S390IPLState), - VMSTATE_UINT8(cssid, S390IPLState), - VMSTATE_UINT8(ssid, S390IPLState), - VMSTATE_UINT16(devno, S390IPLState), - VMSTATE_END_OF_LIST() - } -}; - -static S390IPLState *get_ipl_device(void) -{ - return S390_IPL(object_resolve_path_type("", TYPE_S390_IPL, NULL)); -} - -static uint64_t bios_translate_addr(void *opaque, uint64_t srcaddr) -{ - uint64_t dstaddr = *(uint64_t *) opaque; - /* - * Assuming that our s390-ccw.img was linked for starting at address 0, - * we can simply add the destination address for the final location - */ - return srcaddr + dstaddr; -} - -static void s390_ipl_realize(DeviceState *dev, Error **errp) -{ - S390IPLState *ipl = S390_IPL(dev); - uint64_t pentry = KERN_IMAGE_START; - int kernel_size; - Error *err = NULL; - - int bios_size; - char *bios_filename; - - /* - * Always load the bios if it was enforced, - * even if an external kernel has been defined. - */ - if (!ipl->kernel || ipl->enforce_bios) { - uint64_t fwbase = (MIN(ram_size, 0x80000000U) - 0x200000) & ~0xffffUL; - - if (bios_name == NULL) { - bios_name = ipl->firmware; - } - - bios_filename = qemu_find_file(QEMU_FILE_TYPE_BIOS, bios_name); - if (bios_filename == NULL) { - error_setg(&err, "could not find stage1 bootloader"); - goto error; - } - - bios_size = load_elf(bios_filename, bios_translate_addr, &fwbase, - &ipl->bios_start_addr, NULL, NULL, 1, - EM_S390, 0, 0); - if (bios_size > 0) { - /* Adjust ELF start address to final location */ - ipl->bios_start_addr += fwbase; - } else { - /* Try to load non-ELF file (e.g. s390-ccw.img) */ - bios_size = load_image_targphys(bios_filename, ZIPL_IMAGE_START, - 4096); - ipl->bios_start_addr = ZIPL_IMAGE_START; - } - g_free(bios_filename); - - if (bios_size == -1) { - error_setg(&err, "could not load bootloader '%s'", bios_name); - goto error; - } - - /* default boot target is the bios */ - ipl->start_addr = ipl->bios_start_addr; - } - - if (ipl->kernel) { - kernel_size = load_elf(ipl->kernel, NULL, NULL, &pentry, NULL, - NULL, 1, EM_S390, 0, 0); - if (kernel_size < 0) { - kernel_size = load_image_targphys(ipl->kernel, 0, ram_size); - } - if (kernel_size < 0) { - error_setg(&err, "could not load kernel '%s'", ipl->kernel); - goto error; - } - /* - * Is it a Linux kernel (starting at 0x10000)? If yes, we fill in the - * kernel parameters here as well. Note: For old kernels (up to 3.2) - * we can not rely on the ELF entry point - it was 0x800 (the SALIPL - * loader) and it won't work. For this case we force it to 0x10000, too. - */ - if (pentry == KERN_IMAGE_START || pentry == 0x800) { - ipl->start_addr = KERN_IMAGE_START; - /* Overwrite parameters in the kernel image, which are "rom" */ - strcpy(rom_ptr(KERN_PARM_AREA), ipl->cmdline); - } else { - ipl->start_addr = pentry; - } - - if (ipl->initrd) { - ram_addr_t initrd_offset; - int initrd_size; - - initrd_offset = INITRD_START; - while (kernel_size + 0x100000 > initrd_offset) { - initrd_offset += 0x100000; - } - initrd_size = load_image_targphys(ipl->initrd, initrd_offset, - ram_size - initrd_offset); - if (initrd_size == -1) { - error_setg(&err, "could not load initrd '%s'", ipl->initrd); - goto error; - } - - /* - * we have to overwrite values in the kernel image, - * which are "rom" - */ - stq_p(rom_ptr(INITRD_PARM_START), initrd_offset); - stq_p(rom_ptr(INITRD_PARM_SIZE), initrd_size); - } - } - qemu_register_reset(qdev_reset_all_fn, dev); -error: - error_propagate(errp, err); -} - -static Property s390_ipl_properties[] = { - DEFINE_PROP_STRING("kernel", S390IPLState, kernel), - DEFINE_PROP_STRING("initrd", S390IPLState, initrd), - DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline), - DEFINE_PROP_STRING("firmware", S390IPLState, firmware), - DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false), - DEFINE_PROP_END_OF_LIST(), -}; - -/* - * In addition to updating the iplstate, this function returns: - * - 0 if system was ipled with external kernel - * - -1 if no valid boot device was found - * - ccw id of the boot device otherwise - */ -static uint64_t s390_update_iplstate(S390IPLState *ipl) -{ - DeviceState *dev_st; - - if (ipl->iplb_valid) { - ipl->cssid = 0; - ipl->ssid = 0; - ipl->devno = ipl->iplb.devno; - goto out; - } - - if (ipl->kernel) { - return 0; - } - - dev_st = get_boot_device(0); - if (dev_st) { - VirtioCcwDevice *ccw_dev = (VirtioCcwDevice *) object_dynamic_cast( - OBJECT(qdev_get_parent_bus(dev_st)->parent), - TYPE_VIRTIO_CCW_DEVICE); - if (ccw_dev) { - ipl->cssid = ccw_dev->sch->cssid; - ipl->ssid = ccw_dev->sch->ssid; - ipl->devno = ccw_dev->sch->devno; - goto out; - } - } - - return -1; -out: - return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno); -} - -void s390_ipl_update_diag308(IplParameterBlock *iplb) -{ - S390IPLState *ipl = get_ipl_device(); - - ipl->iplb = *iplb; - ipl->iplb_valid = true; -} - -IplParameterBlock *s390_ipl_get_iplb(void) -{ - S390IPLState *ipl = get_ipl_device(); - - if (!ipl->iplb_valid) { - return NULL; - } - return &ipl->iplb; -} - -void s390_reipl_request(void) -{ - S390IPLState *ipl = get_ipl_device(); - - ipl->reipl_requested = true; - qemu_system_reset_request(); -} - -void s390_ipl_prepare_cpu(S390CPU *cpu) -{ - S390IPLState *ipl = get_ipl_device(); - - cpu->env.psw.addr = ipl->start_addr; - cpu->env.psw.mask = IPL_PSW_MASK; - - if (!ipl->kernel || ipl->iplb_valid) { - cpu->env.psw.addr = ipl->bios_start_addr; - cpu->env.regs[7] = s390_update_iplstate(ipl); - } -} - -static void s390_ipl_reset(DeviceState *dev) -{ - S390IPLState *ipl = S390_IPL(dev); - - if (!ipl->reipl_requested) { - ipl->iplb_valid = false; - } - ipl->reipl_requested = false; -} - -static void s390_ipl_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = s390_ipl_realize; - dc->props = s390_ipl_properties; - dc->reset = s390_ipl_reset; - dc->vmsd = &vmstate_ipl; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static const TypeInfo s390_ipl_info = { - .class_init = s390_ipl_class_init, - .parent = TYPE_DEVICE, - .name = TYPE_S390_IPL, - .instance_size = sizeof(S390IPLState), -}; - -static void s390_ipl_register_types(void) -{ - type_register_static(&s390_ipl_info); -} - -type_init(s390_ipl_register_types) diff --git a/qemu/hw/s390x/ipl.h b/qemu/hw/s390x/ipl.h deleted file mode 100644 index 6b48ed7b9..000000000 --- a/qemu/hw/s390x/ipl.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * s390 IPL device - * - * Copyright 2015 IBM Corp. - * Author(s): Zhang Fan <bjfanzh@cn.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. - */ - -#ifndef HW_S390_IPL_H -#define HW_S390_IPL_H - -#include "hw/qdev.h" -#include "cpu.h" - -typedef struct IplParameterBlock { - uint8_t reserved1[110]; - uint16_t devno; - uint8_t reserved2[88]; -} IplParameterBlock; - -void s390_ipl_update_diag308(IplParameterBlock *iplb); -void s390_ipl_prepare_cpu(S390CPU *cpu); -IplParameterBlock *s390_ipl_get_iplb(void); -void s390_reipl_request(void); - -#define TYPE_S390_IPL "s390-ipl" -#define S390_IPL(obj) OBJECT_CHECK(S390IPLState, (obj), TYPE_S390_IPL) - -struct S390IPLState { - /*< private >*/ - DeviceState parent_obj; - uint64_t start_addr; - uint64_t bios_start_addr; - bool enforce_bios; - IplParameterBlock iplb; - bool iplb_valid; - bool reipl_requested; - - /*< public >*/ - char *kernel; - char *initrd; - char *cmdline; - char *firmware; - uint8_t cssid; - uint8_t ssid; - uint16_t devno; -}; -typedef struct S390IPLState S390IPLState; - -#endif diff --git a/qemu/hw/s390x/s390-pci-bus.c b/qemu/hw/s390x/s390-pci-bus.c deleted file mode 100644 index 918b58543..000000000 --- a/qemu/hw/s390x/s390-pci-bus.c +++ /dev/null @@ -1,621 +0,0 @@ -/* - * s390 PCI BUS - * - * Copyright 2014 IBM Corp. - * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com> - * Hong Bo Li <lihbbj@cn.ibm.com> - * Yi Min Zhao <zyimin@cn.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 "qemu-common.h" -#include "cpu.h" -#include "s390-pci-bus.h" -#include <hw/pci/pci_bus.h> -#include <hw/pci/msi.h> -#include <qemu/error-report.h> - -/* #define DEBUG_S390PCI_BUS */ -#ifdef DEBUG_S390PCI_BUS -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, "S390pci-bus: " fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - -int chsc_sei_nt2_get_event(void *res) -{ - ChscSeiNt2Res *nt2_res = (ChscSeiNt2Res *)res; - PciCcdfAvail *accdf; - PciCcdfErr *eccdf; - int rc = 1; - SeiContainer *sei_cont; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return rc; - } - - sei_cont = QTAILQ_FIRST(&s->pending_sei); - if (sei_cont) { - QTAILQ_REMOVE(&s->pending_sei, sei_cont, link); - nt2_res->nt = 2; - nt2_res->cc = sei_cont->cc; - nt2_res->length = cpu_to_be16(sizeof(ChscSeiNt2Res)); - switch (sei_cont->cc) { - case 1: /* error event */ - eccdf = (PciCcdfErr *)nt2_res->ccdf; - eccdf->fid = cpu_to_be32(sei_cont->fid); - eccdf->fh = cpu_to_be32(sei_cont->fh); - eccdf->e = cpu_to_be32(sei_cont->e); - eccdf->faddr = cpu_to_be64(sei_cont->faddr); - eccdf->pec = cpu_to_be16(sei_cont->pec); - break; - case 2: /* availability event */ - accdf = (PciCcdfAvail *)nt2_res->ccdf; - accdf->fid = cpu_to_be32(sei_cont->fid); - accdf->fh = cpu_to_be32(sei_cont->fh); - accdf->pec = cpu_to_be16(sei_cont->pec); - break; - default: - abort(); - } - g_free(sei_cont); - rc = 0; - } - - return rc; -} - -int chsc_sei_nt2_have_event(void) -{ - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return 0; - } - - return !QTAILQ_EMPTY(&s->pending_sei); -} - -S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid) -{ - S390PCIBusDevice *pbdev; - int i; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return NULL; - } - - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - if ((pbdev->fh != 0) && (pbdev->fid == fid)) { - return pbdev; - } - } - - return NULL; -} - -void s390_pci_sclp_configure(int configure, SCCB *sccb) -{ - PciCfgSccb *psccb = (PciCfgSccb *)sccb; - S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid)); - uint16_t rc; - - if (pbdev) { - if ((configure == 1 && pbdev->configured == true) || - (configure == 0 && pbdev->configured == false)) { - rc = SCLP_RC_NO_ACTION_REQUIRED; - } else { - pbdev->configured = !pbdev->configured; - rc = SCLP_RC_NORMAL_COMPLETION; - } - } else { - DPRINTF("sclp config %d no dev found\n", configure); - rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED; - } - - psccb->header.response_code = cpu_to_be16(rc); -} - -static uint32_t s390_pci_get_pfid(PCIDevice *pdev) -{ - return PCI_SLOT(pdev->devfn); -} - -static uint32_t s390_pci_get_pfh(PCIDevice *pdev) -{ - return PCI_SLOT(pdev->devfn) | FH_VIRT; -} - -S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx) -{ - S390PCIBusDevice *pbdev; - int i; - int j = 0; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return NULL; - } - - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - - if (pbdev->fh == 0) { - continue; - } - - if (j == idx) { - return pbdev; - } - j++; - } - - return NULL; -} - -S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh) -{ - S390PCIBusDevice *pbdev; - int i; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s || !fh) { - return NULL; - } - - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - if (pbdev->fh == fh) { - return pbdev; - } - } - - return NULL; -} - -static void s390_pci_generate_event(uint8_t cc, uint16_t pec, uint32_t fh, - uint32_t fid, uint64_t faddr, uint32_t e) -{ - SeiContainer *sei_cont; - S390pciState *s = S390_PCI_HOST_BRIDGE( - object_resolve_path(TYPE_S390_PCI_HOST_BRIDGE, NULL)); - - if (!s) { - return; - } - - sei_cont = g_malloc0(sizeof(SeiContainer)); - sei_cont->fh = fh; - sei_cont->fid = fid; - sei_cont->cc = cc; - sei_cont->pec = pec; - sei_cont->faddr = faddr; - sei_cont->e = e; - - QTAILQ_INSERT_TAIL(&s->pending_sei, sei_cont, link); - css_generate_css_crws(0); -} - -static void s390_pci_generate_plug_event(uint16_t pec, uint32_t fh, - uint32_t fid) -{ - s390_pci_generate_event(2, pec, fh, fid, 0, 0); -} - -static void s390_pci_generate_error_event(uint16_t pec, uint32_t fh, - uint32_t fid, uint64_t faddr, - uint32_t e) -{ - s390_pci_generate_event(1, pec, fh, fid, faddr, e); -} - -static void s390_pci_set_irq(void *opaque, int irq, int level) -{ - /* nothing to do */ -} - -static int s390_pci_map_irq(PCIDevice *pci_dev, int irq_num) -{ - /* nothing to do */ - return 0; -} - -static uint64_t s390_pci_get_table_origin(uint64_t iota) -{ - return iota & ~ZPCI_IOTA_RTTO_FLAG; -} - -static unsigned int calc_rtx(dma_addr_t ptr) -{ - return ((unsigned long) ptr >> ZPCI_RT_SHIFT) & ZPCI_INDEX_MASK; -} - -static unsigned int calc_sx(dma_addr_t ptr) -{ - return ((unsigned long) ptr >> ZPCI_ST_SHIFT) & ZPCI_INDEX_MASK; -} - -static unsigned int calc_px(dma_addr_t ptr) -{ - return ((unsigned long) ptr >> PAGE_SHIFT) & ZPCI_PT_MASK; -} - -static uint64_t get_rt_sto(uint64_t entry) -{ - return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_RTX) - ? (entry & ZPCI_RTE_ADDR_MASK) - : 0; -} - -static uint64_t get_st_pto(uint64_t entry) -{ - return ((entry & ZPCI_TABLE_TYPE_MASK) == ZPCI_TABLE_TYPE_SX) - ? (entry & ZPCI_STE_ADDR_MASK) - : 0; -} - -static uint64_t s390_guest_io_table_walk(uint64_t guest_iota, - uint64_t guest_dma_address) -{ - uint64_t sto_a, pto_a, px_a; - uint64_t sto, pto, pte; - uint32_t rtx, sx, px; - - rtx = calc_rtx(guest_dma_address); - sx = calc_sx(guest_dma_address); - px = calc_px(guest_dma_address); - - sto_a = guest_iota + rtx * sizeof(uint64_t); - sto = address_space_ldq(&address_space_memory, sto_a, - MEMTXATTRS_UNSPECIFIED, NULL); - sto = get_rt_sto(sto); - if (!sto) { - pte = 0; - goto out; - } - - pto_a = sto + sx * sizeof(uint64_t); - pto = address_space_ldq(&address_space_memory, pto_a, - MEMTXATTRS_UNSPECIFIED, NULL); - pto = get_st_pto(pto); - if (!pto) { - pte = 0; - goto out; - } - - px_a = pto + px * sizeof(uint64_t); - pte = address_space_ldq(&address_space_memory, px_a, - MEMTXATTRS_UNSPECIFIED, NULL); - -out: - return pte; -} - -static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr, - bool is_write) -{ - uint64_t pte; - uint32_t flags; - S390PCIBusDevice *pbdev = container_of(iommu, S390PCIBusDevice, iommu_mr); - S390pciState *s; - IOMMUTLBEntry ret = { - .target_as = &address_space_memory, - .iova = 0, - .translated_addr = 0, - .addr_mask = ~(hwaddr)0, - .perm = IOMMU_NONE, - }; - - if (!pbdev->configured || !pbdev->pdev || !(pbdev->fh & FH_ENABLED)) { - return ret; - } - - DPRINTF("iommu trans addr 0x%" PRIx64 "\n", addr); - - s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pbdev->pdev)->qbus.parent); - /* s390 does not have an APIC mapped to main storage so we use - * a separate AddressSpace only for msix notifications - */ - if (addr == ZPCI_MSI_ADDR) { - ret.target_as = &s->msix_notify_as; - ret.iova = addr; - ret.translated_addr = addr; - ret.addr_mask = 0xfff; - ret.perm = IOMMU_RW; - return ret; - } - - if (!pbdev->g_iota) { - pbdev->error_state = true; - pbdev->lgstg_blocked = true; - s390_pci_generate_error_event(ERR_EVENT_INVALAS, pbdev->fh, pbdev->fid, - addr, 0); - return ret; - } - - if (addr < pbdev->pba || addr > pbdev->pal) { - pbdev->error_state = true; - pbdev->lgstg_blocked = true; - s390_pci_generate_error_event(ERR_EVENT_OORANGE, pbdev->fh, pbdev->fid, - addr, 0); - return ret; - } - - pte = s390_guest_io_table_walk(s390_pci_get_table_origin(pbdev->g_iota), - addr); - - if (!pte) { - pbdev->error_state = true; - pbdev->lgstg_blocked = true; - s390_pci_generate_error_event(ERR_EVENT_SERR, pbdev->fh, pbdev->fid, - addr, ERR_EVENT_Q_BIT); - return ret; - } - - flags = pte & ZPCI_PTE_FLAG_MASK; - ret.iova = addr; - ret.translated_addr = pte & ZPCI_PTE_ADDR_MASK; - ret.addr_mask = 0xfff; - - if (flags & ZPCI_PTE_INVALID) { - ret.perm = IOMMU_NONE; - } else { - ret.perm = IOMMU_RW; - } - - return ret; -} - -static const MemoryRegionIOMMUOps s390_iommu_ops = { - .translate = s390_translate_iommu, -}; - -static AddressSpace *s390_pci_dma_iommu(PCIBus *bus, void *opaque, int devfn) -{ - S390pciState *s = opaque; - - return &s->pbdev[PCI_SLOT(devfn)].as; -} - -static uint8_t set_ind_atomic(uint64_t ind_loc, uint8_t to_be_set) -{ - uint8_t ind_old, ind_new; - hwaddr len = 1; - uint8_t *ind_addr; - - ind_addr = cpu_physical_memory_map(ind_loc, &len, 1); - if (!ind_addr) { - s390_pci_generate_error_event(ERR_EVENT_AIRERR, 0, 0, 0, 0); - return -1; - } - do { - ind_old = *ind_addr; - ind_new = ind_old | to_be_set; - } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); - cpu_physical_memory_unmap(ind_addr, len, 1, len); - - return ind_old; -} - -static void s390_msi_ctrl_write(void *opaque, hwaddr addr, uint64_t data, - unsigned int size) -{ - S390PCIBusDevice *pbdev; - uint32_t io_int_word; - uint32_t fid = data >> ZPCI_MSI_VEC_BITS; - uint32_t vec = data & ZPCI_MSI_VEC_MASK; - uint64_t ind_bit; - uint32_t sum_bit; - uint32_t e = 0; - - DPRINTF("write_msix data 0x%" PRIx64 " fid %d vec 0x%x\n", data, fid, vec); - - pbdev = s390_pci_find_dev_by_fid(fid); - if (!pbdev) { - e |= (vec << ERR_EVENT_MVN_OFFSET); - s390_pci_generate_error_event(ERR_EVENT_NOMSI, 0, fid, addr, e); - return; - } - - if (!(pbdev->fh & FH_ENABLED)) { - return; - } - - ind_bit = pbdev->routes.adapter.ind_offset; - sum_bit = pbdev->routes.adapter.summary_offset; - - set_ind_atomic(pbdev->routes.adapter.ind_addr + (ind_bit + vec) / 8, - 0x80 >> ((ind_bit + vec) % 8)); - if (!set_ind_atomic(pbdev->routes.adapter.summary_addr + sum_bit / 8, - 0x80 >> (sum_bit % 8))) { - io_int_word = (pbdev->isc << 27) | IO_INT_WORD_AI; - s390_io_interrupt(0, 0, 0, io_int_word); - } -} - -static uint64_t s390_msi_ctrl_read(void *opaque, hwaddr addr, unsigned size) -{ - return 0xffffffff; -} - -static const MemoryRegionOps s390_msi_ctrl_ops = { - .write = s390_msi_ctrl_write, - .read = s390_msi_ctrl_read, - .endianness = DEVICE_LITTLE_ENDIAN, -}; - -void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable) -{ - pbdev->configured = false; - - if (enable) { - uint64_t size = pbdev->pal - pbdev->pba + 1; - memory_region_init_iommu(&pbdev->iommu_mr, OBJECT(&pbdev->mr), - &s390_iommu_ops, "iommu-s390", size); - memory_region_add_subregion(&pbdev->mr, pbdev->pba, &pbdev->iommu_mr); - } else { - memory_region_del_subregion(&pbdev->mr, &pbdev->iommu_mr); - } - - pbdev->configured = true; -} - -static void s390_pcihost_init_as(S390pciState *s) -{ - int i; - S390PCIBusDevice *pbdev; - - for (i = 0; i < PCI_SLOT_MAX; i++) { - pbdev = &s->pbdev[i]; - memory_region_init(&pbdev->mr, OBJECT(s), - "iommu-root-s390", UINT64_MAX); - address_space_init(&pbdev->as, &pbdev->mr, "iommu-pci"); - } - - memory_region_init_io(&s->msix_notify_mr, OBJECT(s), - &s390_msi_ctrl_ops, s, "msix-s390", UINT64_MAX); - address_space_init(&s->msix_notify_as, &s->msix_notify_mr, "msix-pci"); -} - -static int s390_pcihost_init(SysBusDevice *dev) -{ - PCIBus *b; - BusState *bus; - PCIHostState *phb = PCI_HOST_BRIDGE(dev); - S390pciState *s = S390_PCI_HOST_BRIDGE(dev); - - DPRINTF("host_init\n"); - - b = pci_register_bus(DEVICE(dev), NULL, - s390_pci_set_irq, s390_pci_map_irq, NULL, - get_system_memory(), get_system_io(), 0, 64, - TYPE_PCI_BUS); - s390_pcihost_init_as(s); - pci_setup_iommu(b, s390_pci_dma_iommu, s); - - bus = BUS(b); - qbus_set_hotplug_handler(bus, DEVICE(dev), NULL); - phb->bus = b; - QTAILQ_INIT(&s->pending_sei); - return 0; -} - -static int s390_pcihost_setup_msix(S390PCIBusDevice *pbdev) -{ - uint8_t pos; - uint16_t ctrl; - uint32_t table, pba; - - pos = pci_find_capability(pbdev->pdev, PCI_CAP_ID_MSIX); - if (!pos) { - pbdev->msix.available = false; - return 0; - } - - ctrl = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_FLAGS, - pci_config_size(pbdev->pdev), sizeof(ctrl)); - table = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_TABLE, - pci_config_size(pbdev->pdev), sizeof(table)); - pba = pci_host_config_read_common(pbdev->pdev, pos + PCI_MSIX_PBA, - pci_config_size(pbdev->pdev), sizeof(pba)); - - pbdev->msix.table_bar = table & PCI_MSIX_FLAGS_BIRMASK; - pbdev->msix.table_offset = table & ~PCI_MSIX_FLAGS_BIRMASK; - pbdev->msix.pba_bar = pba & PCI_MSIX_FLAGS_BIRMASK; - pbdev->msix.pba_offset = pba & ~PCI_MSIX_FLAGS_BIRMASK; - pbdev->msix.entries = (ctrl & PCI_MSIX_FLAGS_QSIZE) + 1; - pbdev->msix.available = true; - return 0; -} - -static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - PCIDevice *pci_dev = PCI_DEVICE(dev); - S390PCIBusDevice *pbdev; - S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev) - ->qbus.parent); - - pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; - - pbdev->fid = s390_pci_get_pfid(pci_dev); - pbdev->pdev = pci_dev; - pbdev->configured = true; - pbdev->fh = s390_pci_get_pfh(pci_dev); - - s390_pcihost_setup_msix(pbdev); - - if (dev->hotplugged) { - s390_pci_generate_plug_event(HP_EVENT_RESERVED_TO_STANDBY, - pbdev->fh, pbdev->fid); - s390_pci_generate_plug_event(HP_EVENT_TO_CONFIGURED, - pbdev->fh, pbdev->fid); - } -} - -static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - PCIDevice *pci_dev = PCI_DEVICE(dev); - S390pciState *s = S390_PCI_HOST_BRIDGE(pci_device_root_bus(pci_dev) - ->qbus.parent); - S390PCIBusDevice *pbdev = &s->pbdev[PCI_SLOT(pci_dev->devfn)]; - - if (pbdev->configured) { - pbdev->configured = false; - s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES, - pbdev->fh, pbdev->fid); - } - - s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED, - pbdev->fh, pbdev->fid); - pbdev->fh = 0; - pbdev->fid = 0; - pbdev->pdev = NULL; - object_unparent(OBJECT(pci_dev)); -} - -static void s390_pcihost_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - - dc->cannot_instantiate_with_device_add_yet = true; - k->init = s390_pcihost_init; - hc->plug = s390_pcihost_hot_plug; - hc->unplug = s390_pcihost_hot_unplug; - msi_nonbroken = true; -} - -static const TypeInfo s390_pcihost_info = { - .name = TYPE_S390_PCI_HOST_BRIDGE, - .parent = TYPE_PCI_HOST_BRIDGE, - .instance_size = sizeof(S390pciState), - .class_init = s390_pcihost_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { } - } -}; - -static void s390_pci_register_types(void) -{ - type_register_static(&s390_pcihost_info); -} - -type_init(s390_pci_register_types) diff --git a/qemu/hw/s390x/s390-pci-bus.h b/qemu/hw/s390x/s390-pci-bus.h deleted file mode 100644 index 59fd5c958..000000000 --- a/qemu/hw/s390x/s390-pci-bus.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * s390 PCI BUS definitions - * - * Copyright 2014 IBM Corp. - * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com> - * Hong Bo Li <lihbbj@cn.ibm.com> - * Yi Min Zhao <zyimin@cn.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. - */ - -#ifndef HW_S390_PCI_BUS_H -#define HW_S390_PCI_BUS_H - -#include <hw/pci/pci.h> -#include <hw/pci/pci_host.h> -#include "hw/s390x/sclp.h" -#include "hw/s390x/s390_flic.h" -#include "hw/s390x/css.h" - -#define TYPE_S390_PCI_HOST_BRIDGE "s390-pcihost" -#define FH_VIRT 0x00ff0000 -#define ENABLE_BIT_OFFSET 31 -#define FH_ENABLED (1 << ENABLE_BIT_OFFSET) -#define S390_PCIPT_ADAPTER 2 - -#define S390_PCI_HOST_BRIDGE(obj) \ - OBJECT_CHECK(S390pciState, (obj), TYPE_S390_PCI_HOST_BRIDGE) - -#define HP_EVENT_TO_CONFIGURED 0x0301 -#define HP_EVENT_RESERVED_TO_STANDBY 0x0302 -#define HP_EVENT_CONFIGURED_TO_STBRES 0x0304 -#define HP_EVENT_STANDBY_TO_RESERVED 0x0308 - -#define ERR_EVENT_INVALAS 0x1 -#define ERR_EVENT_OORANGE 0x2 -#define ERR_EVENT_INVALTF 0x3 -#define ERR_EVENT_TPROTE 0x4 -#define ERR_EVENT_APROTE 0x5 -#define ERR_EVENT_KEYE 0x6 -#define ERR_EVENT_INVALTE 0x7 -#define ERR_EVENT_INVALTL 0x8 -#define ERR_EVENT_TT 0x9 -#define ERR_EVENT_INVALMS 0xa -#define ERR_EVENT_SERR 0xb -#define ERR_EVENT_NOMSI 0x10 -#define ERR_EVENT_INVALBV 0x11 -#define ERR_EVENT_AIBV 0x12 -#define ERR_EVENT_AIRERR 0x13 -#define ERR_EVENT_FMBA 0x2a -#define ERR_EVENT_FMBUP 0x2b -#define ERR_EVENT_FMBPRO 0x2c -#define ERR_EVENT_CCONF 0x30 -#define ERR_EVENT_SERVAC 0x3a -#define ERR_EVENT_PERMERR 0x3b - -#define ERR_EVENT_Q_BIT 0x2 -#define ERR_EVENT_MVN_OFFSET 16 - -#define ZPCI_MSI_VEC_BITS 11 -#define ZPCI_MSI_VEC_MASK 0x7ff - -#define ZPCI_MSI_ADDR 0xfe00000000000000ULL -#define ZPCI_SDMA_ADDR 0x100000000ULL -#define ZPCI_EDMA_ADDR 0x1ffffffffffffffULL - -#define PAGE_SHIFT 12 -#define PAGE_MASK (~(PAGE_SIZE-1)) -#define PAGE_DEFAULT_ACC 0 -#define PAGE_DEFAULT_KEY (PAGE_DEFAULT_ACC << 4) - -/* I/O Translation Anchor (IOTA) */ -enum ZpciIoatDtype { - ZPCI_IOTA_STO = 0, - ZPCI_IOTA_RTTO = 1, - ZPCI_IOTA_RSTO = 2, - ZPCI_IOTA_RFTO = 3, - ZPCI_IOTA_PFAA = 4, - ZPCI_IOTA_IOPFAA = 5, - ZPCI_IOTA_IOPTO = 7 -}; - -#define ZPCI_IOTA_IOT_ENABLED 0x800ULL -#define ZPCI_IOTA_DT_ST (ZPCI_IOTA_STO << 2) -#define ZPCI_IOTA_DT_RT (ZPCI_IOTA_RTTO << 2) -#define ZPCI_IOTA_DT_RS (ZPCI_IOTA_RSTO << 2) -#define ZPCI_IOTA_DT_RF (ZPCI_IOTA_RFTO << 2) -#define ZPCI_IOTA_DT_PF (ZPCI_IOTA_PFAA << 2) -#define ZPCI_IOTA_FS_4K 0 -#define ZPCI_IOTA_FS_1M 1 -#define ZPCI_IOTA_FS_2G 2 -#define ZPCI_KEY (PAGE_DEFAULT_KEY << 5) - -#define ZPCI_IOTA_STO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_ST) -#define ZPCI_IOTA_RTTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RT) -#define ZPCI_IOTA_RSTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RS) -#define ZPCI_IOTA_RFTO_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY | ZPCI_IOTA_DT_RF) -#define ZPCI_IOTA_RFAA_FLAG (ZPCI_IOTA_IOT_ENABLED | ZPCI_KEY |\ - ZPCI_IOTA_DT_PF | ZPCI_IOTA_FS_2G) - -/* I/O Region and segment tables */ -#define ZPCI_INDEX_MASK 0x7ffULL - -#define ZPCI_TABLE_TYPE_MASK 0xc -#define ZPCI_TABLE_TYPE_RFX 0xc -#define ZPCI_TABLE_TYPE_RSX 0x8 -#define ZPCI_TABLE_TYPE_RTX 0x4 -#define ZPCI_TABLE_TYPE_SX 0x0 - -#define ZPCI_TABLE_LEN_RFX 0x3 -#define ZPCI_TABLE_LEN_RSX 0x3 -#define ZPCI_TABLE_LEN_RTX 0x3 - -#define ZPCI_TABLE_OFFSET_MASK 0xc0 -#define ZPCI_TABLE_SIZE 0x4000 -#define ZPCI_TABLE_ALIGN ZPCI_TABLE_SIZE -#define ZPCI_TABLE_ENTRY_SIZE (sizeof(unsigned long)) -#define ZPCI_TABLE_ENTRIES (ZPCI_TABLE_SIZE / ZPCI_TABLE_ENTRY_SIZE) - -#define ZPCI_TABLE_BITS 11 -#define ZPCI_PT_BITS 8 -#define ZPCI_ST_SHIFT (ZPCI_PT_BITS + PAGE_SHIFT) -#define ZPCI_RT_SHIFT (ZPCI_ST_SHIFT + ZPCI_TABLE_BITS) - -#define ZPCI_RTE_FLAG_MASK 0x3fffULL -#define ZPCI_RTE_ADDR_MASK (~ZPCI_RTE_FLAG_MASK) -#define ZPCI_STE_FLAG_MASK 0x7ffULL -#define ZPCI_STE_ADDR_MASK (~ZPCI_STE_FLAG_MASK) - -/* I/O Page tables */ -#define ZPCI_PTE_VALID_MASK 0x400 -#define ZPCI_PTE_INVALID 0x400 -#define ZPCI_PTE_VALID 0x000 -#define ZPCI_PT_SIZE 0x800 -#define ZPCI_PT_ALIGN ZPCI_PT_SIZE -#define ZPCI_PT_ENTRIES (ZPCI_PT_SIZE / ZPCI_TABLE_ENTRY_SIZE) -#define ZPCI_PT_MASK (ZPCI_PT_ENTRIES - 1) - -#define ZPCI_PTE_FLAG_MASK 0xfffULL -#define ZPCI_PTE_ADDR_MASK (~ZPCI_PTE_FLAG_MASK) - -/* Shared bits */ -#define ZPCI_TABLE_VALID 0x00 -#define ZPCI_TABLE_INVALID 0x20 -#define ZPCI_TABLE_PROTECTED 0x200 -#define ZPCI_TABLE_UNPROTECTED 0x000 - -#define ZPCI_TABLE_VALID_MASK 0x20 -#define ZPCI_TABLE_PROT_MASK 0x200 - -typedef struct SeiContainer { - QTAILQ_ENTRY(SeiContainer) link; - uint32_t fid; - uint32_t fh; - uint8_t cc; - uint16_t pec; - uint64_t faddr; - uint32_t e; -} SeiContainer; - -typedef struct PciCcdfErr { - uint32_t reserved1; - uint32_t fh; - uint32_t fid; - uint32_t e; - uint64_t faddr; - uint32_t reserved3; - uint16_t reserved4; - uint16_t pec; -} QEMU_PACKED PciCcdfErr; - -typedef struct PciCcdfAvail { - uint32_t reserved1; - uint32_t fh; - uint32_t fid; - uint32_t reserved2; - uint32_t reserved3; - uint32_t reserved4; - uint32_t reserved5; - uint16_t reserved6; - uint16_t pec; -} QEMU_PACKED PciCcdfAvail; - -typedef struct ChscSeiNt2Res { - uint16_t length; - uint16_t code; - uint16_t reserved1; - uint8_t reserved2; - uint8_t nt; - uint8_t flags; - uint8_t reserved3; - uint8_t reserved4; - uint8_t cc; - uint32_t reserved5[13]; - uint8_t ccdf[4016]; -} QEMU_PACKED ChscSeiNt2Res; - -typedef struct PciCfgSccb { - SCCBHeader header; - uint8_t atype; - uint8_t reserved1; - uint16_t reserved2; - uint32_t aid; -} QEMU_PACKED PciCfgSccb; - -typedef struct S390MsixInfo { - bool available; - uint8_t table_bar; - uint8_t pba_bar; - uint16_t entries; - uint32_t table_offset; - uint32_t pba_offset; -} S390MsixInfo; - -typedef struct S390PCIBusDevice { - PCIDevice *pdev; - bool configured; - bool error_state; - bool lgstg_blocked; - uint32_t fh; - uint32_t fid; - uint64_t g_iota; - uint64_t pba; - uint64_t pal; - uint64_t fmb_addr; - uint8_t isc; - uint16_t noi; - uint8_t sum; - S390MsixInfo msix; - AdapterRoutes routes; - AddressSpace as; - MemoryRegion mr; - MemoryRegion iommu_mr; - IndAddr *summary_ind; - IndAddr *indicator; -} S390PCIBusDevice; - -typedef struct S390pciState { - PCIHostState parent_obj; - S390PCIBusDevice pbdev[PCI_SLOT_MAX]; - AddressSpace msix_notify_as; - MemoryRegion msix_notify_mr; - QTAILQ_HEAD(, SeiContainer) pending_sei; -} S390pciState; - -int chsc_sei_nt2_get_event(void *res); -int chsc_sei_nt2_have_event(void); -void s390_pci_sclp_configure(int configure, SCCB *sccb); -void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable); -S390PCIBusDevice *s390_pci_find_dev_by_idx(uint32_t idx); -S390PCIBusDevice *s390_pci_find_dev_by_fh(uint32_t fh); -S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid); - -#endif diff --git a/qemu/hw/s390x/s390-pci-inst.c b/qemu/hw/s390x/s390-pci-inst.c deleted file mode 100644 index b28e7d14f..000000000 --- a/qemu/hw/s390x/s390-pci-inst.c +++ /dev/null @@ -1,846 +0,0 @@ -/* - * s390 PCI instructions - * - * Copyright 2014 IBM Corp. - * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com> - * Hong Bo Li <lihbbj@cn.ibm.com> - * Yi Min Zhao <zyimin@cn.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 "qemu-common.h" -#include "cpu.h" -#include "s390-pci-inst.h" -#include "s390-pci-bus.h" -#include <exec/memory-internal.h> -#include <qemu/error-report.h> - -/* #define DEBUG_S390PCI_INST */ -#ifdef DEBUG_S390PCI_INST -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, "s390pci-inst: " fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - -static void s390_set_status_code(CPUS390XState *env, - uint8_t r, uint64_t status_code) -{ - env->regs[r] &= ~0xff000000ULL; - env->regs[r] |= (status_code & 0xff) << 24; -} - -static int list_pci(ClpReqRspListPci *rrb, uint8_t *cc) -{ - S390PCIBusDevice *pbdev; - uint32_t res_code, initial_l2, g_l2, finish; - int rc, idx; - uint64_t resume_token; - - rc = 0; - if (lduw_p(&rrb->request.hdr.len) != 32) { - res_code = CLP_RC_LEN; - rc = -EINVAL; - goto out; - } - - if ((ldl_p(&rrb->request.fmt) & CLP_MASK_FMT) != 0) { - res_code = CLP_RC_FMT; - rc = -EINVAL; - goto out; - } - - if ((ldl_p(&rrb->request.fmt) & ~CLP_MASK_FMT) != 0 || - ldq_p(&rrb->request.reserved1) != 0 || - ldq_p(&rrb->request.reserved2) != 0) { - res_code = CLP_RC_RESNOT0; - rc = -EINVAL; - goto out; - } - - resume_token = ldq_p(&rrb->request.resume_token); - - if (resume_token) { - pbdev = s390_pci_find_dev_by_idx(resume_token); - if (!pbdev) { - res_code = CLP_RC_LISTPCI_BADRT; - rc = -EINVAL; - goto out; - } - } - - if (lduw_p(&rrb->response.hdr.len) < 48) { - res_code = CLP_RC_8K; - rc = -EINVAL; - goto out; - } - - initial_l2 = lduw_p(&rrb->response.hdr.len); - if ((initial_l2 - LIST_PCI_HDR_LEN) % sizeof(ClpFhListEntry) - != 0) { - res_code = CLP_RC_LEN; - rc = -EINVAL; - *cc = 3; - goto out; - } - - stl_p(&rrb->response.fmt, 0); - stq_p(&rrb->response.reserved1, 0); - stq_p(&rrb->response.reserved2, 0); - stl_p(&rrb->response.mdd, FH_VIRT); - stw_p(&rrb->response.max_fn, PCI_MAX_FUNCTIONS); - rrb->response.entry_size = sizeof(ClpFhListEntry); - finish = 0; - idx = resume_token; - g_l2 = LIST_PCI_HDR_LEN; - do { - pbdev = s390_pci_find_dev_by_idx(idx); - if (!pbdev) { - finish = 1; - break; - } - stw_p(&rrb->response.fh_list[idx - resume_token].device_id, - pci_get_word(pbdev->pdev->config + PCI_DEVICE_ID)); - stw_p(&rrb->response.fh_list[idx - resume_token].vendor_id, - pci_get_word(pbdev->pdev->config + PCI_VENDOR_ID)); - stl_p(&rrb->response.fh_list[idx - resume_token].config, - pbdev->configured << 31); - stl_p(&rrb->response.fh_list[idx - resume_token].fid, pbdev->fid); - stl_p(&rrb->response.fh_list[idx - resume_token].fh, pbdev->fh); - - g_l2 += sizeof(ClpFhListEntry); - /* Add endian check for DPRINTF? */ - DPRINTF("g_l2 %d vendor id 0x%x device id 0x%x fid 0x%x fh 0x%x\n", - g_l2, - lduw_p(&rrb->response.fh_list[idx - resume_token].vendor_id), - lduw_p(&rrb->response.fh_list[idx - resume_token].device_id), - ldl_p(&rrb->response.fh_list[idx - resume_token].fid), - ldl_p(&rrb->response.fh_list[idx - resume_token].fh)); - idx++; - } while (g_l2 < initial_l2); - - if (finish == 1) { - resume_token = 0; - } else { - resume_token = idx; - } - stq_p(&rrb->response.resume_token, resume_token); - stw_p(&rrb->response.hdr.len, g_l2); - stw_p(&rrb->response.hdr.rsp, CLP_RC_OK); -out: - if (rc) { - DPRINTF("list pci failed rc 0x%x\n", rc); - stw_p(&rrb->response.hdr.rsp, res_code); - } - return rc; -} - -int clp_service_call(S390CPU *cpu, uint8_t r2) -{ - ClpReqHdr *reqh; - ClpRspHdr *resh; - S390PCIBusDevice *pbdev; - uint32_t req_len; - uint32_t res_len; - uint8_t buffer[4096 * 2]; - uint8_t cc = 0; - CPUS390XState *env = &cpu->env; - int i; - - cpu_synchronize_state(CPU(cpu)); - - if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); - return 0; - } - - if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, sizeof(*reqh))) { - return 0; - } - reqh = (ClpReqHdr *)buffer; - req_len = lduw_p(&reqh->len); - if (req_len < 16 || req_len > 8184 || (req_len % 8 != 0)) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - - if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, - req_len + sizeof(*resh))) { - return 0; - } - resh = (ClpRspHdr *)(buffer + req_len); - res_len = lduw_p(&resh->len); - if (res_len < 8 || res_len > 8176 || (res_len % 8 != 0)) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - if ((req_len + res_len) > 8192) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - - if (s390_cpu_virt_mem_read(cpu, env->regs[r2], r2, buffer, - req_len + res_len)) { - return 0; - } - - if (req_len != 32) { - stw_p(&resh->rsp, CLP_RC_LEN); - goto out; - } - - switch (lduw_p(&reqh->cmd)) { - case CLP_LIST_PCI: { - ClpReqRspListPci *rrb = (ClpReqRspListPci *)buffer; - list_pci(rrb, &cc); - break; - } - case CLP_SET_PCI_FN: { - ClpReqSetPci *reqsetpci = (ClpReqSetPci *)reqh; - ClpRspSetPci *ressetpci = (ClpRspSetPci *)resh; - - pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqsetpci->fh)); - if (!pbdev) { - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FH); - goto out; - } - - switch (reqsetpci->oc) { - case CLP_SET_ENABLE_PCI_FN: - pbdev->fh = pbdev->fh | FH_ENABLED; - stl_p(&ressetpci->fh, pbdev->fh); - stw_p(&ressetpci->hdr.rsp, CLP_RC_OK); - break; - case CLP_SET_DISABLE_PCI_FN: - pbdev->fh = pbdev->fh & ~FH_ENABLED; - pbdev->error_state = false; - pbdev->lgstg_blocked = false; - stl_p(&ressetpci->fh, pbdev->fh); - stw_p(&ressetpci->hdr.rsp, CLP_RC_OK); - break; - default: - DPRINTF("unknown set pci command\n"); - stw_p(&ressetpci->hdr.rsp, CLP_RC_SETPCIFN_FHOP); - break; - } - break; - } - case CLP_QUERY_PCI_FN: { - ClpReqQueryPci *reqquery = (ClpReqQueryPci *)reqh; - ClpRspQueryPci *resquery = (ClpRspQueryPci *)resh; - - pbdev = s390_pci_find_dev_by_fh(ldl_p(&reqquery->fh)); - if (!pbdev) { - DPRINTF("query pci no pci dev\n"); - stw_p(&resquery->hdr.rsp, CLP_RC_SETPCIFN_FH); - goto out; - } - - for (i = 0; i < PCI_BAR_COUNT; i++) { - uint32_t data = pci_get_long(pbdev->pdev->config + - PCI_BASE_ADDRESS_0 + (i * 4)); - - stl_p(&resquery->bar[i], data); - resquery->bar_size[i] = pbdev->pdev->io_regions[i].size ? - ctz64(pbdev->pdev->io_regions[i].size) : 0; - DPRINTF("bar %d addr 0x%x size 0x%" PRIx64 "barsize 0x%x\n", i, - ldl_p(&resquery->bar[i]), - pbdev->pdev->io_regions[i].size, - resquery->bar_size[i]); - } - - stq_p(&resquery->sdma, ZPCI_SDMA_ADDR); - stq_p(&resquery->edma, ZPCI_EDMA_ADDR); - stw_p(&resquery->pchid, 0); - stw_p(&resquery->ug, 1); - stl_p(&resquery->uid, pbdev->fid); - stw_p(&resquery->hdr.rsp, CLP_RC_OK); - break; - } - case CLP_QUERY_PCI_FNGRP: { - ClpRspQueryPciGrp *resgrp = (ClpRspQueryPciGrp *)resh; - resgrp->fr = 1; - stq_p(&resgrp->dasm, 0); - stq_p(&resgrp->msia, ZPCI_MSI_ADDR); - stw_p(&resgrp->mui, 0); - stw_p(&resgrp->i, 128); - resgrp->version = 0; - - stw_p(&resgrp->hdr.rsp, CLP_RC_OK); - break; - } - default: - DPRINTF("unknown clp command\n"); - stw_p(&resh->rsp, CLP_RC_CMD); - break; - } - -out: - if (s390_cpu_virt_mem_write(cpu, env->regs[r2], r2, buffer, - req_len + res_len)) { - return 0; - } - setcc(cpu, cc); - return 0; -} - -int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) -{ - CPUS390XState *env = &cpu->env; - S390PCIBusDevice *pbdev; - uint64_t offset; - uint64_t data; - uint8_t len; - uint32_t fh; - uint8_t pcias; - - cpu_synchronize_state(CPU(cpu)); - - if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); - return 0; - } - - if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); - return 0; - } - - fh = env->regs[r2] >> 32; - pcias = (env->regs[r2] >> 16) & 0xf; - len = env->regs[r2] & 0xf; - offset = env->regs[r2 + 1]; - - pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev || !(pbdev->fh & FH_ENABLED)) { - DPRINTF("pcilg no pci dev\n"); - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - } - - if (pbdev->lgstg_blocked) { - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); - return 0; - } - - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - MemoryRegion *mr = pbdev->pdev->io_regions[pcias].memory; - memory_region_dispatch_read(mr, offset, &data, len, - MEMTXATTRS_UNSPECIFIED); - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - data = pci_host_config_read_common( - pbdev->pdev, offset, pci_config_size(pbdev->pdev), len); - - switch (len) { - case 1: - break; - case 2: - data = bswap16(data); - break; - case 4: - data = bswap32(data); - break; - case 8: - data = bswap64(data); - break; - default: - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - } else { - DPRINTF("invalid space\n"); - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS); - return 0; - } - - env->regs[r1] = data; - setcc(cpu, ZPCI_PCI_LS_OK); - return 0; -} - -static void update_msix_table_msg_data(S390PCIBusDevice *pbdev, uint64_t offset, - uint64_t *data, uint8_t len) -{ - uint32_t val; - uint8_t *msg_data; - - if (offset % PCI_MSIX_ENTRY_SIZE != 8) { - return; - } - - if (len != 4) { - DPRINTF("access msix table msg data but len is %d\n", len); - return; - } - - msg_data = (uint8_t *)data - offset % PCI_MSIX_ENTRY_SIZE + - PCI_MSIX_ENTRY_VECTOR_CTRL; - val = pci_get_long(msg_data) | (pbdev->fid << ZPCI_MSI_VEC_BITS); - pci_set_long(msg_data, val); - DPRINTF("update msix msg_data to 0x%" PRIx64 "\n", *data); -} - -static int trap_msix(S390PCIBusDevice *pbdev, uint64_t offset, uint8_t pcias) -{ - if (pbdev->msix.available && pbdev->msix.table_bar == pcias && - offset >= pbdev->msix.table_offset && - offset <= pbdev->msix.table_offset + - (pbdev->msix.entries - 1) * PCI_MSIX_ENTRY_SIZE) { - return 1; - } else { - return 0; - } -} - -int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) -{ - CPUS390XState *env = &cpu->env; - uint64_t offset, data; - S390PCIBusDevice *pbdev; - uint8_t len; - uint32_t fh; - uint8_t pcias; - - cpu_synchronize_state(CPU(cpu)); - - if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); - return 0; - } - - if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); - return 0; - } - - fh = env->regs[r2] >> 32; - pcias = (env->regs[r2] >> 16) & 0xf; - len = env->regs[r2] & 0xf; - offset = env->regs[r2 + 1]; - - pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev || !(pbdev->fh & FH_ENABLED)) { - DPRINTF("pcistg no pci dev\n"); - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - } - - if (pbdev->lgstg_blocked) { - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r2, ZPCI_PCI_ST_BLOCKED); - return 0; - } - - data = env->regs[r1]; - if (pcias < 6) { - if ((8 - (offset & 0x7)) < len) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - MemoryRegion *mr; - if (trap_msix(pbdev, offset, pcias)) { - offset = offset - pbdev->msix.table_offset; - mr = &pbdev->pdev->msix_table_mmio; - update_msix_table_msg_data(pbdev, offset, &data, len); - } else { - mr = pbdev->pdev->io_regions[pcias].memory; - } - - memory_region_dispatch_write(mr, offset, data, len, - MEMTXATTRS_UNSPECIFIED); - } else if (pcias == 15) { - if ((4 - (offset & 0x3)) < len) { - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - switch (len) { - case 1: - break; - case 2: - data = bswap16(data); - break; - case 4: - data = bswap32(data); - break; - case 8: - data = bswap64(data); - break; - default: - program_interrupt(env, PGM_OPERAND, 4); - return 0; - } - - pci_host_config_write_common(pbdev->pdev, offset, - pci_config_size(pbdev->pdev), - data, len); - } else { - DPRINTF("pcistg invalid space\n"); - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r2, ZPCI_PCI_ST_INVAL_AS); - return 0; - } - - setcc(cpu, ZPCI_PCI_LS_OK); - return 0; -} - -int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2) -{ - CPUS390XState *env = &cpu->env; - uint32_t fh; - S390PCIBusDevice *pbdev; - hwaddr start, end; - IOMMUTLBEntry entry; - MemoryRegion *mr; - - cpu_synchronize_state(CPU(cpu)); - - if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 4); - goto out; - } - - if (r2 & 0x1) { - program_interrupt(env, PGM_SPECIFICATION, 4); - goto out; - } - - fh = env->regs[r1] >> 32; - start = env->regs[r2]; - end = start + env->regs[r2 + 1]; - - pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev || !(pbdev->fh & FH_ENABLED)) { - DPRINTF("rpcit no pci dev\n"); - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - goto out; - } - - mr = &pbdev->iommu_mr; - while (start < end) { - entry = mr->iommu_ops->translate(mr, start, 0); - - if (!entry.translated_addr) { - setcc(cpu, ZPCI_PCI_LS_ERR); - goto out; - } - - memory_region_notify_iommu(mr, entry); - start += entry.addr_mask + 1; - } - - setcc(cpu, ZPCI_PCI_LS_OK); -out: - return 0; -} - -int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, - uint8_t ar) -{ - CPUS390XState *env = &cpu->env; - S390PCIBusDevice *pbdev; - MemoryRegion *mr; - int i; - uint32_t fh; - uint8_t pcias; - uint8_t len; - uint8_t buffer[128]; - - if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); - return 0; - } - - fh = env->regs[r1] >> 32; - pcias = (env->regs[r1] >> 16) & 0xf; - len = env->regs[r1] & 0xff; - - if (pcias > 5) { - DPRINTF("pcistb invalid space\n"); - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_INVAL_AS); - return 0; - } - - switch (len) { - case 16: - case 32: - case 64: - case 128: - break; - default: - program_interrupt(env, PGM_SPECIFICATION, 6); - return 0; - } - - pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev || !(pbdev->fh & FH_ENABLED)) { - DPRINTF("pcistb no pci dev fh 0x%x\n", fh); - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - } - - if (pbdev->lgstg_blocked) { - setcc(cpu, ZPCI_PCI_LS_ERR); - s390_set_status_code(env, r1, ZPCI_PCI_ST_BLOCKED); - return 0; - } - - mr = pbdev->pdev->io_regions[pcias].memory; - if (!memory_region_access_valid(mr, env->regs[r3], len, true)) { - program_interrupt(env, PGM_ADDRESSING, 6); - return 0; - } - - if (s390_cpu_virt_mem_read(cpu, gaddr, ar, buffer, len)) { - return 0; - } - - for (i = 0; i < len / 8; i++) { - memory_region_dispatch_write(mr, env->regs[r3] + i * 8, - ldq_p(buffer + i * 8), 8, - MEMTXATTRS_UNSPECIFIED); - } - - setcc(cpu, ZPCI_PCI_LS_OK); - return 0; -} - -static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) -{ - int ret, len; - - ret = css_register_io_adapter(S390_PCIPT_ADAPTER, - FIB_DATA_ISC(ldl_p(&fib.data)), true, false, - &pbdev->routes.adapter.adapter_id); - assert(ret == 0); - - pbdev->summary_ind = get_indicator(ldq_p(&fib.aisb), sizeof(uint64_t)); - len = BITS_TO_LONGS(FIB_DATA_NOI(ldl_p(&fib.data))) * sizeof(unsigned long); - pbdev->indicator = get_indicator(ldq_p(&fib.aibv), len); - - map_indicator(&pbdev->routes.adapter, pbdev->summary_ind); - map_indicator(&pbdev->routes.adapter, pbdev->indicator); - - pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb); - pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data)); - pbdev->routes.adapter.ind_addr = ldq_p(&fib.aibv); - pbdev->routes.adapter.ind_offset = FIB_DATA_AIBVO(ldl_p(&fib.data)); - pbdev->isc = FIB_DATA_ISC(ldl_p(&fib.data)); - pbdev->noi = FIB_DATA_NOI(ldl_p(&fib.data)); - pbdev->sum = FIB_DATA_SUM(ldl_p(&fib.data)); - - DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id); - return 0; -} - -static int dereg_irqs(S390PCIBusDevice *pbdev) -{ - release_indicator(&pbdev->routes.adapter, pbdev->summary_ind); - release_indicator(&pbdev->routes.adapter, pbdev->indicator); - - pbdev->summary_ind = NULL; - pbdev->indicator = NULL; - pbdev->routes.adapter.summary_addr = 0; - pbdev->routes.adapter.summary_offset = 0; - pbdev->routes.adapter.ind_addr = 0; - pbdev->routes.adapter.ind_offset = 0; - pbdev->isc = 0; - pbdev->noi = 0; - pbdev->sum = 0; - - DPRINTF("dereg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id); - return 0; -} - -static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib) -{ - uint64_t pba = ldq_p(&fib.pba); - uint64_t pal = ldq_p(&fib.pal); - uint64_t g_iota = ldq_p(&fib.iota); - uint8_t dt = (g_iota >> 2) & 0x7; - uint8_t t = (g_iota >> 11) & 0x1; - - if (pba > pal || pba < ZPCI_SDMA_ADDR || pal > ZPCI_EDMA_ADDR) { - program_interrupt(env, PGM_OPERAND, 6); - return -EINVAL; - } - - /* currently we only support designation type 1 with translation */ - if (!(dt == ZPCI_IOTA_RTTO && t)) { - error_report("unsupported ioat dt %d t %d", dt, t); - program_interrupt(env, PGM_OPERAND, 6); - return -EINVAL; - } - - pbdev->pba = pba; - pbdev->pal = pal; - pbdev->g_iota = g_iota; - - s390_pcihost_iommu_configure(pbdev, true); - - return 0; -} - -static void dereg_ioat(S390PCIBusDevice *pbdev) -{ - pbdev->pba = 0; - pbdev->pal = 0; - pbdev->g_iota = 0; - - s390_pcihost_iommu_configure(pbdev, false); -} - -int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) -{ - CPUS390XState *env = &cpu->env; - uint8_t oc; - uint32_t fh; - ZpciFib fib; - S390PCIBusDevice *pbdev; - uint64_t cc = ZPCI_PCI_LS_OK; - - if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); - return 0; - } - - oc = env->regs[r1] & 0xff; - fh = env->regs[r1] >> 32; - - if (fiba & 0x7) { - program_interrupt(env, PGM_SPECIFICATION, 6); - return 0; - } - - pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev || !(pbdev->fh & FH_ENABLED)) { - DPRINTF("mpcifc no pci dev fh 0x%x\n", fh); - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - } - - if (s390_cpu_virt_mem_read(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { - return 0; - } - - switch (oc) { - case ZPCI_MOD_FC_REG_INT: - if (reg_irqs(env, pbdev, fib)) { - cc = ZPCI_PCI_LS_ERR; - } - break; - case ZPCI_MOD_FC_DEREG_INT: - dereg_irqs(pbdev); - break; - case ZPCI_MOD_FC_REG_IOAT: - if (reg_ioat(env, pbdev, fib)) { - cc = ZPCI_PCI_LS_ERR; - } - break; - case ZPCI_MOD_FC_DEREG_IOAT: - dereg_ioat(pbdev); - break; - case ZPCI_MOD_FC_REREG_IOAT: - dereg_ioat(pbdev); - if (reg_ioat(env, pbdev, fib)) { - cc = ZPCI_PCI_LS_ERR; - } - break; - case ZPCI_MOD_FC_RESET_ERROR: - pbdev->error_state = false; - pbdev->lgstg_blocked = false; - break; - case ZPCI_MOD_FC_RESET_BLOCK: - pbdev->lgstg_blocked = false; - break; - case ZPCI_MOD_FC_SET_MEASURE: - pbdev->fmb_addr = ldq_p(&fib.fmb_addr); - break; - default: - program_interrupt(&cpu->env, PGM_OPERAND, 6); - cc = ZPCI_PCI_LS_ERR; - } - - setcc(cpu, cc); - return 0; -} - -int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar) -{ - CPUS390XState *env = &cpu->env; - uint32_t fh; - ZpciFib fib; - S390PCIBusDevice *pbdev; - uint32_t data; - uint64_t cc = ZPCI_PCI_LS_OK; - - if (env->psw.mask & PSW_MASK_PSTATE) { - program_interrupt(env, PGM_PRIVILEGED, 6); - return 0; - } - - fh = env->regs[r1] >> 32; - - if (fiba & 0x7) { - program_interrupt(env, PGM_SPECIFICATION, 6); - return 0; - } - - pbdev = s390_pci_find_dev_by_fh(fh); - if (!pbdev) { - setcc(cpu, ZPCI_PCI_LS_INVAL_HANDLE); - return 0; - } - - memset(&fib, 0, sizeof(fib)); - stq_p(&fib.pba, pbdev->pba); - stq_p(&fib.pal, pbdev->pal); - stq_p(&fib.iota, pbdev->g_iota); - stq_p(&fib.aibv, pbdev->routes.adapter.ind_addr); - stq_p(&fib.aisb, pbdev->routes.adapter.summary_addr); - stq_p(&fib.fmb_addr, pbdev->fmb_addr); - - data = ((uint32_t)pbdev->isc << 28) | ((uint32_t)pbdev->noi << 16) | - ((uint32_t)pbdev->routes.adapter.ind_offset << 8) | - ((uint32_t)pbdev->sum << 7) | pbdev->routes.adapter.summary_offset; - stl_p(&fib.data, data); - - if (pbdev->fh & FH_ENABLED) { - fib.fc |= 0x80; - } - - if (pbdev->error_state) { - fib.fc |= 0x40; - } - - if (pbdev->lgstg_blocked) { - fib.fc |= 0x20; - } - - if (pbdev->g_iota) { - fib.fc |= 0x10; - } - - if (s390_cpu_virt_mem_write(cpu, fiba, ar, (uint8_t *)&fib, sizeof(fib))) { - return 0; - } - - setcc(cpu, cc); - return 0; -} diff --git a/qemu/hw/s390x/s390-pci-inst.h b/qemu/hw/s390x/s390-pci-inst.h deleted file mode 100644 index 70fa71395..000000000 --- a/qemu/hw/s390x/s390-pci-inst.h +++ /dev/null @@ -1,289 +0,0 @@ -/* - * s390 PCI instruction definitions - * - * Copyright 2014 IBM Corp. - * Author(s): Frank Blaschka <frank.blaschka@de.ibm.com> - * Hong Bo Li <lihbbj@cn.ibm.com> - * Yi Min Zhao <zyimin@cn.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. - */ - -#ifndef HW_S390_PCI_INST_H -#define HW_S390_PCI_INST_H - -#include <sysemu/dma.h> - -/* CLP common request & response block size */ -#define CLP_BLK_SIZE 4096 -#define PCI_BAR_COUNT 6 -#define PCI_MAX_FUNCTIONS 4096 - -typedef struct ClpReqHdr { - uint16_t len; - uint16_t cmd; -} QEMU_PACKED ClpReqHdr; - -typedef struct ClpRspHdr { - uint16_t len; - uint16_t rsp; -} QEMU_PACKED ClpRspHdr; - -/* CLP Response Codes */ -#define CLP_RC_OK 0x0010 /* Command request successfully */ -#define CLP_RC_CMD 0x0020 /* Command code not recognized */ -#define CLP_RC_PERM 0x0030 /* Command not authorized */ -#define CLP_RC_FMT 0x0040 /* Invalid command request format */ -#define CLP_RC_LEN 0x0050 /* Invalid command request length */ -#define CLP_RC_8K 0x0060 /* Command requires 8K LPCB */ -#define CLP_RC_RESNOT0 0x0070 /* Reserved field not zero */ -#define CLP_RC_NODATA 0x0080 /* No data available */ -#define CLP_RC_FC_UNKNOWN 0x0100 /* Function code not recognized */ - -/* - * Call Logical Processor - Command Codes - */ -#define CLP_LIST_PCI 0x0002 -#define CLP_QUERY_PCI_FN 0x0003 -#define CLP_QUERY_PCI_FNGRP 0x0004 -#define CLP_SET_PCI_FN 0x0005 - -/* PCI function handle list entry */ -typedef struct ClpFhListEntry { - uint16_t device_id; - uint16_t vendor_id; -#define CLP_FHLIST_MASK_CONFIG 0x80000000 - uint32_t config; - uint32_t fid; - uint32_t fh; -} QEMU_PACKED ClpFhListEntry; - -#define CLP_RC_SETPCIFN_FH 0x0101 /* Invalid PCI fn handle */ -#define CLP_RC_SETPCIFN_FHOP 0x0102 /* Fn handle not valid for op */ -#define CLP_RC_SETPCIFN_DMAAS 0x0103 /* Invalid DMA addr space */ -#define CLP_RC_SETPCIFN_RES 0x0104 /* Insufficient resources */ -#define CLP_RC_SETPCIFN_ALRDY 0x0105 /* Fn already in requested state */ -#define CLP_RC_SETPCIFN_ERR 0x0106 /* Fn in permanent error state */ -#define CLP_RC_SETPCIFN_RECPND 0x0107 /* Error recovery pending */ -#define CLP_RC_SETPCIFN_BUSY 0x0108 /* Fn busy */ -#define CLP_RC_LISTPCI_BADRT 0x010a /* Resume token not recognized */ -#define CLP_RC_QUERYPCIFG_PFGID 0x010b /* Unrecognized PFGID */ - -/* request or response block header length */ -#define LIST_PCI_HDR_LEN 32 - -/* Number of function handles fitting in response block */ -#define CLP_FH_LIST_NR_ENTRIES \ - ((CLP_BLK_SIZE - 2 * LIST_PCI_HDR_LEN) \ - / sizeof(ClpFhListEntry)) - -#define CLP_SET_ENABLE_PCI_FN 0 /* Yes, 0 enables it */ -#define CLP_SET_DISABLE_PCI_FN 1 /* Yes, 1 disables it */ - -#define CLP_UTIL_STR_LEN 64 - -#define CLP_MASK_FMT 0xf0000000 - -/* List PCI functions request */ -typedef struct ClpReqListPci { - ClpReqHdr hdr; - uint32_t fmt; - uint64_t reserved1; - uint64_t resume_token; - uint64_t reserved2; -} QEMU_PACKED ClpReqListPci; - -/* List PCI functions response */ -typedef struct ClpRspListPci { - ClpRspHdr hdr; - uint32_t fmt; - uint64_t reserved1; - uint64_t resume_token; - uint32_t mdd; - uint16_t max_fn; - uint8_t reserved2; - uint8_t entry_size; - ClpFhListEntry fh_list[CLP_FH_LIST_NR_ENTRIES]; -} QEMU_PACKED ClpRspListPci; - -/* Query PCI function request */ -typedef struct ClpReqQueryPci { - ClpReqHdr hdr; - uint32_t fmt; - uint64_t reserved1; - uint32_t fh; /* function handle */ - uint32_t reserved2; - uint64_t reserved3; -} QEMU_PACKED ClpReqQueryPci; - -/* Query PCI function response */ -typedef struct ClpRspQueryPci { - ClpRspHdr hdr; - uint32_t fmt; - uint64_t reserved1; - uint16_t vfn; /* virtual fn number */ -#define CLP_RSP_QPCI_MASK_UTIL 0x100 -#define CLP_RSP_QPCI_MASK_PFGID 0xff - uint16_t ug; - uint32_t fid; /* pci function id */ - uint8_t bar_size[PCI_BAR_COUNT]; - uint16_t pchid; - uint32_t bar[PCI_BAR_COUNT]; - uint64_t reserved2; - uint64_t sdma; /* start dma as */ - uint64_t edma; /* end dma as */ - uint32_t reserved3[11]; - uint32_t uid; - uint8_t util_str[CLP_UTIL_STR_LEN]; /* utility string */ -} QEMU_PACKED ClpRspQueryPci; - -/* Query PCI function group request */ -typedef struct ClpReqQueryPciGrp { - ClpReqHdr hdr; - uint32_t fmt; - uint64_t reserved1; -#define CLP_REQ_QPCIG_MASK_PFGID 0xff - uint32_t g; - uint32_t reserved2; - uint64_t reserved3; -} QEMU_PACKED ClpReqQueryPciGrp; - -/* Query PCI function group response */ -typedef struct ClpRspQueryPciGrp { - ClpRspHdr hdr; - uint32_t fmt; - uint64_t reserved1; -#define CLP_RSP_QPCIG_MASK_NOI 0xfff - uint16_t i; - uint8_t version; -#define CLP_RSP_QPCIG_MASK_FRAME 0x2 -#define CLP_RSP_QPCIG_MASK_REFRESH 0x1 - uint8_t fr; - uint16_t reserved2; - uint16_t mui; - uint64_t reserved3; - uint64_t dasm; /* dma address space mask */ - uint64_t msia; /* MSI address */ - uint64_t reserved4; - uint64_t reserved5; -} QEMU_PACKED ClpRspQueryPciGrp; - -/* Set PCI function request */ -typedef struct ClpReqSetPci { - ClpReqHdr hdr; - uint32_t fmt; - uint64_t reserved1; - uint32_t fh; /* function handle */ - uint16_t reserved2; - uint8_t oc; /* operation controls */ - uint8_t ndas; /* number of dma spaces */ - uint64_t reserved3; -} QEMU_PACKED ClpReqSetPci; - -/* Set PCI function response */ -typedef struct ClpRspSetPci { - ClpRspHdr hdr; - uint32_t fmt; - uint64_t reserved1; - uint32_t fh; /* function handle */ - uint32_t reserved3; - uint64_t reserved4; -} QEMU_PACKED ClpRspSetPci; - -typedef struct ClpReqRspListPci { - ClpReqListPci request; - ClpRspListPci response; -} QEMU_PACKED ClpReqRspListPci; - -typedef struct ClpReqRspSetPci { - ClpReqSetPci request; - ClpRspSetPci response; -} QEMU_PACKED ClpReqRspSetPci; - -typedef struct ClpReqRspQueryPci { - ClpReqQueryPci request; - ClpRspQueryPci response; -} QEMU_PACKED ClpReqRspQueryPci; - -typedef struct ClpReqRspQueryPciGrp { - ClpReqQueryPciGrp request; - ClpRspQueryPciGrp response; -} QEMU_PACKED ClpReqRspQueryPciGrp; - -/* Load/Store status codes */ -#define ZPCI_PCI_ST_FUNC_NOT_ENABLED 4 -#define ZPCI_PCI_ST_FUNC_IN_ERR 8 -#define ZPCI_PCI_ST_BLOCKED 12 -#define ZPCI_PCI_ST_INSUF_RES 16 -#define ZPCI_PCI_ST_INVAL_AS 20 -#define ZPCI_PCI_ST_FUNC_ALREADY_ENABLED 24 -#define ZPCI_PCI_ST_DMA_AS_NOT_ENABLED 28 -#define ZPCI_PCI_ST_2ND_OP_IN_INV_AS 36 -#define ZPCI_PCI_ST_FUNC_NOT_AVAIL 40 -#define ZPCI_PCI_ST_ALREADY_IN_RQ_STATE 44 - -/* Load/Store return codes */ -#define ZPCI_PCI_LS_OK 0 -#define ZPCI_PCI_LS_ERR 1 -#define ZPCI_PCI_LS_BUSY 2 -#define ZPCI_PCI_LS_INVAL_HANDLE 3 - -/* Modify PCI Function Controls */ -#define ZPCI_MOD_FC_REG_INT 2 -#define ZPCI_MOD_FC_DEREG_INT 3 -#define ZPCI_MOD_FC_REG_IOAT 4 -#define ZPCI_MOD_FC_DEREG_IOAT 5 -#define ZPCI_MOD_FC_REREG_IOAT 6 -#define ZPCI_MOD_FC_RESET_ERROR 7 -#define ZPCI_MOD_FC_RESET_BLOCK 9 -#define ZPCI_MOD_FC_SET_MEASURE 10 - -/* FIB function controls */ -#define ZPCI_FIB_FC_ENABLED 0x80 -#define ZPCI_FIB_FC_ERROR 0x40 -#define ZPCI_FIB_FC_LS_BLOCKED 0x20 -#define ZPCI_FIB_FC_DMAAS_REG 0x10 - -/* FIB function controls */ -#define ZPCI_FIB_FC_ENABLED 0x80 -#define ZPCI_FIB_FC_ERROR 0x40 -#define ZPCI_FIB_FC_LS_BLOCKED 0x20 -#define ZPCI_FIB_FC_DMAAS_REG 0x10 - -/* Function Information Block */ -typedef struct ZpciFib { - uint8_t fmt; /* format */ - uint8_t reserved1[7]; - uint8_t fc; /* function controls */ - uint8_t reserved2; - uint16_t reserved3; - uint32_t reserved4; - uint64_t pba; /* PCI base address */ - uint64_t pal; /* PCI address limit */ - uint64_t iota; /* I/O Translation Anchor */ -#define FIB_DATA_ISC(x) (((x) >> 28) & 0x7) -#define FIB_DATA_NOI(x) (((x) >> 16) & 0xfff) -#define FIB_DATA_AIBVO(x) (((x) >> 8) & 0x3f) -#define FIB_DATA_SUM(x) (((x) >> 7) & 0x1) -#define FIB_DATA_AISBO(x) ((x) & 0x3f) - uint32_t data; - uint32_t reserved5; - uint64_t aibv; /* Adapter int bit vector address */ - uint64_t aisb; /* Adapter int summary bit address */ - uint64_t fmb_addr; /* Function measurement address and key */ - uint32_t reserved6; - uint32_t gd; -} QEMU_PACKED ZpciFib; - -int clp_service_call(S390CPU *cpu, uint8_t r2); -int pcilg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); -int pcistg_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); -int rpcit_service_call(S390CPU *cpu, uint8_t r1, uint8_t r2); -int pcistb_service_call(S390CPU *cpu, uint8_t r1, uint8_t r3, uint64_t gaddr, - uint8_t ar); -int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar); -int stpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar); - -#endif diff --git a/qemu/hw/s390x/s390-skeys-kvm.c b/qemu/hw/s390x/s390-skeys-kvm.c deleted file mode 100644 index 131da56bb..000000000 --- a/qemu/hw/s390x/s390-skeys-kvm.c +++ /dev/null @@ -1,76 +0,0 @@ -/* - * s390 storage key device - * - * Copyright 2015 IBM Corp. - * Author(s): Jason J. Herne <jjherne@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 "hw/s390x/storage-keys.h" -#include "sysemu/kvm.h" -#include "qemu/error-report.h" - -static int kvm_s390_skeys_enabled(S390SKeysState *ss) -{ - S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); - uint8_t single_key; - int r; - - r = skeyclass->get_skeys(ss, 0, 1, &single_key); - if (r != 0 && r != KVM_S390_GET_SKEYS_NONE) { - error_report("S390_GET_KEYS error %d", r); - } - return (r == 0); -} - -static int kvm_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, - uint64_t count, uint8_t *keys) -{ - struct kvm_s390_skeys args = { - .start_gfn = start_gfn, - .count = count, - .skeydata_addr = (__u64)keys - }; - - return kvm_vm_ioctl(kvm_state, KVM_S390_GET_SKEYS, &args); -} - -static int kvm_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, - uint64_t count, uint8_t *keys) -{ - struct kvm_s390_skeys args = { - .start_gfn = start_gfn, - .count = count, - .skeydata_addr = (__u64)keys - }; - - return kvm_vm_ioctl(kvm_state, KVM_S390_SET_SKEYS, &args); -} - -static void kvm_s390_skeys_class_init(ObjectClass *oc, void *data) -{ - S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); - - skeyclass->skeys_enabled = kvm_s390_skeys_enabled; - skeyclass->get_skeys = kvm_s390_skeys_get; - skeyclass->set_skeys = kvm_s390_skeys_set; -} - -static const TypeInfo kvm_s390_skeys_info = { - .name = TYPE_KVM_S390_SKEYS, - .parent = TYPE_S390_SKEYS, - .instance_size = sizeof(S390SKeysState), - .class_init = kvm_s390_skeys_class_init, - .class_size = sizeof(S390SKeysClass), -}; - -static void kvm_s390_skeys_register_types(void) -{ - type_register_static(&kvm_s390_skeys_info); -} - -type_init(kvm_s390_skeys_register_types) diff --git a/qemu/hw/s390x/s390-skeys.c b/qemu/hw/s390x/s390-skeys.c deleted file mode 100644 index 6528ffed1..000000000 --- a/qemu/hw/s390x/s390-skeys.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * s390 storage key device - * - * Copyright 2015 IBM Corp. - * Author(s): Jason J. Herne <jjherne@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 "hw/boards.h" -#include "qmp-commands.h" -#include "migration/qemu-file.h" -#include "hw/s390x/storage-keys.h" -#include "qemu/error-report.h" - -#define S390_SKEYS_BUFFER_SIZE 131072 /* Room for 128k storage keys */ -#define S390_SKEYS_SAVE_FLAG_EOS 0x01 -#define S390_SKEYS_SAVE_FLAG_SKEYS 0x02 -#define S390_SKEYS_SAVE_FLAG_ERROR 0x04 - -S390SKeysState *s390_get_skeys_device(void) -{ - S390SKeysState *ss; - - ss = S390_SKEYS(object_resolve_path_type("", TYPE_S390_SKEYS, NULL)); - assert(ss); - return ss; -} - -void s390_skeys_init(void) -{ - Object *obj; - - if (kvm_enabled()) { - obj = object_new(TYPE_KVM_S390_SKEYS); - } else { - obj = object_new(TYPE_QEMU_S390_SKEYS); - } - object_property_add_child(qdev_get_machine(), TYPE_S390_SKEYS, - obj, NULL); - object_unref(obj); - - qdev_init_nofail(DEVICE(obj)); -} - -static void write_keys(QEMUFile *f, uint8_t *keys, uint64_t startgfn, - uint64_t count, Error **errp) -{ - uint64_t curpage = startgfn; - uint64_t maxpage = curpage + count - 1; - const char *fmt = "page=%03" PRIx64 ": key(%d) => ACC=%X, FP=%d, REF=%d," - " ch=%d, reserved=%d\n"; - char buf[128]; - int len; - - for (; curpage <= maxpage; curpage++) { - uint8_t acc = (*keys & 0xF0) >> 4; - int fp = (*keys & 0x08); - int ref = (*keys & 0x04); - int ch = (*keys & 0x02); - int res = (*keys & 0x01); - - len = snprintf(buf, sizeof(buf), fmt, curpage, - *keys, acc, fp, ref, ch, res); - assert(len < sizeof(buf)); - qemu_put_buffer(f, (uint8_t *)buf, len); - keys++; - } -} - -void hmp_info_skeys(Monitor *mon, const QDict *qdict) -{ - S390SKeysState *ss = s390_get_skeys_device(); - S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); - uint64_t addr = qdict_get_int(qdict, "addr"); - uint8_t key; - int r; - - /* Quick check to see if guest is using storage keys*/ - if (!skeyclass->skeys_enabled(ss)) { - monitor_printf(mon, "Error: This guest is not using storage keys\n"); - return; - } - - r = skeyclass->get_skeys(ss, addr / TARGET_PAGE_SIZE, 1, &key); - if (r < 0) { - monitor_printf(mon, "Error: %s\n", strerror(-r)); - return; - } - - monitor_printf(mon, " key: 0x%X\n", key); -} - -void hmp_dump_skeys(Monitor *mon, const QDict *qdict) -{ - const char *filename = qdict_get_str(qdict, "filename"); - Error *err = NULL; - - qmp_dump_skeys(filename, &err); - if (err) { - error_report_err(err); - } -} - -void qmp_dump_skeys(const char *filename, Error **errp) -{ - S390SKeysState *ss = s390_get_skeys_device(); - S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); - const uint64_t total_count = ram_size / TARGET_PAGE_SIZE; - uint64_t handled_count = 0, cur_count; - Error *lerr = NULL; - vaddr cur_gfn = 0; - uint8_t *buf; - int ret; - QEMUFile *f; - - /* Quick check to see if guest is using storage keys*/ - if (!skeyclass->skeys_enabled(ss)) { - error_setg(errp, "This guest is not using storage keys - " - "nothing to dump"); - return; - } - - f = qemu_fopen(filename, "wb"); - if (!f) { - error_setg_file_open(errp, errno, filename); - return; - } - - buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); - if (!buf) { - error_setg(errp, "Could not allocate memory"); - goto out; - } - - /* we'll only dump initial memory for now */ - while (handled_count < total_count) { - /* Calculate how many keys to ask for & handle overflow case */ - cur_count = MIN(total_count - handled_count, S390_SKEYS_BUFFER_SIZE); - - ret = skeyclass->get_skeys(ss, cur_gfn, cur_count, buf); - if (ret < 0) { - error_setg(errp, "get_keys error %d", ret); - goto out_free; - } - - /* write keys to stream */ - write_keys(f, buf, cur_gfn, cur_count, &lerr); - if (lerr) { - goto out_free; - } - - cur_gfn += cur_count; - handled_count += cur_count; - } - -out_free: - error_propagate(errp, lerr); - g_free(buf); -out: - qemu_fclose(f); -} - -static void qemu_s390_skeys_init(Object *obj) -{ - QEMUS390SKeysState *skeys = QEMU_S390_SKEYS(obj); - MachineState *machine = MACHINE(qdev_get_machine()); - - skeys->key_count = machine->maxram_size / TARGET_PAGE_SIZE; - skeys->keydata = g_malloc0(skeys->key_count); -} - -static int qemu_s390_skeys_enabled(S390SKeysState *ss) -{ - return 1; -} - -/* - * TODO: for memory hotplug support qemu_s390_skeys_set and qemu_s390_skeys_get - * will have to make sure that the given gfn belongs to a memory region and not - * a memory hole. - */ -static int qemu_s390_skeys_set(S390SKeysState *ss, uint64_t start_gfn, - uint64_t count, uint8_t *keys) -{ - QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss); - int i; - - /* Check for uint64 overflow and access beyond end of key data */ - if (start_gfn + count > skeydev->key_count || start_gfn + count < count) { - error_report("Error: Setting storage keys for page beyond the end " - "of memory: gfn=%" PRIx64 " count=%" PRId64, - start_gfn, count); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - skeydev->keydata[start_gfn + i] = keys[i]; - } - return 0; -} - -static int qemu_s390_skeys_get(S390SKeysState *ss, uint64_t start_gfn, - uint64_t count, uint8_t *keys) -{ - QEMUS390SKeysState *skeydev = QEMU_S390_SKEYS(ss); - int i; - - /* Check for uint64 overflow and access beyond end of key data */ - if (start_gfn + count > skeydev->key_count || start_gfn + count < count) { - error_report("Error: Getting storage keys for page beyond the end " - "of memory: gfn=%" PRIx64 " count=%" PRId64, - start_gfn, count); - return -EINVAL; - } - - for (i = 0; i < count; i++) { - keys[i] = skeydev->keydata[start_gfn + i]; - } - return 0; -} - -static void qemu_s390_skeys_class_init(ObjectClass *oc, void *data) -{ - S390SKeysClass *skeyclass = S390_SKEYS_CLASS(oc); - - skeyclass->skeys_enabled = qemu_s390_skeys_enabled; - skeyclass->get_skeys = qemu_s390_skeys_get; - skeyclass->set_skeys = qemu_s390_skeys_set; -} - -static const TypeInfo qemu_s390_skeys_info = { - .name = TYPE_QEMU_S390_SKEYS, - .parent = TYPE_S390_SKEYS, - .instance_init = qemu_s390_skeys_init, - .instance_size = sizeof(QEMUS390SKeysState), - .class_init = qemu_s390_skeys_class_init, - .class_size = sizeof(S390SKeysClass), -}; - -static void s390_storage_keys_save(QEMUFile *f, void *opaque) -{ - S390SKeysState *ss = S390_SKEYS(opaque); - S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); - uint64_t pages_left = ram_size / TARGET_PAGE_SIZE; - uint64_t read_count, eos = S390_SKEYS_SAVE_FLAG_EOS; - vaddr cur_gfn = 0; - int error = 0; - uint8_t *buf; - - if (!skeyclass->skeys_enabled(ss)) { - goto end_stream; - } - - buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); - if (!buf) { - error_report("storage key save could not allocate memory"); - goto end_stream; - } - - /* We only support initial memory. Standby memory is not handled yet. */ - qemu_put_be64(f, (cur_gfn * TARGET_PAGE_SIZE) | S390_SKEYS_SAVE_FLAG_SKEYS); - qemu_put_be64(f, pages_left); - - while (pages_left) { - read_count = MIN(pages_left, S390_SKEYS_BUFFER_SIZE); - - if (!error) { - error = skeyclass->get_skeys(ss, cur_gfn, read_count, buf); - if (error) { - /* - * If error: we want to fill the stream with valid data instead - * of stopping early so we pad the stream with 0x00 values and - * use S390_SKEYS_SAVE_FLAG_ERROR to indicate failure to the - * reading side. - */ - error_report("S390_GET_KEYS error %d", error); - memset(buf, 0, S390_SKEYS_BUFFER_SIZE); - eos = S390_SKEYS_SAVE_FLAG_ERROR; - } - } - - qemu_put_buffer(f, buf, read_count); - cur_gfn += read_count; - pages_left -= read_count; - } - - g_free(buf); -end_stream: - qemu_put_be64(f, eos); -} - -static int s390_storage_keys_load(QEMUFile *f, void *opaque, int version_id) -{ - S390SKeysState *ss = S390_SKEYS(opaque); - S390SKeysClass *skeyclass = S390_SKEYS_GET_CLASS(ss); - int ret = 0; - - while (!ret) { - ram_addr_t addr; - int flags; - - addr = qemu_get_be64(f); - flags = addr & ~TARGET_PAGE_MASK; - addr &= TARGET_PAGE_MASK; - - switch (flags) { - case S390_SKEYS_SAVE_FLAG_SKEYS: { - const uint64_t total_count = qemu_get_be64(f); - uint64_t handled_count = 0, cur_count; - uint64_t cur_gfn = addr / TARGET_PAGE_SIZE; - uint8_t *buf = g_try_malloc(S390_SKEYS_BUFFER_SIZE); - - if (!buf) { - error_report("storage key load could not allocate memory"); - ret = -ENOMEM; - break; - } - - while (handled_count < total_count) { - cur_count = MIN(total_count - handled_count, - S390_SKEYS_BUFFER_SIZE); - qemu_get_buffer(f, buf, cur_count); - - ret = skeyclass->set_skeys(ss, cur_gfn, cur_count, buf); - if (ret < 0) { - error_report("S390_SET_KEYS error %d", ret); - break; - } - handled_count += cur_count; - cur_gfn += cur_count; - } - g_free(buf); - break; - } - case S390_SKEYS_SAVE_FLAG_ERROR: { - error_report("Storage key data is incomplete"); - ret = -EINVAL; - break; - } - case S390_SKEYS_SAVE_FLAG_EOS: - /* normal exit */ - return 0; - default: - error_report("Unexpected storage key flag data: %#x", flags); - ret = -EINVAL; - } - } - - return ret; -} - -static inline bool s390_skeys_get_migration_enabled(Object *obj, Error **errp) -{ - S390SKeysState *ss = S390_SKEYS(obj); - - return ss->migration_enabled; -} - -static inline void s390_skeys_set_migration_enabled(Object *obj, bool value, - Error **errp) -{ - S390SKeysState *ss = S390_SKEYS(obj); - - /* Prevent double registration of savevm handler */ - if (ss->migration_enabled == value) { - return; - } - - ss->migration_enabled = value; - - if (ss->migration_enabled) { - register_savevm(NULL, TYPE_S390_SKEYS, 0, 1, s390_storage_keys_save, - s390_storage_keys_load, ss); - } else { - unregister_savevm(DEVICE(ss), TYPE_S390_SKEYS, ss); - } -} - -static void s390_skeys_instance_init(Object *obj) -{ - object_property_add_bool(obj, "migration-enabled", - s390_skeys_get_migration_enabled, - s390_skeys_set_migration_enabled, NULL); - object_property_set_bool(obj, true, "migration-enabled", NULL); -} - -static void s390_skeys_class_init(ObjectClass *oc, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->hotpluggable = false; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static const TypeInfo s390_skeys_info = { - .name = TYPE_S390_SKEYS, - .parent = TYPE_DEVICE, - .instance_init = s390_skeys_instance_init, - .instance_size = sizeof(S390SKeysState), - .class_init = s390_skeys_class_init, - .class_size = sizeof(S390SKeysClass), - .abstract = true, -}; - -static void qemu_s390_skeys_register_types(void) -{ - type_register_static(&s390_skeys_info); - type_register_static(&qemu_s390_skeys_info); -} - -type_init(qemu_s390_skeys_register_types) diff --git a/qemu/hw/s390x/s390-virtio-ccw.c b/qemu/hw/s390x/s390-virtio-ccw.c deleted file mode 100644 index e3df9c78b..000000000 --- a/qemu/hw/s390x/s390-virtio-ccw.c +++ /dev/null @@ -1,381 +0,0 @@ -/* - * virtio ccw machine - * - * Copyright 2012 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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 "qemu-common.h" -#include "cpu.h" -#include "hw/boards.h" -#include "exec/address-spaces.h" -#include "s390-virtio.h" -#include "hw/s390x/sclp.h" -#include "hw/s390x/s390_flic.h" -#include "ioinst.h" -#include "css.h" -#include "virtio-ccw.h" -#include "qemu/config-file.h" -#include "s390-pci-bus.h" -#include "hw/s390x/storage-keys.h" -#include "hw/compat.h" -#include "hw/s390x/s390-virtio-ccw.h" - -static const char *const reset_dev_types[] = { - "virtual-css-bridge", - "s390-sclp-event-facility", - "s390-flic", - "diag288", -}; - -void subsystem_reset(void) -{ - DeviceState *dev; - int i; - - for (i = 0; i < ARRAY_SIZE(reset_dev_types); i++) { - dev = DEVICE(object_resolve_path_type("", reset_dev_types[i], NULL)); - if (dev) { - qdev_reset_all(dev); - } - } -} - -static int virtio_ccw_hcall_notify(const uint64_t *args) -{ - uint64_t subch_id = args[0]; - uint64_t queue = args[1]; - SubchDev *sch; - int cssid, ssid, schid, m; - - if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) { - return -EINVAL; - } - sch = css_find_subch(m, cssid, ssid, schid); - if (!sch || !css_subch_visible(sch)) { - return -EINVAL; - } - if (queue >= VIRTIO_CCW_QUEUE_MAX) { - return -EINVAL; - } - virtio_queue_notify(virtio_ccw_get_vdev(sch), queue); - return 0; - -} - -static int virtio_ccw_hcall_early_printk(const uint64_t *args) -{ - uint64_t mem = args[0]; - - if (mem < ram_size) { - /* Early printk */ - return 0; - } - return -EINVAL; -} - -static void virtio_ccw_register_hcalls(void) -{ - s390_register_virtio_hypercall(KVM_S390_VIRTIO_CCW_NOTIFY, - virtio_ccw_hcall_notify); - /* Tolerate early printk. */ - s390_register_virtio_hypercall(KVM_S390_VIRTIO_NOTIFY, - virtio_ccw_hcall_early_printk); -} - -void s390_memory_init(ram_addr_t mem_size) -{ - MemoryRegion *sysmem = get_system_memory(); - MemoryRegion *ram = g_new(MemoryRegion, 1); - - /* allocate RAM for core */ - memory_region_allocate_system_memory(ram, NULL, "s390.ram", mem_size); - memory_region_add_subregion(sysmem, 0, ram); - - /* Initialize storage key device */ - s390_skeys_init(); -} - -static void ccw_init(MachineState *machine) -{ - int ret; - VirtualCssBus *css_bus; - DeviceState *dev; - - s390_sclp_init(); - s390_memory_init(machine->ram_size); - - /* get a BUS */ - css_bus = virtual_css_bus_init(); - s390_init_ipl_dev(machine->kernel_filename, machine->kernel_cmdline, - machine->initrd_filename, "s390-ccw.img", true); - s390_flic_init(); - - dev = qdev_create(NULL, TYPE_S390_PCI_HOST_BRIDGE); - object_property_add_child(qdev_get_machine(), TYPE_S390_PCI_HOST_BRIDGE, - OBJECT(dev), NULL); - qdev_init_nofail(dev); - - /* register hypercalls */ - virtio_ccw_register_hcalls(); - - /* init CPUs */ - s390_init_cpus(machine); - - if (kvm_enabled()) { - 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. - */ - ret = css_create_css_image(VIRTUAL_CSSID, true); - assert(ret == 0); - - /* Create VirtIO network adapters */ - s390_create_virtio_net(BUS(css_bus), "virtio-net-ccw"); - - /* Register savevm handler for guest TOD clock */ - register_savevm(NULL, "todclock", 0, 1, - gtod_save, gtod_load, kvm_state); -} - -static void s390_cpu_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - gchar *name; - S390CPU *cpu = S390_CPU(dev); - CPUState *cs = CPU(dev); - - name = g_strdup_printf("cpu[%i]", cpu->env.cpu_num); - object_property_set_link(OBJECT(hotplug_dev), OBJECT(cs), name, - errp); - g_free(name); -} - -static void s390_machine_device_plug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - s390_cpu_plug(hotplug_dev, dev, errp); - } -} - -static HotplugHandler *s390_get_hotplug_handler(MachineState *machine, - DeviceState *dev) -{ - if (object_dynamic_cast(OBJECT(dev), TYPE_CPU)) { - return HOTPLUG_HANDLER(machine); - } - return NULL; -} - -static void s390_hot_add_cpu(const int64_t id, Error **errp) -{ - MachineState *machine = MACHINE(qdev_get_machine()); - Error *err = NULL; - - s390x_new_cpu(machine->cpu_model, id, &err); - error_propagate(errp, err); -} - -static void ccw_machine_class_init(ObjectClass *oc, void *data) -{ - MachineClass *mc = MACHINE_CLASS(oc); - NMIClass *nc = NMI_CLASS(oc); - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(oc); - - mc->init = ccw_init; - mc->reset = s390_machine_reset; - mc->hot_add_cpu = s390_hot_add_cpu; - mc->block_default_type = IF_VIRTIO; - mc->no_cdrom = 1; - mc->no_floppy = 1; - mc->no_serial = 1; - mc->no_parallel = 1; - mc->no_sdcard = 1; - mc->use_sclp = 1; - mc->max_cpus = 255; - mc->get_hotplug_handler = s390_get_hotplug_handler; - hc->plug = s390_machine_device_plug; - nc->nmi_monitor_handler = s390_nmi; -} - -static inline bool machine_get_aes_key_wrap(Object *obj, Error **errp) -{ - S390CcwMachineState *ms = S390_CCW_MACHINE(obj); - - return ms->aes_key_wrap; -} - -static inline void machine_set_aes_key_wrap(Object *obj, bool value, - Error **errp) -{ - S390CcwMachineState *ms = S390_CCW_MACHINE(obj); - - ms->aes_key_wrap = value; -} - -static inline bool machine_get_dea_key_wrap(Object *obj, Error **errp) -{ - S390CcwMachineState *ms = S390_CCW_MACHINE(obj); - - return ms->dea_key_wrap; -} - -static inline void machine_set_dea_key_wrap(Object *obj, bool value, - Error **errp) -{ - S390CcwMachineState *ms = S390_CCW_MACHINE(obj); - - ms->dea_key_wrap = value; -} - -static inline void s390_machine_initfn(Object *obj) -{ - object_property_add_bool(obj, "aes-key-wrap", - machine_get_aes_key_wrap, - machine_set_aes_key_wrap, NULL); - object_property_set_description(obj, "aes-key-wrap", - "enable/disable AES key wrapping using the CPACF wrapping key", - NULL); - object_property_set_bool(obj, true, "aes-key-wrap", NULL); - - object_property_add_bool(obj, "dea-key-wrap", - machine_get_dea_key_wrap, - machine_set_dea_key_wrap, NULL); - object_property_set_description(obj, "dea-key-wrap", - "enable/disable DEA key wrapping using the CPACF wrapping key", - NULL); - object_property_set_bool(obj, true, "dea-key-wrap", NULL); -} - -static const TypeInfo ccw_machine_info = { - .name = TYPE_S390_CCW_MACHINE, - .parent = TYPE_MACHINE, - .abstract = true, - .instance_size = sizeof(S390CcwMachineState), - .instance_init = s390_machine_initfn, - .class_init = ccw_machine_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_NMI }, - { TYPE_HOTPLUG_HANDLER}, - { } - }, -}; - -#define DEFINE_CCW_MACHINE(suffix, verstr, latest) \ - static void ccw_machine_##suffix##_class_init(ObjectClass *oc, \ - void *data) \ - { \ - MachineClass *mc = MACHINE_CLASS(oc); \ - ccw_machine_##suffix##_class_options(mc); \ - mc->desc = "VirtIO-ccw based S390 machine v" verstr; \ - if (latest) { \ - mc->alias = "s390-ccw-virtio"; \ - mc->is_default = 1; \ - } \ - } \ - static void ccw_machine_##suffix##_instance_init(Object *obj) \ - { \ - MachineState *machine = MACHINE(obj); \ - ccw_machine_##suffix##_instance_options(machine); \ - } \ - static const TypeInfo ccw_machine_##suffix##_info = { \ - .name = MACHINE_TYPE_NAME("s390-ccw-virtio-" verstr), \ - .parent = TYPE_S390_CCW_MACHINE, \ - .class_init = ccw_machine_##suffix##_class_init, \ - .instance_init = ccw_machine_##suffix##_instance_init, \ - }; \ - static void ccw_machine_register_##suffix(void) \ - { \ - type_register_static(&ccw_machine_##suffix##_info); \ - } \ - type_init(ccw_machine_register_##suffix) - -#define CCW_COMPAT_2_5 \ - HW_COMPAT_2_5 - -#define CCW_COMPAT_2_4 \ - CCW_COMPAT_2_5 \ - HW_COMPAT_2_4 \ - {\ - .driver = TYPE_S390_SKEYS,\ - .property = "migration-enabled",\ - .value = "off",\ - },{\ - .driver = "virtio-blk-ccw",\ - .property = "max_revision",\ - .value = "0",\ - },{\ - .driver = "virtio-balloon-ccw",\ - .property = "max_revision",\ - .value = "0",\ - },{\ - .driver = "virtio-serial-ccw",\ - .property = "max_revision",\ - .value = "0",\ - },{\ - .driver = "virtio-9p-ccw",\ - .property = "max_revision",\ - .value = "0",\ - },{\ - .driver = "virtio-rng-ccw",\ - .property = "max_revision",\ - .value = "0",\ - },{\ - .driver = "virtio-net-ccw",\ - .property = "max_revision",\ - .value = "0",\ - },{\ - .driver = "virtio-scsi-ccw",\ - .property = "max_revision",\ - .value = "0",\ - },{\ - .driver = "vhost-scsi-ccw",\ - .property = "max_revision",\ - .value = "0",\ - }, - -static void ccw_machine_2_6_instance_options(MachineState *machine) -{ -} - -static void ccw_machine_2_6_class_options(MachineClass *mc) -{ -} -DEFINE_CCW_MACHINE(2_6, "2.6", true); - -static void ccw_machine_2_5_instance_options(MachineState *machine) -{ -} - -static void ccw_machine_2_5_class_options(MachineClass *mc) -{ - SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5); -} -DEFINE_CCW_MACHINE(2_5, "2.5", false); - -static void ccw_machine_2_4_instance_options(MachineState *machine) -{ - ccw_machine_2_5_instance_options(machine); -} - -static void ccw_machine_2_4_class_options(MachineClass *mc) -{ - SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4); -} -DEFINE_CCW_MACHINE(2_4, "2.4", false); - -static void ccw_machine_register_types(void) -{ - type_register_static(&ccw_machine_info); -} - -type_init(ccw_machine_register_types) diff --git a/qemu/hw/s390x/s390-virtio-hcall.c b/qemu/hw/s390x/s390-virtio-hcall.c deleted file mode 100644 index 23d67d617..000000000 --- a/qemu/hw/s390x/s390-virtio-hcall.c +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Support for virtio hypercalls on s390 - * - * Copyright 2012 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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 "cpu.h" -#include "hw/s390x/s390-virtio.h" - -#define MAX_DIAG_SUBCODES 255 - -static s390_virtio_fn s390_diag500_table[MAX_DIAG_SUBCODES]; - -void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn) -{ - assert(code < MAX_DIAG_SUBCODES); - assert(!s390_diag500_table[code]); - - s390_diag500_table[code] = fn; -} - -int s390_virtio_hypercall(CPUS390XState *env) -{ - s390_virtio_fn fn; - - if (env->regs[1] < MAX_DIAG_SUBCODES) { - fn = s390_diag500_table[env->regs[1]]; - if (fn) { - env->regs[2] = fn(&env->regs[2]); - return 0; - } - } - - return -EINVAL; -} diff --git a/qemu/hw/s390x/s390-virtio.c b/qemu/hw/s390x/s390-virtio.c deleted file mode 100644 index 544c61643..000000000 --- a/qemu/hw/s390x/s390-virtio.c +++ /dev/null @@ -1,210 +0,0 @@ -/* - * QEMU S390 virtio target - * - * Copyright (c) 2009 Alexander Graf <agraf@suse.de> - * Copyright IBM Corp 2012 - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * Contributions after 2012-10-29 are licensed under the terms of the - * GNU GPL, version 2 or (at your option) any later version. - * - * You should have received a copy of the GNU (Lesser) General Public - * License along with this library; if not, see <http://www.gnu.org/licenses/>. - */ - -#include "qemu/osdep.h" -#include "qapi/error.h" -#include "hw/hw.h" -#include "qapi/qmp/qerror.h" -#include "qemu/error-report.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "sysemu/sysemu.h" -#include "net/net.h" -#include "hw/boards.h" -#include "hw/loader.h" -#include "hw/virtio/virtio.h" -#include "sysemu/kvm.h" -#include "exec/address-spaces.h" -#include "sysemu/qtest.h" - -#include "hw/s390x/sclp.h" -#include "hw/s390x/s390_flic.h" -#include "hw/s390x/s390-virtio.h" -#include "hw/s390x/storage-keys.h" -#include "hw/s390x/ipl.h" -#include "cpu.h" - -//#define DEBUG_S390 - -#ifdef DEBUG_S390 -#define DPRINTF(fmt, ...) \ - do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) -#else -#define DPRINTF(fmt, ...) \ - do { } while (0) -#endif - -#define MAX_BLK_DEVS 10 - -#define S390_TOD_CLOCK_VALUE_MISSING 0x00 -#define S390_TOD_CLOCK_VALUE_PRESENT 0x01 - -static S390CPU **cpu_states; - -S390CPU *s390_cpu_addr2state(uint16_t cpu_addr) -{ - if (cpu_addr >= max_cpus) { - return NULL; - } - - /* Fast lookup via CPU ID */ - return cpu_states[cpu_addr]; -} - -void s390_init_ipl_dev(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *firmware, - bool enforce_bios) -{ - Object *new = object_new(TYPE_S390_IPL); - DeviceState *dev = DEVICE(new); - - if (kernel_filename) { - qdev_prop_set_string(dev, "kernel", kernel_filename); - } - if (initrd_filename) { - qdev_prop_set_string(dev, "initrd", initrd_filename); - } - qdev_prop_set_string(dev, "cmdline", kernel_cmdline); - qdev_prop_set_string(dev, "firmware", firmware); - qdev_prop_set_bit(dev, "enforce_bios", enforce_bios); - object_property_add_child(qdev_get_machine(), TYPE_S390_IPL, - new, NULL); - object_unref(new); - qdev_init_nofail(dev); -} - -void s390_init_cpus(MachineState *machine) -{ - int i; - gchar *name; - - if (machine->cpu_model == NULL) { - machine->cpu_model = "host"; - } - - cpu_states = g_new0(S390CPU *, max_cpus); - - for (i = 0; i < max_cpus; i++) { - name = g_strdup_printf("cpu[%i]", i); - object_property_add_link(OBJECT(machine), name, TYPE_S390_CPU, - (Object **) &cpu_states[i], - object_property_allow_set_link, - OBJ_PROP_LINK_UNREF_ON_RELEASE, - &error_abort); - g_free(name); - } - - for (i = 0; i < smp_cpus; i++) { - s390x_new_cpu(machine->cpu_model, i, &error_fatal); - } -} - - -void s390_create_virtio_net(BusState *bus, const char *name) -{ - int i; - - for (i = 0; i < nb_nics; i++) { - NICInfo *nd = &nd_table[i]; - DeviceState *dev; - - if (!nd->model) { - nd->model = g_strdup("virtio"); - } - - qemu_check_nic_model(nd, "virtio"); - - dev = qdev_create(bus, name); - qdev_set_nic_properties(dev, nd); - qdev_init_nofail(dev); - } -} - -void gtod_save(QEMUFile *f, void *opaque) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - r = s390_get_clock(&tod_high, &tod_low); - if (r) { - fprintf(stderr, "WARNING: Unable to get guest clock for migration. " - "Error code %d. Guest clock will not be migrated " - "which could cause the guest to hang.\n", r); - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_MISSING); - return; - } - - qemu_put_byte(f, S390_TOD_CLOCK_VALUE_PRESENT); - qemu_put_byte(f, tod_high); - qemu_put_be64(f, tod_low); -} - -int gtod_load(QEMUFile *f, void *opaque, int version_id) -{ - uint64_t tod_low; - uint8_t tod_high; - int r; - - if (qemu_get_byte(f) == S390_TOD_CLOCK_VALUE_MISSING) { - fprintf(stderr, "WARNING: Guest clock was not migrated. This could " - "cause the guest to hang.\n"); - return 0; - } - - tod_high = qemu_get_byte(f); - tod_low = qemu_get_be64(f); - - r = s390_set_clock(&tod_high, &tod_low); - if (r) { - fprintf(stderr, "WARNING: Unable to set guest clock value. " - "s390_get_clock returned error %d. This could cause " - "the guest to hang.\n", r); - } - - return 0; -} - -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); - } -} - -void s390_machine_reset(void) -{ - S390CPU *ipl_cpu = S390_CPU(qemu_get_cpu(0)); - - qemu_devices_reset(); - s390_cmma_reset(); - s390_crypto_reset(); - - /* all cpus are stopped - configure and start the ipl cpu only */ - s390_ipl_prepare_cpu(ipl_cpu); - s390_cpu_set_state(CPU_STATE_OPERATING, ipl_cpu); -} diff --git a/qemu/hw/s390x/s390-virtio.h b/qemu/hw/s390x/s390-virtio.h deleted file mode 100644 index ffd014cb5..000000000 --- a/qemu/hw/s390x/s390-virtio.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Virtio interfaces for s390 - * - * Copyright 2012 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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. - */ - -#ifndef HW_S390_VIRTIO_H -#define HW_S390_VIRTIO_H 1 - -#include "hw/nmi.h" -#include "standard-headers/asm-s390/kvm_virtio.h" -#include "standard-headers/asm-s390/virtio-ccw.h" - -typedef int (*s390_virtio_fn)(const uint64_t *args); -void s390_register_virtio_hypercall(uint64_t code, s390_virtio_fn fn); - -void s390_init_cpus(MachineState *machine); -void s390_init_ipl_dev(const char *kernel_filename, - const char *kernel_cmdline, - const char *initrd_filename, - const char *firmware, - bool enforce_bios); -void s390_create_virtio_net(BusState *bus, const char *name); -void s390_nmi(NMIState *n, int cpu_index, Error **errp); -void s390_machine_reset(void); -void s390_memory_init(ram_addr_t mem_size); -#endif diff --git a/qemu/hw/s390x/sclp.c b/qemu/hw/s390x/sclp.c deleted file mode 100644 index 85dbe1b60..000000000 --- a/qemu/hw/s390x/sclp.c +++ /dev/null @@ -1,618 +0,0 @@ -/* - * SCLP Support - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Christian Borntraeger <borntraeger@de.ibm.com> - * Heinz Graalfs <graalfs@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 "cpu.h" -#include "sysemu/kvm.h" -#include "exec/memory.h" -#include "sysemu/sysemu.h" -#include "exec/address-spaces.h" -#include "hw/boards.h" -#include "hw/s390x/sclp.h" -#include "hw/s390x/event-facility.h" -#include "hw/s390x/s390-pci-bus.h" - -static inline SCLPDevice *get_sclp_device(void) -{ - return SCLP(object_resolve_path_type("", TYPE_SCLP, NULL)); -} - -/* Provide information about the configuration, CPUs and storage */ -static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb) -{ - ReadInfo *read_info = (ReadInfo *) sccb; - MachineState *machine = MACHINE(qdev_get_machine()); - sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - CPUState *cpu; - int cpu_count = 0; - int i = 0; - int rnsize, rnmax; - int slots = MIN(machine->ram_slots, s390_get_memslot_count(kvm_state)); - - CPU_FOREACH(cpu) { - cpu_count++; - } - - /* CPU information */ - read_info->entries_cpu = cpu_to_be16(cpu_count); - read_info->offset_cpu = cpu_to_be16(offsetof(ReadInfo, entries)); - read_info->highest_cpu = cpu_to_be16(max_cpus); - - for (i = 0; i < cpu_count; i++) { - read_info->entries[i].address = i; - read_info->entries[i].type = 0; - } - - read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO | - SCLP_HAS_PCI_RECONFIG); - - /* Memory Hotplug is only supported for the ccw machine type */ - if (mhd) { - mhd->standby_subregion_size = MEM_SECTION_SIZE; - /* Deduct the memory slot already used for core */ - if (slots > 0) { - while ((mhd->standby_subregion_size * (slots - 1) - < mhd->standby_mem_size)) { - mhd->standby_subregion_size = mhd->standby_subregion_size << 1; - } - } - /* - * Initialize mapping of guest standby memory sections indicating which - * are and are not online. Assume all standby memory begins offline. - */ - if (mhd->standby_state_map == 0) { - if (mhd->standby_mem_size % mhd->standby_subregion_size) { - mhd->standby_state_map = g_malloc0((mhd->standby_mem_size / - mhd->standby_subregion_size + 1) * - (mhd->standby_subregion_size / - MEM_SECTION_SIZE)); - } else { - mhd->standby_state_map = g_malloc0(mhd->standby_mem_size / - MEM_SECTION_SIZE); - } - } - mhd->padded_ram_size = ram_size + mhd->pad_size; - mhd->rzm = 1 << mhd->increment_size; - - read_info->facilities |= cpu_to_be64(SCLP_FC_ASSIGN_ATTACH_READ_STOR); - } - - rnsize = 1 << (sclp->increment_size - 20); - if (rnsize <= 128) { - read_info->rnsize = rnsize; - } else { - read_info->rnsize = 0; - read_info->rnsize2 = cpu_to_be32(rnsize); - } - - rnmax = machine->maxram_size >> sclp->increment_size; - if (rnmax < 0x10000) { - read_info->rnmax = cpu_to_be16(rnmax); - } else { - read_info->rnmax = cpu_to_be16(0); - read_info->rnmax2 = cpu_to_be64(rnmax); - } - - sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); -} - -static void read_storage_element0_info(SCLPDevice *sclp, SCCB *sccb) -{ - int i, assigned; - int subincrement_id = SCLP_STARTING_SUBINCREMENT_ID; - ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb; - sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - - if (!mhd) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - return; - } - - if ((ram_size >> mhd->increment_size) >= 0x10000) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); - return; - } - - /* Return information regarding core memory */ - storage_info->max_id = cpu_to_be16(mhd->standby_mem_size ? 1 : 0); - assigned = ram_size >> mhd->increment_size; - storage_info->assigned = cpu_to_be16(assigned); - - for (i = 0; i < assigned; i++) { - storage_info->entries[i] = cpu_to_be32(subincrement_id); - subincrement_id += SCLP_INCREMENT_UNIT; - } - sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); -} - -static void read_storage_element1_info(SCLPDevice *sclp, SCCB *sccb) -{ - ReadStorageElementInfo *storage_info = (ReadStorageElementInfo *) sccb; - sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - - if (!mhd) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - return; - } - - if ((mhd->standby_mem_size >> mhd->increment_size) >= 0x10000) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION); - return; - } - - /* Return information regarding standby memory */ - storage_info->max_id = cpu_to_be16(mhd->standby_mem_size ? 1 : 0); - storage_info->assigned = cpu_to_be16(mhd->standby_mem_size >> - mhd->increment_size); - storage_info->standby = cpu_to_be16(mhd->standby_mem_size >> - mhd->increment_size); - sccb->h.response_code = cpu_to_be16(SCLP_RC_STANDBY_READ_COMPLETION); -} - -static void attach_storage_element(SCLPDevice *sclp, SCCB *sccb, - uint16_t element) -{ - int i, assigned, subincrement_id; - AttachStorageElement *attach_info = (AttachStorageElement *) sccb; - sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - - if (!mhd) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - return; - } - - if (element != 1) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - return; - } - - assigned = mhd->standby_mem_size >> mhd->increment_size; - attach_info->assigned = cpu_to_be16(assigned); - subincrement_id = ((ram_size >> mhd->increment_size) << 16) - + SCLP_STARTING_SUBINCREMENT_ID; - for (i = 0; i < assigned; i++) { - attach_info->entries[i] = cpu_to_be32(subincrement_id); - subincrement_id += SCLP_INCREMENT_UNIT; - } - sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); -} - -static void assign_storage(SCLPDevice *sclp, SCCB *sccb) -{ - MemoryRegion *mr = NULL; - uint64_t this_subregion_size; - AssignStorage *assign_info = (AssignStorage *) sccb; - sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - ram_addr_t assign_addr; - MemoryRegion *sysmem = get_system_memory(); - - if (!mhd) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - return; - } - assign_addr = (assign_info->rn - 1) * mhd->rzm; - - if ((assign_addr % MEM_SECTION_SIZE == 0) && - (assign_addr >= mhd->padded_ram_size)) { - /* Re-use existing memory region if found */ - mr = memory_region_find(sysmem, assign_addr, 1).mr; - memory_region_unref(mr); - if (!mr) { - - MemoryRegion *standby_ram = g_new(MemoryRegion, 1); - - /* offset to align to standby_subregion_size for allocation */ - ram_addr_t offset = assign_addr - - (assign_addr - mhd->padded_ram_size) - % mhd->standby_subregion_size; - - /* strlen("standby.ram") + 4 (Max of KVM_MEMORY_SLOTS) + NULL */ - char id[16]; - snprintf(id, 16, "standby.ram%d", - (int)((offset - mhd->padded_ram_size) / - mhd->standby_subregion_size) + 1); - - /* Allocate a subregion of the calculated standby_subregion_size */ - if (offset + mhd->standby_subregion_size > - mhd->padded_ram_size + mhd->standby_mem_size) { - this_subregion_size = mhd->padded_ram_size + - mhd->standby_mem_size - offset; - } else { - this_subregion_size = mhd->standby_subregion_size; - } - - memory_region_init_ram(standby_ram, NULL, id, this_subregion_size, - &error_fatal); - /* This is a hack to make memory hotunplug work again. Once we have - * subdevices, we have to unparent them when unassigning memory, - * instead of doing it via the ref count of the MemoryRegion. */ - object_ref(OBJECT(standby_ram)); - object_unparent(OBJECT(standby_ram)); - vmstate_register_ram_global(standby_ram); - memory_region_add_subregion(sysmem, offset, standby_ram); - } - /* The specified subregion is no longer in standby */ - mhd->standby_state_map[(assign_addr - mhd->padded_ram_size) - / MEM_SECTION_SIZE] = 1; - } - sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); -} - -static void unassign_storage(SCLPDevice *sclp, SCCB *sccb) -{ - MemoryRegion *mr = NULL; - AssignStorage *assign_info = (AssignStorage *) sccb; - sclpMemoryHotplugDev *mhd = get_sclp_memory_hotplug_dev(); - ram_addr_t unassign_addr; - MemoryRegion *sysmem = get_system_memory(); - - if (!mhd) { - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND); - return; - } - unassign_addr = (assign_info->rn - 1) * mhd->rzm; - - /* if the addr is a multiple of 256 MB */ - if ((unassign_addr % MEM_SECTION_SIZE == 0) && - (unassign_addr >= mhd->padded_ram_size)) { - mhd->standby_state_map[(unassign_addr - - mhd->padded_ram_size) / MEM_SECTION_SIZE] = 0; - - /* find the specified memory region and destroy it */ - mr = memory_region_find(sysmem, unassign_addr, 1).mr; - memory_region_unref(mr); - if (mr) { - int i; - int is_removable = 1; - ram_addr_t map_offset = (unassign_addr - mhd->padded_ram_size - - (unassign_addr - mhd->padded_ram_size) - % mhd->standby_subregion_size); - /* Mark all affected subregions as 'standby' once again */ - for (i = 0; - i < (mhd->standby_subregion_size / MEM_SECTION_SIZE); - i++) { - - if (mhd->standby_state_map[i + map_offset / MEM_SECTION_SIZE]) { - is_removable = 0; - break; - } - } - if (is_removable) { - memory_region_del_subregion(sysmem, mr); - object_unref(OBJECT(mr)); - } - } - } - sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION); -} - -/* Provide information about the CPU */ -static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb) -{ - ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb; - CPUState *cpu; - int cpu_count = 0; - int i = 0; - - CPU_FOREACH(cpu) { - cpu_count++; - } - - cpu_info->nr_configured = cpu_to_be16(cpu_count); - cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries)); - cpu_info->nr_standby = cpu_to_be16(0); - - /* The standby offset is 16-byte for each CPU */ - cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured - + cpu_info->nr_configured*sizeof(CPUEntry)); - - for (i = 0; i < cpu_count; i++) { - cpu_info->entries[i].address = i; - cpu_info->entries[i].type = 0; - } - - sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); -} - -static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code) -{ - SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); - SCLPEventFacility *ef = sclp->event_facility; - SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); - - switch (code & SCLP_CMD_CODE_MASK) { - case SCLP_CMDW_READ_SCP_INFO: - case SCLP_CMDW_READ_SCP_INFO_FORCED: - sclp_c->read_SCP_info(sclp, sccb); - break; - case SCLP_CMDW_READ_CPU_INFO: - sclp_c->read_cpu_info(sclp, sccb); - break; - case SCLP_READ_STORAGE_ELEMENT_INFO: - if (code & 0xff00) { - sclp_c->read_storage_element1_info(sclp, sccb); - } else { - sclp_c->read_storage_element0_info(sclp, sccb); - } - break; - case SCLP_ATTACH_STORAGE_ELEMENT: - sclp_c->attach_storage_element(sclp, sccb, (code & 0xff00) >> 8); - break; - case SCLP_ASSIGN_STORAGE: - sclp_c->assign_storage(sclp, sccb); - break; - case SCLP_UNASSIGN_STORAGE: - sclp_c->unassign_storage(sclp, sccb); - break; - case SCLP_CMDW_CONFIGURE_PCI: - s390_pci_sclp_configure(1, sccb); - break; - case SCLP_CMDW_DECONFIGURE_PCI: - s390_pci_sclp_configure(0, sccb); - break; - default: - efc->command_handler(ef, sccb, code); - break; - } -} - -int sclp_service_call(CPUS390XState *env, uint64_t sccb, uint32_t code) -{ - SCLPDevice *sclp = get_sclp_device(); - SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); - int r = 0; - SCCB work_sccb; - - hwaddr sccb_len = sizeof(SCCB); - - /* first some basic checks on program checks */ - if (env->psw.mask & PSW_MASK_PSTATE) { - r = -PGM_PRIVILEGED; - goto out; - } - if (cpu_physical_memory_is_io(sccb)) { - r = -PGM_ADDRESSING; - goto out; - } - if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa - || (sccb & ~0x7ffffff8UL) != 0) { - r = -PGM_SPECIFICATION; - goto out; - } - - /* - * we want to work on a private copy of the sccb, to prevent guests - * from playing dirty tricks by modifying the memory content after - * the host has checked the values - */ - cpu_physical_memory_read(sccb, &work_sccb, sccb_len); - - /* Valid sccb sizes */ - if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader) || - be16_to_cpu(work_sccb.h.length) > SCCB_SIZE) { - r = -PGM_SPECIFICATION; - goto out; - } - - sclp_c->execute(sclp, (SCCB *)&work_sccb, code); - - cpu_physical_memory_write(sccb, &work_sccb, - be16_to_cpu(work_sccb.h.length)); - - sclp_c->service_interrupt(sclp, sccb); - -out: - return r; -} - -static void service_interrupt(SCLPDevice *sclp, uint32_t sccb) -{ - SCLPEventFacility *ef = sclp->event_facility; - SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef); - - uint32_t param = sccb & ~3; - - /* Indicate whether an event is still pending */ - param |= efc->event_pending(ef) ? 1 : 0; - - if (!param) { - /* No need to send an interrupt, there's nothing to be notified about */ - return; - } - s390_sclp_extint(param); -} - -void sclp_service_interrupt(uint32_t sccb) -{ - SCLPDevice *sclp = get_sclp_device(); - SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp); - - sclp_c->service_interrupt(sclp, sccb); -} - -/* qemu object creation and initialization functions */ - -void s390_sclp_init(void) -{ - Object *new = object_new(TYPE_SCLP); - - object_property_add_child(qdev_get_machine(), TYPE_SCLP, new, - NULL); - object_unref(OBJECT(new)); - qdev_init_nofail(DEVICE(new)); -} - -static void sclp_realize(DeviceState *dev, Error **errp) -{ - MachineState *machine = MACHINE(qdev_get_machine()); - SCLPDevice *sclp = SCLP(dev); - Error *err = NULL; - uint64_t hw_limit; - int ret; - - object_property_set_bool(OBJECT(sclp->event_facility), true, "realized", - &err); - if (err) { - goto out; - } - /* - * qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long - * as we can't find a fitting bus via the qom tree, we have to add the - * event facility to the sysbus, so e.g. a sclp console can be created. - */ - qdev_set_parent_bus(DEVICE(sclp->event_facility), sysbus_get_default()); - - ret = s390_set_memory_limit(machine->maxram_size, &hw_limit); - if (ret == -E2BIG) { - error_setg(&err, "qemu: host supports a maximum of %" PRIu64 " GB", - hw_limit >> 30); - } else if (ret) { - error_setg(&err, "qemu: setting the guest size failed"); - } - -out: - error_propagate(errp, err); -} - -static void sclp_memory_init(SCLPDevice *sclp) -{ - MachineState *machine = MACHINE(qdev_get_machine()); - ram_addr_t initial_mem = machine->ram_size; - ram_addr_t max_mem = machine->maxram_size; - ram_addr_t standby_mem = max_mem - initial_mem; - ram_addr_t pad_mem = 0; - int increment_size = 20; - - /* The storage increment size is a multiple of 1M and is a power of 2. - * The number of storage increments must be MAX_STORAGE_INCREMENTS or fewer. - * The variable 'increment_size' is an exponent of 2 that can be - * used to calculate the size (in bytes) of an increment. */ - while ((initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) { - increment_size++; - } - if (machine->ram_slots) { - while ((standby_mem >> increment_size) > MAX_STORAGE_INCREMENTS) { - increment_size++; - } - } - sclp->increment_size = increment_size; - - /* The core and standby memory areas need to be aligned with - * the increment size. In effect, this can cause the - * user-specified memory size to be rounded down to align - * with the nearest increment boundary. */ - initial_mem = initial_mem >> increment_size << increment_size; - standby_mem = standby_mem >> increment_size << increment_size; - - /* If the size of ram is not on a MEM_SECTION_SIZE boundary, - calculate the pad size necessary to force this boundary. */ - if (machine->ram_slots && standby_mem) { - sclpMemoryHotplugDev *mhd = init_sclp_memory_hotplug_dev(); - - if (initial_mem % MEM_SECTION_SIZE) { - pad_mem = MEM_SECTION_SIZE - initial_mem % MEM_SECTION_SIZE; - } - mhd->increment_size = increment_size; - mhd->pad_size = pad_mem; - mhd->standby_mem_size = standby_mem; - } - machine->ram_size = initial_mem; - machine->maxram_size = initial_mem + pad_mem + standby_mem; - /* let's propagate the changed ram size into the global variable. */ - ram_size = initial_mem; -} - -static void sclp_init(Object *obj) -{ - SCLPDevice *sclp = SCLP(obj); - Object *new; - - new = object_new(TYPE_SCLP_EVENT_FACILITY); - object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new, NULL); - object_unref(new); - sclp->event_facility = EVENT_FACILITY(new); - - sclp_memory_init(sclp); -} - -static void sclp_class_init(ObjectClass *oc, void *data) -{ - SCLPDeviceClass *sc = SCLP_CLASS(oc); - DeviceClass *dc = DEVICE_CLASS(oc); - - dc->desc = "SCLP (Service-Call Logical Processor)"; - dc->realize = sclp_realize; - dc->hotpluggable = false; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - - sc->read_SCP_info = read_SCP_info; - sc->read_storage_element0_info = read_storage_element0_info; - sc->read_storage_element1_info = read_storage_element1_info; - sc->attach_storage_element = attach_storage_element; - sc->assign_storage = assign_storage; - sc->unassign_storage = unassign_storage; - sc->read_cpu_info = sclp_read_cpu_info; - sc->execute = sclp_execute; - sc->service_interrupt = service_interrupt; -} - -static TypeInfo sclp_info = { - .name = TYPE_SCLP, - .parent = TYPE_DEVICE, - .instance_init = sclp_init, - .instance_size = sizeof(SCLPDevice), - .class_init = sclp_class_init, - .class_size = sizeof(SCLPDeviceClass), -}; - -sclpMemoryHotplugDev *init_sclp_memory_hotplug_dev(void) -{ - DeviceState *dev; - dev = qdev_create(NULL, TYPE_SCLP_MEMORY_HOTPLUG_DEV); - object_property_add_child(qdev_get_machine(), - TYPE_SCLP_MEMORY_HOTPLUG_DEV, - OBJECT(dev), NULL); - qdev_init_nofail(dev); - return SCLP_MEMORY_HOTPLUG_DEV(object_resolve_path( - TYPE_SCLP_MEMORY_HOTPLUG_DEV, NULL)); -} - -sclpMemoryHotplugDev *get_sclp_memory_hotplug_dev(void) -{ - return SCLP_MEMORY_HOTPLUG_DEV(object_resolve_path( - TYPE_SCLP_MEMORY_HOTPLUG_DEV, NULL)); -} - -static void sclp_memory_hotplug_dev_class_init(ObjectClass *klass, - void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static TypeInfo sclp_memory_hotplug_dev_info = { - .name = TYPE_SCLP_MEMORY_HOTPLUG_DEV, - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(sclpMemoryHotplugDev), - .class_init = sclp_memory_hotplug_dev_class_init, -}; - -static void register_types(void) -{ - type_register_static(&sclp_memory_hotplug_dev_info); - type_register_static(&sclp_info); -} -type_init(register_types); diff --git a/qemu/hw/s390x/sclpcpu.c b/qemu/hw/s390x/sclpcpu.c deleted file mode 100644 index b1f3ef8c7..000000000 --- a/qemu/hw/s390x/sclpcpu.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * SCLP event type - * Signal CPU - Trigger SCLP interrupt for system CPU configure or - * de-configure - * - * Copyright IBM, Corp. 2013 - * - * Authors: - * Thang Pham <thang.pham@us.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 "sysemu/sysemu.h" -#include "hw/s390x/sclp.h" -#include "hw/s390x/event-facility.h" -#include "cpu.h" -#include "sysemu/cpus.h" -#include "sysemu/kvm.h" - -typedef struct ConfigMgtData { - EventBufferHeader ebh; - uint8_t reserved; - uint8_t event_qualifier; -} QEMU_PACKED ConfigMgtData; - -#define EVENT_QUAL_CPU_CHANGE 1 - -void raise_irq_cpu_hotplug(void) -{ - Object *obj = object_resolve_path_type("", TYPE_SCLP_CPU_HOTPLUG, NULL); - - SCLP_EVENT(obj)->event_pending = true; - - /* Trigger SCLP read operation */ - sclp_service_interrupt(0); -} - -static unsigned int send_mask(void) -{ - return SCLP_EVENT_MASK_CONFIG_MGT_DATA; -} - -static unsigned int receive_mask(void) -{ - return 0; -} - -static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, - int *slen) -{ - ConfigMgtData *cdata = (ConfigMgtData *) evt_buf_hdr; - if (*slen < sizeof(ConfigMgtData)) { - return 0; - } - - /* Event is no longer pending */ - if (!event->event_pending) { - return 0; - } - event->event_pending = false; - - /* Event header data */ - cdata->ebh.length = cpu_to_be16(sizeof(ConfigMgtData)); - cdata->ebh.type = SCLP_EVENT_CONFIG_MGT_DATA; - cdata->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; - - /* Trigger a rescan of CPUs by setting event qualifier */ - cdata->event_qualifier = EVENT_QUAL_CPU_CHANGE; - *slen -= sizeof(ConfigMgtData); - - return 1; -} - -static void cpu_class_init(ObjectClass *oc, void *data) -{ - SCLPEventClass *k = SCLP_EVENT_CLASS(oc); - DeviceClass *dc = DEVICE_CLASS(oc); - - k->get_send_mask = send_mask; - k->get_receive_mask = receive_mask; - k->read_event_data = read_event_data; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static const TypeInfo sclp_cpu_info = { - .name = TYPE_SCLP_CPU_HOTPLUG, - .parent = TYPE_SCLP_EVENT, - .instance_size = sizeof(SCLPEvent), - .class_init = cpu_class_init, - .class_size = sizeof(SCLPEventClass), -}; - -static void sclp_cpu_register_types(void) -{ - type_register_static(&sclp_cpu_info); -} - -type_init(sclp_cpu_register_types) diff --git a/qemu/hw/s390x/sclpquiesce.c b/qemu/hw/s390x/sclpquiesce.c deleted file mode 100644 index c0ecab9c3..000000000 --- a/qemu/hw/s390x/sclpquiesce.c +++ /dev/null @@ -1,143 +0,0 @@ -/* - * SCLP event type - * Signal Quiesce - trigger system powerdown request - * - * Copyright IBM, Corp. 2012 - * - * Authors: - * Heinz Graalfs <graalfs@de.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 <hw/qdev.h> -#include "sysemu/sysemu.h" -#include "hw/s390x/sclp.h" -#include "hw/s390x/event-facility.h" - -typedef struct SignalQuiesce { - EventBufferHeader ebh; - uint16_t timeout; - uint8_t unit; -} QEMU_PACKED SignalQuiesce; - -static bool can_handle_event(uint8_t type) -{ - return type == SCLP_EVENT_SIGNAL_QUIESCE; -} - -static unsigned int send_mask(void) -{ - return SCLP_EVENT_MASK_SIGNAL_QUIESCE; -} - -static unsigned int receive_mask(void) -{ - return 0; -} - -static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, - int *slen) -{ - SignalQuiesce *sq = (SignalQuiesce *) evt_buf_hdr; - - if (*slen < sizeof(SignalQuiesce)) { - return 0; - } - - if (!event->event_pending) { - return 0; - } - event->event_pending = false; - - sq->ebh.length = cpu_to_be16(sizeof(SignalQuiesce)); - sq->ebh.type = SCLP_EVENT_SIGNAL_QUIESCE; - sq->ebh.flags |= SCLP_EVENT_BUFFER_ACCEPTED; - /* - * system_powerdown does not have a timeout. Fortunately the - * timeout value is currently ignored by Linux, anyway - */ - sq->timeout = cpu_to_be16(0); - sq->unit = cpu_to_be16(0); - *slen -= sizeof(SignalQuiesce); - - return 1; -} - -static const VMStateDescription vmstate_sclpquiesce = { - .name = TYPE_SCLP_QUIESCE, - .version_id = 0, - .minimum_version_id = 0, - .fields = (VMStateField[]) { - VMSTATE_BOOL(event_pending, SCLPEvent), - VMSTATE_END_OF_LIST() - } -}; - -typedef struct QuiesceNotifier QuiesceNotifier; - -static struct QuiesceNotifier { - Notifier notifier; - SCLPEvent *event; -} qn; - -static void quiesce_powerdown_req(Notifier *n, void *opaque) -{ - QuiesceNotifier *qn = container_of(n, QuiesceNotifier, notifier); - SCLPEvent *event = qn->event; - - event->event_pending = true; - /* trigger SCLP read operation */ - sclp_service_interrupt(0); -} - -static int quiesce_init(SCLPEvent *event) -{ - qn.notifier.notify = quiesce_powerdown_req; - qn.event = event; - - qemu_register_powerdown_notifier(&qn.notifier); - - return 0; -} - -static void quiesce_reset(DeviceState *dev) -{ - SCLPEvent *event = SCLP_EVENT(dev); - - event->event_pending = false; -} - -static void quiesce_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - SCLPEventClass *k = SCLP_EVENT_CLASS(klass); - - dc->reset = quiesce_reset; - dc->vmsd = &vmstate_sclpquiesce; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); - k->init = quiesce_init; - - k->get_send_mask = send_mask; - k->get_receive_mask = receive_mask; - k->can_handle_event = can_handle_event; - k->read_event_data = read_event_data; - k->write_event_data = NULL; -} - -static const TypeInfo sclp_quiesce_info = { - .name = TYPE_SCLP_QUIESCE, - .parent = TYPE_SCLP_EVENT, - .instance_size = sizeof(SCLPEvent), - .class_init = quiesce_class_init, - .class_size = sizeof(SCLPEventClass), -}; - -static void register_types(void) -{ - type_register_static(&sclp_quiesce_info); -} - -type_init(register_types) diff --git a/qemu/hw/s390x/virtio-ccw.c b/qemu/hw/s390x/virtio-ccw.c deleted file mode 100644 index d51642db0..000000000 --- a/qemu/hw/s390x/virtio-ccw.c +++ /dev/null @@ -1,1928 +0,0 @@ -/* - * virtio ccw target implementation - * - * Copyright 2012,2015 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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/hw.h" -#include "sysemu/block-backend.h" -#include "sysemu/blockdev.h" -#include "sysemu/sysemu.h" -#include "net/net.h" -#include "hw/virtio/virtio.h" -#include "hw/virtio/virtio-serial.h" -#include "hw/virtio/virtio-net.h" -#include "hw/sysbus.h" -#include "qemu/bitops.h" -#include "qemu/error-report.h" -#include "hw/virtio/virtio-access.h" -#include "hw/virtio/virtio-bus.h" -#include "hw/s390x/adapter.h" -#include "hw/s390x/s390_flic.h" - -#include "ioinst.h" -#include "css.h" -#include "virtio-ccw.h" -#include "trace.h" - -static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, - VirtioCcwDevice *dev); - -static void virtual_css_bus_reset(BusState *qbus) -{ - /* This should actually be modelled via the generic css */ - css_reset(); -} - - -static void virtual_css_bus_class_init(ObjectClass *klass, void *data) -{ - BusClass *k = BUS_CLASS(klass); - - k->reset = virtual_css_bus_reset; -} - -static const TypeInfo virtual_css_bus_info = { - .name = TYPE_VIRTUAL_CSS_BUS, - .parent = TYPE_BUS, - .instance_size = sizeof(VirtualCssBus), - .class_init = virtual_css_bus_class_init, -}; - -VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch) -{ - VirtIODevice *vdev = NULL; - VirtioCcwDevice *dev = sch->driver_data; - - if (dev) { - vdev = virtio_bus_get_device(&dev->bus); - } - return vdev; -} - -static int virtio_ccw_set_guest2host_notifier(VirtioCcwDevice *dev, int n, - bool assign, bool set_handler) -{ - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - VirtQueue *vq = virtio_get_queue(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(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(notifier, sch_id, n, assign); - event_notifier_cleanup(notifier); - } - return r; -} - -static void virtio_ccw_start_ioeventfd(VirtioCcwDevice *dev) -{ - VirtIODevice *vdev; - int n, r; - - if (!(dev->flags & VIRTIO_CCW_FLAG_USE_IOEVENTFD) || - dev->ioeventfd_disabled || - dev->ioeventfd_started) { - return; - } - vdev = virtio_bus_get_device(&dev->bus); - for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(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(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) -{ - VirtIODevice *vdev; - int n, r; - - if (!dev->ioeventfd_started) { - return; - } - vdev = virtio_bus_get_device(&dev->bus); - for (n = 0; n < VIRTIO_CCW_QUEUE_MAX; n++) { - if (!virtio_queue_get_num(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; - BusState *bus; - DeviceState *dev; - - /* Create bridge device */ - dev = qdev_create(NULL, "virtual-css-bridge"); - qdev_init_nofail(dev); - - /* Create bus on bridge device */ - bus = qbus_create(TYPE_VIRTUAL_CSS_BUS, dev, "virtual-css"); - cbus = VIRTUAL_CSS_BUS(bus); - - /* Enable hotplugging */ - qbus_set_hotplug_handler(bus, dev, &error_abort); - - return cbus; -} - -/* Communication blocks used by several channel commands. */ -typedef struct VqInfoBlockLegacy { - uint64_t queue; - uint32_t align; - uint16_t index; - uint16_t num; -} QEMU_PACKED VqInfoBlockLegacy; - -typedef struct VqInfoBlock { - uint64_t desc; - uint32_t res0; - uint16_t index; - uint16_t num; - uint64_t avail; - uint64_t used; -} QEMU_PACKED VqInfoBlock; - -typedef struct VqConfigBlock { - uint16_t index; - uint16_t num_max; -} QEMU_PACKED VqConfigBlock; - -typedef struct VirtioFeatDesc { - uint32_t features; - uint8_t index; -} QEMU_PACKED VirtioFeatDesc; - -typedef struct VirtioThinintInfo { - hwaddr summary_indicator; - hwaddr device_indicator; - uint64_t ind_bit; - uint8_t isc; -} QEMU_PACKED VirtioThinintInfo; - -typedef struct VirtioRevInfo { - uint16_t revision; - uint16_t length; - uint8_t data[0]; -} QEMU_PACKED VirtioRevInfo; - -/* Specify where the virtqueues for the subchannel are in guest memory. */ -static int virtio_ccw_set_vqs(SubchDev *sch, VqInfoBlock *info, - VqInfoBlockLegacy *linfo) -{ - VirtIODevice *vdev = virtio_ccw_get_vdev(sch); - uint16_t index = info ? info->index : linfo->index; - uint16_t num = info ? info->num : linfo->num; - uint64_t desc = info ? info->desc : linfo->queue; - - if (index >= VIRTIO_CCW_QUEUE_MAX) { - return -EINVAL; - } - - /* Current code in virtio.c relies on 4K alignment. */ - if (linfo && desc && (linfo->align != 4096)) { - return -EINVAL; - } - - if (!vdev) { - return -EINVAL; - } - - if (info) { - virtio_queue_set_rings(vdev, index, desc, info->avail, info->used); - } else { - virtio_queue_set_addr(vdev, index, desc); - } - if (!desc) { - virtio_queue_set_vector(vdev, index, VIRTIO_NO_VECTOR); - } else { - if (info) { - /* virtio-1 allows changing the ring size. */ - if (virtio_queue_get_num(vdev, index) < num) { - /* Fail if we exceed the maximum number. */ - return -EINVAL; - } - virtio_queue_set_num(vdev, index, num); - } else if (virtio_queue_get_num(vdev, index) > num) { - /* Fail if we don't have a big enough queue. */ - return -EINVAL; - } - /* We ignore possible increased num for legacy for compatibility. */ - virtio_queue_set_vector(vdev, index, index); - } - /* tell notify handler in case of config change */ - vdev->config_vector = VIRTIO_CCW_QUEUE_MAX; - return 0; -} - -static void virtio_ccw_reset_virtio(VirtioCcwDevice *dev, VirtIODevice *vdev) -{ - virtio_ccw_stop_ioeventfd(dev); - virtio_reset(vdev); - if (dev->indicators) { - release_indicator(&dev->routes.adapter, dev->indicators); - dev->indicators = NULL; - } - if (dev->indicators2) { - release_indicator(&dev->routes.adapter, dev->indicators2); - dev->indicators2 = NULL; - } - if (dev->summary_indicator) { - release_indicator(&dev->routes.adapter, dev->summary_indicator); - dev->summary_indicator = NULL; - } - dev->sch->thinint_active = false; -} - -static int virtio_ccw_handle_set_vq(SubchDev *sch, CCW1 ccw, bool check_len, - bool is_legacy) -{ - int ret; - VqInfoBlock info; - VqInfoBlockLegacy linfo; - size_t info_len = is_legacy ? sizeof(linfo) : sizeof(info); - - if (check_len) { - if (ccw.count != info_len) { - return -EINVAL; - } - } else if (ccw.count < info_len) { - /* Can't execute command. */ - return -EINVAL; - } - if (!ccw.cda) { - return -EFAULT; - } - if (is_legacy) { - linfo.queue = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - linfo.align = address_space_ldl_be(&address_space_memory, - ccw.cda + sizeof(linfo.queue), - MEMTXATTRS_UNSPECIFIED, - NULL); - linfo.index = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(linfo.queue) - + sizeof(linfo.align), - MEMTXATTRS_UNSPECIFIED, - NULL); - linfo.num = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(linfo.queue) - + sizeof(linfo.align) - + sizeof(linfo.index), - MEMTXATTRS_UNSPECIFIED, - NULL); - ret = virtio_ccw_set_vqs(sch, NULL, &linfo); - } else { - info.desc = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - info.index = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0), - MEMTXATTRS_UNSPECIFIED, NULL); - info.num = address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0) - + sizeof(info.index), - MEMTXATTRS_UNSPECIFIED, NULL); - info.avail = address_space_ldq_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0) - + sizeof(info.index) - + sizeof(info.num), - MEMTXATTRS_UNSPECIFIED, NULL); - info.used = address_space_ldq_be(&address_space_memory, - ccw.cda + sizeof(info.desc) - + sizeof(info.res0) - + sizeof(info.index) - + sizeof(info.num) - + sizeof(info.avail), - MEMTXATTRS_UNSPECIFIED, NULL); - ret = virtio_ccw_set_vqs(sch, &info, NULL); - } - sch->curr_status.scsw.count = 0; - return ret; -} - -static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw) -{ - int ret; - VirtioRevInfo revinfo; - uint8_t status; - VirtioFeatDesc features; - void *config; - hwaddr indicators; - VqConfigBlock vq_config; - VirtioCcwDevice *dev = sch->driver_data; - VirtIODevice *vdev = virtio_ccw_get_vdev(sch); - bool check_len; - int len; - hwaddr hw_len; - VirtioThinintInfo *thinint; - - if (!dev) { - return -EINVAL; - } - - trace_virtio_ccw_interpret_ccw(sch->cssid, sch->ssid, sch->schid, - ccw.cmd_code); - check_len = !((ccw.flags & CCW_FLAG_SLI) && !(ccw.flags & CCW_FLAG_DC)); - - /* Look at the command. */ - switch (ccw.cmd_code) { - case CCW_CMD_SET_VQ: - ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1); - break; - case CCW_CMD_VDEV_RESET: - virtio_ccw_reset_virtio(dev, vdev); - ret = 0; - break; - case CCW_CMD_READ_FEAT: - if (check_len) { - if (ccw.count != sizeof(features)) { - ret = -EINVAL; - break; - } - } else if (ccw.count < sizeof(features)) { - /* Can't execute command. */ - ret = -EINVAL; - break; - } - if (!ccw.cda) { - ret = -EFAULT; - } else { - features.index = address_space_ldub(&address_space_memory, - ccw.cda - + sizeof(features.features), - MEMTXATTRS_UNSPECIFIED, - NULL); - if (features.index == 0) { - if (dev->revision >= 1) { - /* Don't offer legacy features for modern devices. */ - features.features = (uint32_t) - (vdev->host_features & ~VIRTIO_LEGACY_FEATURES); - } else { - features.features = (uint32_t)vdev->host_features; - } - } else if ((features.index == 1) && (dev->revision >= 1)) { - /* - * Only offer feature bits beyond 31 if the guest has - * negotiated at least revision 1. - */ - features.features = (uint32_t)(vdev->host_features >> 32); - } else { - /* Return zeroes if the guest supports more feature bits. */ - features.features = 0; - } - address_space_stl_le(&address_space_memory, ccw.cda, - features.features, MEMTXATTRS_UNSPECIFIED, - NULL); - sch->curr_status.scsw.count = ccw.count - sizeof(features); - ret = 0; - } - break; - case CCW_CMD_WRITE_FEAT: - if (check_len) { - if (ccw.count != sizeof(features)) { - ret = -EINVAL; - break; - } - } else if (ccw.count < sizeof(features)) { - /* Can't execute command. */ - ret = -EINVAL; - break; - } - if (!ccw.cda) { - ret = -EFAULT; - } else { - features.index = address_space_ldub(&address_space_memory, - ccw.cda - + sizeof(features.features), - MEMTXATTRS_UNSPECIFIED, - NULL); - features.features = address_space_ldl_le(&address_space_memory, - ccw.cda, - MEMTXATTRS_UNSPECIFIED, - NULL); - if (features.index == 0) { - virtio_set_features(vdev, - (vdev->guest_features & 0xffffffff00000000ULL) | - features.features); - } else if ((features.index == 1) && (dev->revision >= 1)) { - /* - * If the guest did not negotiate at least revision 1, - * we did not offer it any feature bits beyond 31. Such a - * guest passing us any bit here is therefore buggy. - */ - virtio_set_features(vdev, - (vdev->guest_features & 0x00000000ffffffffULL) | - ((uint64_t)features.features << 32)); - } else { - /* - * If the guest supports more feature bits, assert that it - * passes us zeroes for those we don't support. - */ - if (features.features) { - fprintf(stderr, "Guest bug: features[%i]=%x (expected 0)\n", - features.index, features.features); - /* XXX: do a unit check here? */ - } - } - sch->curr_status.scsw.count = ccw.count - sizeof(features); - ret = 0; - } - break; - case CCW_CMD_READ_CONF: - if (check_len) { - if (ccw.count > vdev->config_len) { - ret = -EINVAL; - break; - } - } - len = MIN(ccw.count, vdev->config_len); - if (!ccw.cda) { - ret = -EFAULT; - } else { - virtio_bus_get_vdev_config(&dev->bus, vdev->config); - /* XXX config space endianness */ - cpu_physical_memory_write(ccw.cda, vdev->config, len); - sch->curr_status.scsw.count = ccw.count - len; - ret = 0; - } - break; - case CCW_CMD_WRITE_CONF: - if (check_len) { - if (ccw.count > vdev->config_len) { - ret = -EINVAL; - break; - } - } - len = MIN(ccw.count, vdev->config_len); - hw_len = len; - if (!ccw.cda) { - ret = -EFAULT; - } else { - config = cpu_physical_memory_map(ccw.cda, &hw_len, 0); - if (!config) { - ret = -EFAULT; - } else { - len = hw_len; - /* XXX config space endianness */ - memcpy(vdev->config, config, len); - cpu_physical_memory_unmap(config, hw_len, 0, hw_len); - virtio_bus_set_vdev_config(&dev->bus, vdev->config); - sch->curr_status.scsw.count = ccw.count - len; - ret = 0; - } - } - break; - case CCW_CMD_WRITE_STATUS: - if (check_len) { - if (ccw.count != sizeof(status)) { - ret = -EINVAL; - break; - } - } else if (ccw.count < sizeof(status)) { - /* Can't execute command. */ - ret = -EINVAL; - break; - } - if (!ccw.cda) { - ret = -EFAULT; - } else { - status = address_space_ldub(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - if (!(status & VIRTIO_CONFIG_S_DRIVER_OK)) { - virtio_ccw_stop_ioeventfd(dev); - } - if (virtio_set_status(vdev, status) == 0) { - if (vdev->status == 0) { - virtio_ccw_reset_virtio(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; - } else { - /* Trigger a command reject. */ - ret = -ENOSYS; - } - } - break; - case CCW_CMD_SET_IND: - if (check_len) { - if (ccw.count != sizeof(indicators)) { - ret = -EINVAL; - break; - } - } else if (ccw.count < sizeof(indicators)) { - /* Can't execute command. */ - ret = -EINVAL; - break; - } - if (sch->thinint_active) { - /* Trigger a command reject. */ - ret = -ENOSYS; - break; - } - if (!ccw.cda) { - ret = -EFAULT; - } else { - indicators = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - dev->indicators = get_indicator(indicators, sizeof(uint64_t)); - sch->curr_status.scsw.count = ccw.count - sizeof(indicators); - ret = 0; - } - break; - case CCW_CMD_SET_CONF_IND: - if (check_len) { - if (ccw.count != sizeof(indicators)) { - ret = -EINVAL; - break; - } - } else if (ccw.count < sizeof(indicators)) { - /* Can't execute command. */ - ret = -EINVAL; - break; - } - if (!ccw.cda) { - ret = -EFAULT; - } else { - indicators = address_space_ldq_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - dev->indicators2 = get_indicator(indicators, sizeof(uint64_t)); - sch->curr_status.scsw.count = ccw.count - sizeof(indicators); - ret = 0; - } - break; - case CCW_CMD_READ_VQ_CONF: - if (check_len) { - if (ccw.count != sizeof(vq_config)) { - ret = -EINVAL; - break; - } - } else if (ccw.count < sizeof(vq_config)) { - /* Can't execute command. */ - ret = -EINVAL; - break; - } - if (!ccw.cda) { - ret = -EFAULT; - } else { - vq_config.index = address_space_lduw_be(&address_space_memory, - ccw.cda, - MEMTXATTRS_UNSPECIFIED, - NULL); - if (vq_config.index >= VIRTIO_CCW_QUEUE_MAX) { - ret = -EINVAL; - break; - } - vq_config.num_max = virtio_queue_get_num(vdev, - vq_config.index); - address_space_stw_be(&address_space_memory, - ccw.cda + sizeof(vq_config.index), - vq_config.num_max, - MEMTXATTRS_UNSPECIFIED, - NULL); - sch->curr_status.scsw.count = ccw.count - sizeof(vq_config); - ret = 0; - } - break; - case CCW_CMD_SET_IND_ADAPTER: - if (check_len) { - if (ccw.count != sizeof(*thinint)) { - ret = -EINVAL; - break; - } - } else if (ccw.count < sizeof(*thinint)) { - /* Can't execute command. */ - ret = -EINVAL; - break; - } - len = sizeof(*thinint); - hw_len = len; - if (!ccw.cda) { - ret = -EFAULT; - } else if (dev->indicators && !sch->thinint_active) { - /* Trigger a command reject. */ - ret = -ENOSYS; - } else { - thinint = cpu_physical_memory_map(ccw.cda, &hw_len, 0); - if (!thinint) { - ret = -EFAULT; - } else { - uint64_t ind_bit = ldq_be_p(&thinint->ind_bit); - - len = hw_len; - dev->summary_indicator = - get_indicator(ldq_be_p(&thinint->summary_indicator), - sizeof(uint8_t)); - dev->indicators = - get_indicator(ldq_be_p(&thinint->device_indicator), - ind_bit / 8 + 1); - dev->thinint_isc = thinint->isc; - dev->routes.adapter.ind_offset = ind_bit; - dev->routes.adapter.summary_offset = 7; - cpu_physical_memory_unmap(thinint, hw_len, 0, hw_len); - ret = css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO, - dev->thinint_isc, true, false, - &dev->routes.adapter.adapter_id); - assert(ret == 0); - sch->thinint_active = ((dev->indicators != NULL) && - (dev->summary_indicator != NULL)); - sch->curr_status.scsw.count = ccw.count - len; - ret = 0; - } - } - break; - case CCW_CMD_SET_VIRTIO_REV: - len = sizeof(revinfo); - if (ccw.count < len) { - ret = -EINVAL; - break; - } - if (!ccw.cda) { - ret = -EFAULT; - break; - } - revinfo.revision = - address_space_lduw_be(&address_space_memory, ccw.cda, - MEMTXATTRS_UNSPECIFIED, NULL); - revinfo.length = - address_space_lduw_be(&address_space_memory, - ccw.cda + sizeof(revinfo.revision), - MEMTXATTRS_UNSPECIFIED, NULL); - if (ccw.count < len + revinfo.length || - (check_len && ccw.count > len + revinfo.length)) { - ret = -EINVAL; - break; - } - /* - * Once we start to support revisions with additional data, we'll - * need to fetch it here. Nothing to do for now, though. - */ - if (dev->revision >= 0 || - revinfo.revision > virtio_ccw_rev_max(dev)) { - ret = -ENOSYS; - break; - } - ret = 0; - dev->revision = revinfo.revision; - break; - default: - ret = -ENOSYS; - break; - } - return ret; -} - -static void virtio_sch_disable_cb(SubchDev *sch) -{ - VirtioCcwDevice *dev = sch->driver_data; - - dev->revision = -1; -} - -static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp) -{ - unsigned int cssid = 0; - unsigned int ssid = 0; - unsigned int schid; - unsigned int devno; - bool have_devno = false; - bool found = false; - SubchDev *sch; - int num; - Error *err = NULL; - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_GET_CLASS(dev); - - sch = g_malloc0(sizeof(SubchDev)); - - sch->driver_data = dev; - dev->sch = sch; - - dev->indicators = NULL; - - /* Initialize subchannel structure. */ - sch->channel_prog = 0x0; - sch->last_cmd_valid = false; - sch->thinint_active = false; - /* - * Use a device number if provided. Otherwise, fall back to subchannel - * number. - */ - if (dev->bus_id) { - num = sscanf(dev->bus_id, "%x.%x.%04x", &cssid, &ssid, &devno); - if (num == 3) { - if ((cssid > MAX_CSSID) || (ssid > MAX_SSID)) { - error_setg(errp, "Invalid cssid or ssid: cssid %x, ssid %x", - cssid, ssid); - goto out_err; - } - /* Enforce use of virtual cssid. */ - if (cssid != VIRTUAL_CSSID) { - error_setg(errp, "cssid %x not valid for virtio devices", - cssid); - goto out_err; - } - if (css_devno_used(cssid, ssid, devno)) { - error_setg(errp, "Device %x.%x.%04x already exists", - cssid, ssid, devno); - goto out_err; - } - sch->cssid = cssid; - sch->ssid = ssid; - sch->devno = devno; - have_devno = true; - } else { - error_setg(errp, "Malformed devno parameter '%s'", dev->bus_id); - goto out_err; - } - } - - /* Find the next free id. */ - if (have_devno) { - for (schid = 0; schid <= MAX_SCHID; schid++) { - if (!css_find_subch(1, cssid, ssid, schid)) { - sch->schid = schid; - css_subch_assign(cssid, ssid, schid, devno, sch); - found = true; - break; - } - } - if (!found) { - error_setg(errp, "No free subchannel found for %x.%x.%04x", - cssid, ssid, devno); - goto out_err; - } - trace_virtio_ccw_new_device(cssid, ssid, schid, devno, - "user-configured"); - } else { - cssid = VIRTUAL_CSSID; - for (ssid = 0; ssid <= MAX_SSID; ssid++) { - for (schid = 0; schid <= MAX_SCHID; schid++) { - if (!css_find_subch(1, cssid, ssid, schid)) { - sch->cssid = cssid; - sch->ssid = ssid; - sch->schid = schid; - devno = schid; - /* - * If the devno is already taken, look further in this - * subchannel set. - */ - while (css_devno_used(cssid, ssid, devno)) { - if (devno == MAX_SCHID) { - devno = 0; - } else if (devno == schid - 1) { - error_setg(errp, "No free devno found"); - goto out_err; - } else { - devno++; - } - } - sch->devno = devno; - css_subch_assign(cssid, ssid, schid, devno, sch); - found = true; - break; - } - } - if (found) { - break; - } - } - if (!found) { - error_setg(errp, "Virtual channel subsystem is full!"); - goto out_err; - } - trace_virtio_ccw_new_device(cssid, ssid, schid, devno, - "auto-configured"); - } - - /* Build initial schib. */ - css_sch_build_virtual_schib(sch, 0, VIRTIO_CCW_CHPID_TYPE); - - sch->ccw_cb = virtio_ccw_cb; - sch->disable_cb = virtio_sch_disable_cb; - - /* Build senseid data. */ - memset(&sch->id, 0, sizeof(SenseId)); - sch->id.reserved = 0xff; - sch->id.cu_type = VIRTIO_CCW_CU_TYPE; - - dev->revision = -1; - - if (k->realize) { - k->realize(dev, &err); - } - if (err) { - error_propagate(errp, err); - css_subch_assign(cssid, ssid, schid, devno, NULL); - goto out_err; - } - - return; - -out_err: - dev->sch = NULL; - g_free(sch); -} - -static int virtio_ccw_exit(VirtioCcwDevice *dev) -{ - SubchDev *sch = dev->sch; - - if (sch) { - css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL); - g_free(sch); - } - if (dev->indicators) { - release_indicator(&dev->routes.adapter, dev->indicators); - dev->indicators = NULL; - } - return 0; -} - -static void virtio_ccw_net_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - DeviceState *qdev = DEVICE(ccw_dev); - VirtIONetCcw *dev = VIRTIO_NET_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - - virtio_net_set_netclient_name(&dev->vdev, qdev->id, - object_get_typename(OBJECT(qdev))); - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - } -} - -static void virtio_ccw_net_instance_init(Object *obj) -{ - VirtIONetCcw *dev = VIRTIO_NET_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_NET); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static void virtio_ccw_blk_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - } -} - -static void virtio_ccw_blk_instance_init(Object *obj) -{ - VirtIOBlkCcw *dev = VIRTIO_BLK_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_BLK); - object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev),"iothread", - &error_abort); - object_property_add_alias(obj, "bootindex", OBJECT(&dev->vdev), - "bootindex", &error_abort); -} - -static void virtio_ccw_serial_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - DeviceState *proxy = DEVICE(ccw_dev); - Error *err = NULL; - char *bus_name; - - /* - * For command line compatibility, this sets the virtio-serial-device bus - * name as before. - */ - if (proxy->id) { - bus_name = g_strdup_printf("%s.0", proxy->id); - virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); - g_free(bus_name); - } - - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - } -} - - -static void virtio_ccw_serial_instance_init(Object *obj) -{ - VirtioSerialCcw *dev = VIRTIO_SERIAL_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_SERIAL); -} - -static void virtio_ccw_balloon_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - } -} - -static void virtio_ccw_balloon_instance_init(Object *obj) -{ - VirtIOBalloonCcw *dev = VIRTIO_BALLOON_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_BALLOON); - object_property_add_alias(obj, "guest-stats", OBJECT(&dev->vdev), - "guest-stats", &error_abort); - object_property_add_alias(obj, "guest-stats-polling-interval", - OBJECT(&dev->vdev), - "guest-stats-polling-interval", &error_abort); -} - -static void virtio_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - DeviceState *qdev = DEVICE(ccw_dev); - Error *err = NULL; - char *bus_name; - - /* - * For command line compatibility, this sets the virtio-scsi-device bus - * name as before. - */ - if (qdev->id) { - bus_name = g_strdup_printf("%s.0", qdev->id); - virtio_device_set_child_bus_name(VIRTIO_DEVICE(vdev), bus_name); - g_free(bus_name); - } - - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - } -} - -static void virtio_ccw_scsi_instance_init(Object *obj) -{ - VirtIOSCSICcw *dev = VIRTIO_SCSI_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_SCSI); - object_property_add_alias(obj, "iothread", OBJECT(&dev->vdev), "iothread", - &error_abort); -} - -#ifdef CONFIG_VHOST_SCSI -static void vhost_ccw_scsi_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - VHostSCSICcw *dev = VHOST_SCSI_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - } -} - -static void vhost_ccw_scsi_instance_init(Object *obj) -{ - VHostSCSICcw *dev = VHOST_SCSI_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VHOST_SCSI); -} -#endif - -static void virtio_ccw_rng_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - VirtIORNGCcw *dev = VIRTIO_RNG_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - return; - } - - object_property_set_link(OBJECT(dev), - OBJECT(dev->vdev.conf.rng), "rng", - NULL); -} - -/* DeviceState to VirtioCcwDevice. Note: used on datapath, - * be careful and test performance if you change this. - */ -static inline VirtioCcwDevice *to_virtio_ccw_dev_fast(DeviceState *d) -{ - return container_of(d, VirtioCcwDevice, parent_obj); -} - -static uint8_t virtio_set_ind_atomic(SubchDev *sch, uint64_t ind_loc, - uint8_t to_be_set) -{ - uint8_t ind_old, ind_new; - hwaddr len = 1; - uint8_t *ind_addr; - - ind_addr = cpu_physical_memory_map(ind_loc, &len, 1); - if (!ind_addr) { - error_report("%s(%x.%x.%04x): unable to access indicator", - __func__, sch->cssid, sch->ssid, sch->schid); - return -1; - } - do { - ind_old = *ind_addr; - ind_new = ind_old | to_be_set; - } while (atomic_cmpxchg(ind_addr, ind_old, ind_new) != ind_old); - cpu_physical_memory_unmap(ind_addr, len, 1, len); - - return ind_old; -} - -static void virtio_ccw_notify(DeviceState *d, uint16_t vector) -{ - VirtioCcwDevice *dev = to_virtio_ccw_dev_fast(d); - SubchDev *sch = dev->sch; - uint64_t indicators; - - /* queue indicators + secondary indicators */ - if (vector >= VIRTIO_CCW_QUEUE_MAX + 64) { - return; - } - - if (vector < VIRTIO_CCW_QUEUE_MAX) { - if (!dev->indicators) { - return; - } - if (sch->thinint_active) { - /* - * In the adapter interrupt case, indicators points to a - * memory area that may be (way) larger than 64 bit and - * ind_bit indicates the start of the indicators in a big - * endian notation. - */ - uint64_t ind_bit = dev->routes.adapter.ind_offset; - - virtio_set_ind_atomic(sch, dev->indicators->addr + - (ind_bit + vector) / 8, - 0x80 >> ((ind_bit + vector) % 8)); - if (!virtio_set_ind_atomic(sch, dev->summary_indicator->addr, - 0x01)) { - css_adapter_interrupt(dev->thinint_isc); - } - } else { - indicators = address_space_ldq(&address_space_memory, - dev->indicators->addr, - MEMTXATTRS_UNSPECIFIED, - NULL); - indicators |= 1ULL << vector; - address_space_stq(&address_space_memory, dev->indicators->addr, - indicators, MEMTXATTRS_UNSPECIFIED, NULL); - css_conditional_io_interrupt(sch); - } - } else { - if (!dev->indicators2) { - return; - } - vector = 0; - indicators = address_space_ldq(&address_space_memory, - dev->indicators2->addr, - MEMTXATTRS_UNSPECIFIED, - NULL); - indicators |= 1ULL << vector; - address_space_stq(&address_space_memory, dev->indicators2->addr, - indicators, MEMTXATTRS_UNSPECIFIED, NULL); - css_conditional_io_interrupt(sch); - } -} - -static void virtio_ccw_reset(DeviceState *d) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - - virtio_ccw_reset_virtio(dev, vdev); - css_reset_sch(dev->sch); -} - -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); - } -} - -static bool virtio_ccw_query_guest_notifiers(DeviceState *d) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - - return !!(dev->sch->curr_status.pmcw.flags & PMCW_FLAGS_MASK_ENA); -} - -static int virtio_ccw_set_host_notifier(DeviceState *d, int n, bool assign) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - - /* Stop using the generic ioeventfd, we are doing eventfd handling - * ourselves below */ - dev->ioeventfd_disabled = assign; - if (assign) { - virtio_ccw_stop_ioeventfd(dev); - } - return virtio_ccw_set_guest2host_notifier(dev, n, assign, false); -} - -static int virtio_ccw_get_mappings(VirtioCcwDevice *dev) -{ - int r; - - if (!dev->sch->thinint_active) { - return -EINVAL; - } - - r = map_indicator(&dev->routes.adapter, dev->summary_indicator); - if (r) { - return r; - } - r = map_indicator(&dev->routes.adapter, dev->indicators); - if (r) { - return r; - } - dev->routes.adapter.summary_addr = dev->summary_indicator->map; - dev->routes.adapter.ind_addr = dev->indicators->map; - - return 0; -} - -static int virtio_ccw_setup_irqroutes(VirtioCcwDevice *dev, int nvqs) -{ - int i; - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - int ret; - S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); - - ret = virtio_ccw_get_mappings(dev); - if (ret) { - return ret; - } - for (i = 0; i < nvqs; i++) { - if (!virtio_queue_get_num(vdev, i)) { - break; - } - } - dev->routes.num_routes = i; - return fsc->add_adapter_routes(fs, &dev->routes); -} - -static void virtio_ccw_release_irqroutes(VirtioCcwDevice *dev, int nvqs) -{ - S390FLICState *fs = s390_get_flic(); - S390FLICStateClass *fsc = S390_FLIC_COMMON_GET_CLASS(fs); - - fsc->release_adapter_routes(fs, &dev->routes); -} - -static int virtio_ccw_add_irqfd(VirtioCcwDevice *dev, int n) -{ - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - VirtQueue *vq = virtio_get_queue(vdev, n); - EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); - - return kvm_irqchip_add_irqfd_notifier_gsi(kvm_state, notifier, NULL, - dev->routes.gsi[n]); -} - -static void virtio_ccw_remove_irqfd(VirtioCcwDevice *dev, int n) -{ - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - VirtQueue *vq = virtio_get_queue(vdev, n); - EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); - int ret; - - ret = kvm_irqchip_remove_irqfd_notifier_gsi(kvm_state, notifier, - dev->routes.gsi[n]); - assert(ret == 0); -} - -static int virtio_ccw_set_guest_notifier(VirtioCcwDevice *dev, int n, - bool assign, bool with_irqfd) -{ - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - VirtQueue *vq = virtio_get_queue(vdev, n); - EventNotifier *notifier = virtio_queue_get_guest_notifier(vq); - VirtioDeviceClass *k = VIRTIO_DEVICE_GET_CLASS(vdev); - - if (assign) { - int r = event_notifier_init(notifier, 0); - - if (r < 0) { - return r; - } - virtio_queue_set_guest_notifier_fd_handler(vq, true, with_irqfd); - if (with_irqfd) { - r = virtio_ccw_add_irqfd(dev, n); - if (r) { - virtio_queue_set_guest_notifier_fd_handler(vq, false, - with_irqfd); - return r; - } - } - /* - * We do not support individual masking for channel devices, so we - * need to manually trigger any guest masking callbacks here. - */ - if (k->guest_notifier_mask) { - k->guest_notifier_mask(vdev, n, false); - } - /* get lost events and re-inject */ - if (k->guest_notifier_pending && - k->guest_notifier_pending(vdev, n)) { - event_notifier_set(notifier); - } - } else { - if (k->guest_notifier_mask) { - k->guest_notifier_mask(vdev, n, true); - } - if (with_irqfd) { - virtio_ccw_remove_irqfd(dev, n); - } - virtio_queue_set_guest_notifier_fd_handler(vq, false, with_irqfd); - event_notifier_cleanup(notifier); - } - return 0; -} - -static int virtio_ccw_set_guest_notifiers(DeviceState *d, int nvqs, - bool assigned) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - bool with_irqfd = dev->sch->thinint_active && kvm_irqfds_enabled(); - int r, n; - - if (with_irqfd && assigned) { - /* irq routes need to be set up before assigning irqfds */ - r = virtio_ccw_setup_irqroutes(dev, nvqs); - if (r < 0) { - goto irqroute_error; - } - } - for (n = 0; n < nvqs; n++) { - if (!virtio_queue_get_num(vdev, n)) { - break; - } - r = virtio_ccw_set_guest_notifier(dev, n, assigned, with_irqfd); - if (r < 0) { - goto assign_error; - } - } - if (with_irqfd && !assigned) { - /* release irq routes after irqfds have been released */ - virtio_ccw_release_irqroutes(dev, nvqs); - } - return 0; - -assign_error: - while (--n >= 0) { - virtio_ccw_set_guest_notifier(dev, n, !assigned, false); - } -irqroute_error: - if (with_irqfd && assigned) { - virtio_ccw_release_irqroutes(dev, nvqs); - } - return r; -} - -static void virtio_ccw_save_queue(DeviceState *d, int n, QEMUFile *f) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - - qemu_put_be16(f, virtio_queue_vector(vdev, n)); -} - -static int virtio_ccw_load_queue(DeviceState *d, int n, QEMUFile *f) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - uint16_t vector; - - qemu_get_be16s(f, &vector); - virtio_queue_set_vector(vdev, n , vector); - - return 0; -} - -static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - SubchDev *s = dev->sch; - VirtIODevice *vdev = virtio_ccw_get_vdev(s); - - subch_device_save(s, f); - if (dev->indicators != NULL) { - qemu_put_be32(f, dev->indicators->len); - qemu_put_be64(f, dev->indicators->addr); - } else { - qemu_put_be32(f, 0); - qemu_put_be64(f, 0UL); - } - if (dev->indicators2 != NULL) { - qemu_put_be32(f, dev->indicators2->len); - qemu_put_be64(f, dev->indicators2->addr); - } else { - qemu_put_be32(f, 0); - qemu_put_be64(f, 0UL); - } - if (dev->summary_indicator != NULL) { - qemu_put_be32(f, dev->summary_indicator->len); - qemu_put_be64(f, dev->summary_indicator->addr); - } else { - qemu_put_be32(f, 0); - qemu_put_be64(f, 0UL); - } - qemu_put_be16(f, vdev->config_vector); - qemu_put_be64(f, dev->routes.adapter.ind_offset); - qemu_put_byte(f, dev->thinint_isc); - qemu_put_be32(f, dev->revision); -} - -static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - SubchDev *s = dev->sch; - VirtIODevice *vdev = virtio_ccw_get_vdev(s); - int len; - - s->driver_data = dev; - subch_device_load(s, f); - len = qemu_get_be32(f); - if (len != 0) { - dev->indicators = get_indicator(qemu_get_be64(f), len); - } else { - qemu_get_be64(f); - dev->indicators = NULL; - } - len = qemu_get_be32(f); - if (len != 0) { - dev->indicators2 = get_indicator(qemu_get_be64(f), len); - } else { - qemu_get_be64(f); - dev->indicators2 = NULL; - } - len = qemu_get_be32(f); - if (len != 0) { - dev->summary_indicator = get_indicator(qemu_get_be64(f), len); - } else { - qemu_get_be64(f); - dev->summary_indicator = NULL; - } - qemu_get_be16s(f, &vdev->config_vector); - dev->routes.adapter.ind_offset = qemu_get_be64(f); - dev->thinint_isc = qemu_get_byte(f); - dev->revision = qemu_get_be32(f); - if (s->thinint_active) { - return css_register_io_adapter(CSS_IO_ADAPTER_VIRTIO, - dev->thinint_isc, true, false, - &dev->routes.adapter.adapter_id); - } - - return 0; -} - -/* This is called by virtio-bus just after the device is plugged. */ -static void virtio_ccw_device_plugged(DeviceState *d, Error **errp) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - SubchDev *sch = dev->sch; - int n = virtio_get_num_queues(vdev); - - if (virtio_get_num_queues(vdev) > VIRTIO_CCW_QUEUE_MAX) { - error_setg(errp, "The nubmer of virtqueues %d " - "exceeds ccw limit %d", n, - VIRTIO_CCW_QUEUE_MAX); - return; - } - - if (!kvm_eventfds_enabled()) { - dev->flags &= ~VIRTIO_CCW_FLAG_USE_IOEVENTFD; - } - - sch->id.cu_model = virtio_bus_get_vdev_id(&dev->bus); - - if (dev->max_rev >= 1) { - virtio_add_feature(&vdev->host_features, VIRTIO_F_VERSION_1); - } - - css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, - d->hotplugged, 1); -} - -static void virtio_ccw_post_plugged(DeviceState *d, Error **errp) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - VirtIODevice *vdev = virtio_bus_get_device(&dev->bus); - - if (!virtio_host_has_feature(vdev, VIRTIO_F_VERSION_1)) { - /* A backend didn't support modern virtio. */ - dev->max_rev = 0; - } -} - -static void virtio_ccw_device_unplugged(DeviceState *d) -{ - VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d); - - virtio_ccw_stop_ioeventfd(dev); -} -/**************** Virtio-ccw Bus Device Descriptions *******************/ - -static Property virtio_ccw_net_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - 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_net_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = virtio_ccw_net_realize; - k->exit = virtio_ccw_exit; - dc->reset = virtio_ccw_reset; - dc->props = virtio_ccw_net_properties; - set_bit(DEVICE_CATEGORY_NETWORK, dc->categories); -} - -static const TypeInfo virtio_ccw_net = { - .name = TYPE_VIRTIO_NET_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtIONetCcw), - .instance_init = virtio_ccw_net_instance_init, - .class_init = virtio_ccw_net_class_init, -}; - -static Property virtio_ccw_blk_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - 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_blk_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = virtio_ccw_blk_realize; - k->exit = virtio_ccw_exit; - dc->reset = virtio_ccw_reset; - dc->props = virtio_ccw_blk_properties; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); -} - -static const TypeInfo virtio_ccw_blk = { - .name = TYPE_VIRTIO_BLK_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtIOBlkCcw), - .instance_init = virtio_ccw_blk_instance_init, - .class_init = virtio_ccw_blk_class_init, -}; - -static Property virtio_ccw_serial_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - 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_serial_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = virtio_ccw_serial_realize; - k->exit = virtio_ccw_exit; - dc->reset = virtio_ccw_reset; - dc->props = virtio_ccw_serial_properties; - set_bit(DEVICE_CATEGORY_INPUT, dc->categories); -} - -static const TypeInfo virtio_ccw_serial = { - .name = TYPE_VIRTIO_SERIAL_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtioSerialCcw), - .instance_init = virtio_ccw_serial_instance_init, - .class_init = virtio_ccw_serial_class_init, -}; - -static Property virtio_ccw_balloon_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - 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_balloon_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = virtio_ccw_balloon_realize; - k->exit = virtio_ccw_exit; - dc->reset = virtio_ccw_reset; - dc->props = virtio_ccw_balloon_properties; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static const TypeInfo virtio_ccw_balloon = { - .name = TYPE_VIRTIO_BALLOON_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtIOBalloonCcw), - .instance_init = virtio_ccw_balloon_instance_init, - .class_init = virtio_ccw_balloon_class_init, -}; - -static Property virtio_ccw_scsi_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - 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_scsi_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = virtio_ccw_scsi_realize; - k->exit = virtio_ccw_exit; - dc->reset = virtio_ccw_reset; - dc->props = virtio_ccw_scsi_properties; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); -} - -static const TypeInfo virtio_ccw_scsi = { - .name = TYPE_VIRTIO_SCSI_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtIOSCSICcw), - .instance_init = virtio_ccw_scsi_instance_init, - .class_init = virtio_ccw_scsi_class_init, -}; - -#ifdef CONFIG_VHOST_SCSI -static Property vhost_ccw_scsi_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - DEFINE_PROP_UINT32("max_revision", VirtioCcwDevice, max_rev, - VIRTIO_CCW_MAX_REV), - DEFINE_PROP_END_OF_LIST(), -}; - -static void vhost_ccw_scsi_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = vhost_ccw_scsi_realize; - k->exit = virtio_ccw_exit; - dc->reset = virtio_ccw_reset; - dc->props = vhost_ccw_scsi_properties; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); -} - -static const TypeInfo vhost_ccw_scsi = { - .name = TYPE_VHOST_SCSI_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VHostSCSICcw), - .instance_init = vhost_ccw_scsi_instance_init, - .class_init = vhost_ccw_scsi_class_init, -}; -#endif - -static void virtio_ccw_rng_instance_init(Object *obj) -{ - VirtIORNGCcw *dev = VIRTIO_RNG_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_RNG); - object_property_add_alias(obj, "rng", OBJECT(&dev->vdev), - "rng", &error_abort); -} - -static Property virtio_ccw_rng_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - 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_rng_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->realize = virtio_ccw_rng_realize; - k->exit = virtio_ccw_exit; - dc->reset = virtio_ccw_reset; - dc->props = virtio_ccw_rng_properties; - set_bit(DEVICE_CATEGORY_MISC, dc->categories); -} - -static const TypeInfo virtio_ccw_rng = { - .name = TYPE_VIRTIO_RNG_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(VirtIORNGCcw), - .instance_init = virtio_ccw_rng_instance_init, - .class_init = virtio_ccw_rng_class_init, -}; - -static void virtio_ccw_busdev_realize(DeviceState *dev, Error **errp) -{ - VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; - - virtio_ccw_bus_new(&_dev->bus, sizeof(_dev->bus), _dev); - virtio_ccw_device_realize(_dev, errp); -} - -static int virtio_ccw_busdev_exit(DeviceState *dev) -{ - VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; - VirtIOCCWDeviceClass *_info = VIRTIO_CCW_DEVICE_GET_CLASS(dev); - - return _info->exit(_dev); -} - -static void virtio_ccw_busdev_unplug(HotplugHandler *hotplug_dev, - DeviceState *dev, Error **errp) -{ - VirtioCcwDevice *_dev = (VirtioCcwDevice *)dev; - SubchDev *sch = _dev->sch; - - virtio_ccw_stop_ioeventfd(_dev); - - /* - * We should arrive here only for device_del, since we don't support - * direct hot(un)plug of channels, but only through virtio. - */ - assert(sch != NULL); - /* Subchannel is now disabled and no longer valid. */ - sch->curr_status.pmcw.flags &= ~(PMCW_FLAGS_MASK_ENA | - PMCW_FLAGS_MASK_DNV); - - css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid, 1, 0); - - object_unparent(OBJECT(dev)); -} - -static void virtio_ccw_device_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - - dc->realize = virtio_ccw_busdev_realize; - dc->exit = virtio_ccw_busdev_exit; - dc->bus_type = TYPE_VIRTUAL_CSS_BUS; -} - -static const TypeInfo virtio_ccw_device_info = { - .name = TYPE_VIRTIO_CCW_DEVICE, - .parent = TYPE_DEVICE, - .instance_size = sizeof(VirtioCcwDevice), - .class_init = virtio_ccw_device_class_init, - .class_size = sizeof(VirtIOCCWDeviceClass), - .abstract = true, -}; - -/***************** Virtual-css Bus Bridge Device ********************/ -/* Only required to have the virtio bus as child in the system bus */ - -static int virtual_css_bridge_init(SysBusDevice *dev) -{ - /* nothing */ - return 0; -} - -static void virtual_css_bridge_class_init(ObjectClass *klass, void *data) -{ - SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass); - HotplugHandlerClass *hc = HOTPLUG_HANDLER_CLASS(klass); - DeviceClass *dc = DEVICE_CLASS(klass); - - k->init = virtual_css_bridge_init; - hc->unplug = virtio_ccw_busdev_unplug; - set_bit(DEVICE_CATEGORY_BRIDGE, dc->categories); -} - -static const TypeInfo virtual_css_bridge_info = { - .name = "virtual-css-bridge", - .parent = TYPE_SYS_BUS_DEVICE, - .instance_size = sizeof(SysBusDevice), - .class_init = virtual_css_bridge_class_init, - .interfaces = (InterfaceInfo[]) { - { TYPE_HOTPLUG_HANDLER }, - { } - } -}; - -/* virtio-ccw-bus */ - -static void virtio_ccw_bus_new(VirtioBusState *bus, size_t bus_size, - VirtioCcwDevice *dev) -{ - DeviceState *qdev = DEVICE(dev); - char virtio_bus_name[] = "virtio-bus"; - - qbus_create_inplace(bus, bus_size, TYPE_VIRTIO_CCW_BUS, - qdev, virtio_bus_name); -} - -static void virtio_ccw_bus_class_init(ObjectClass *klass, void *data) -{ - VirtioBusClass *k = VIRTIO_BUS_CLASS(klass); - BusClass *bus_class = BUS_CLASS(klass); - - bus_class->max_dev = 1; - k->notify = virtio_ccw_notify; - k->vmstate_change = virtio_ccw_vmstate_change; - k->query_guest_notifiers = virtio_ccw_query_guest_notifiers; - k->set_host_notifier = virtio_ccw_set_host_notifier; - k->set_guest_notifiers = virtio_ccw_set_guest_notifiers; - k->save_queue = virtio_ccw_save_queue; - k->load_queue = virtio_ccw_load_queue; - k->save_config = virtio_ccw_save_config; - k->load_config = virtio_ccw_load_config; - k->device_plugged = virtio_ccw_device_plugged; - k->post_plugged = virtio_ccw_post_plugged; - k->device_unplugged = virtio_ccw_device_unplugged; -} - -static const TypeInfo virtio_ccw_bus_info = { - .name = TYPE_VIRTIO_CCW_BUS, - .parent = TYPE_VIRTIO_BUS, - .instance_size = sizeof(VirtioCcwBusState), - .class_init = virtio_ccw_bus_class_init, -}; - -#ifdef CONFIG_VIRTFS -static Property virtio_ccw_9p_properties[] = { - DEFINE_PROP_STRING("devno", VirtioCcwDevice, bus_id), - 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_9p_realize(VirtioCcwDevice *ccw_dev, Error **errp) -{ - V9fsCCWState *dev = VIRTIO_9P_CCW(ccw_dev); - DeviceState *vdev = DEVICE(&dev->vdev); - Error *err = NULL; - - qdev_set_parent_bus(vdev, BUS(&ccw_dev->bus)); - object_property_set_bool(OBJECT(vdev), true, "realized", &err); - if (err) { - error_propagate(errp, err); - } -} - -static void virtio_ccw_9p_class_init(ObjectClass *klass, void *data) -{ - DeviceClass *dc = DEVICE_CLASS(klass); - VirtIOCCWDeviceClass *k = VIRTIO_CCW_DEVICE_CLASS(klass); - - k->exit = virtio_ccw_exit; - k->realize = virtio_ccw_9p_realize; - dc->reset = virtio_ccw_reset; - dc->props = virtio_ccw_9p_properties; - set_bit(DEVICE_CATEGORY_STORAGE, dc->categories); -} - -static void virtio_ccw_9p_instance_init(Object *obj) -{ - V9fsCCWState *dev = VIRTIO_9P_CCW(obj); - - virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev), - TYPE_VIRTIO_9P); -} - -static const TypeInfo virtio_ccw_9p_info = { - .name = TYPE_VIRTIO_9P_CCW, - .parent = TYPE_VIRTIO_CCW_DEVICE, - .instance_size = sizeof(V9fsCCWState), - .instance_init = virtio_ccw_9p_instance_init, - .class_init = virtio_ccw_9p_class_init, -}; -#endif - -static void virtio_ccw_register(void) -{ - type_register_static(&virtio_ccw_bus_info); - type_register_static(&virtual_css_bus_info); - type_register_static(&virtio_ccw_device_info); - type_register_static(&virtio_ccw_serial); - type_register_static(&virtio_ccw_blk); - type_register_static(&virtio_ccw_net); - type_register_static(&virtio_ccw_balloon); - type_register_static(&virtio_ccw_scsi); -#ifdef CONFIG_VHOST_SCSI - type_register_static(&vhost_ccw_scsi); -#endif - type_register_static(&virtio_ccw_rng); - type_register_static(&virtual_css_bridge_info); -#ifdef CONFIG_VIRTFS - type_register_static(&virtio_ccw_9p_info); -#endif -} - -type_init(virtio_ccw_register) diff --git a/qemu/hw/s390x/virtio-ccw.h b/qemu/hw/s390x/virtio-ccw.h deleted file mode 100644 index 66c831ba8..000000000 --- a/qemu/hw/s390x/virtio-ccw.h +++ /dev/null @@ -1,211 +0,0 @@ -/* - * virtio ccw target definitions - * - * Copyright 2012,2015 IBM Corp. - * Author(s): Cornelia Huck <cornelia.huck@de.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. - */ - -#ifndef HW_S390X_VIRTIO_CCW_H -#define HW_S390X_VIRTIO_CCW_H - -#include <hw/virtio/virtio-blk.h> -#include <hw/virtio/virtio-net.h> -#include <hw/virtio/virtio-serial.h> -#include <hw/virtio/virtio-scsi.h> -#ifdef CONFIG_VHOST_SCSI -#include <hw/virtio/vhost-scsi.h> -#endif -#include <hw/virtio/virtio-balloon.h> -#include <hw/virtio/virtio-rng.h> -#include <hw/virtio/virtio-bus.h> - -#include "css.h" - -#define VIRTUAL_CSSID 0xfe - -#define VIRTIO_CCW_CU_TYPE 0x3832 -#define VIRTIO_CCW_CHPID_TYPE 0x32 - -#define CCW_CMD_SET_VQ 0x13 -#define CCW_CMD_VDEV_RESET 0x33 -#define CCW_CMD_READ_FEAT 0x12 -#define CCW_CMD_WRITE_FEAT 0x11 -#define CCW_CMD_READ_CONF 0x22 -#define CCW_CMD_WRITE_CONF 0x21 -#define CCW_CMD_WRITE_STATUS 0x31 -#define CCW_CMD_SET_IND 0x43 -#define CCW_CMD_SET_CONF_IND 0x53 -#define CCW_CMD_READ_VQ_CONF 0x32 -#define CCW_CMD_SET_IND_ADAPTER 0x73 -#define CCW_CMD_SET_VIRTIO_REV 0x83 - -#define TYPE_VIRTIO_CCW_DEVICE "virtio-ccw-device" -#define VIRTIO_CCW_DEVICE(obj) \ - OBJECT_CHECK(VirtioCcwDevice, (obj), TYPE_VIRTIO_CCW_DEVICE) -#define VIRTIO_CCW_DEVICE_CLASS(klass) \ - OBJECT_CLASS_CHECK(VirtIOCCWDeviceClass, (klass), TYPE_VIRTIO_CCW_DEVICE) -#define VIRTIO_CCW_DEVICE_GET_CLASS(obj) \ - OBJECT_GET_CLASS(VirtIOCCWDeviceClass, (obj), TYPE_VIRTIO_CCW_DEVICE) - -typedef struct VirtioBusState VirtioCcwBusState; -typedef struct VirtioBusClass VirtioCcwBusClass; - -#define TYPE_VIRTIO_CCW_BUS "virtio-ccw-bus" -#define VIRTIO_CCW_BUS(obj) \ - OBJECT_CHECK(VirtioCcwBus, (obj), TYPE_VIRTIO_CCW_BUS) -#define VIRTIO_CCW_BUS_GET_CLASS(obj) \ - OBJECT_CHECK(VirtioCcwBusState, (obj), TYPE_VIRTIO_CCW_BUS) -#define VIRTIO_CCW_BUS_CLASS(klass) \ - OBJECT_CLASS_CHECK(VirtioCcwBusClass, klass, TYPE_VIRTIO_CCW_BUS) - -typedef struct VirtioCcwDevice VirtioCcwDevice; - -typedef struct VirtIOCCWDeviceClass { - DeviceClass parent_class; - void (*realize)(VirtioCcwDevice *dev, Error **errp); - int (*exit)(VirtioCcwDevice *dev); -} VirtIOCCWDeviceClass; - -/* 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; - char *bus_id; - int revision; - uint32_t max_rev; - VirtioBusState bus; - bool ioeventfd_started; - bool ioeventfd_disabled; - uint32_t flags; - uint8_t thinint_isc; - AdapterRoutes routes; - /* Guest provided values: */ - IndAddr *indicators; - IndAddr *indicators2; - IndAddr *summary_indicator; - uint64_t ind_bit; -}; - -/* The maximum virtio revision we support. */ -#define VIRTIO_CCW_MAX_REV 1 -static inline int virtio_ccw_rev_max(VirtioCcwDevice *dev) -{ - return dev->max_rev; -} - -/* virtual css bus type */ -typedef struct VirtualCssBus { - BusState parent_obj; -} VirtualCssBus; - -#define TYPE_VIRTUAL_CSS_BUS "virtual-css-bus" -#define VIRTUAL_CSS_BUS(obj) \ - OBJECT_CHECK(VirtualCssBus, (obj), TYPE_VIRTUAL_CSS_BUS) - -/* virtio-scsi-ccw */ - -#define TYPE_VIRTIO_SCSI_CCW "virtio-scsi-ccw" -#define VIRTIO_SCSI_CCW(obj) \ - OBJECT_CHECK(VirtIOSCSICcw, (obj), TYPE_VIRTIO_SCSI_CCW) - -typedef struct VirtIOSCSICcw { - VirtioCcwDevice parent_obj; - VirtIOSCSI vdev; -} VirtIOSCSICcw; - -#ifdef CONFIG_VHOST_SCSI -/* vhost-scsi-ccw */ - -#define TYPE_VHOST_SCSI_CCW "vhost-scsi-ccw" -#define VHOST_SCSI_CCW(obj) \ - OBJECT_CHECK(VHostSCSICcw, (obj), TYPE_VHOST_SCSI_CCW) - -typedef struct VHostSCSICcw { - VirtioCcwDevice parent_obj; - VHostSCSI vdev; -} VHostSCSICcw; -#endif - -/* virtio-blk-ccw */ - -#define TYPE_VIRTIO_BLK_CCW "virtio-blk-ccw" -#define VIRTIO_BLK_CCW(obj) \ - OBJECT_CHECK(VirtIOBlkCcw, (obj), TYPE_VIRTIO_BLK_CCW) - -typedef struct VirtIOBlkCcw { - VirtioCcwDevice parent_obj; - VirtIOBlock vdev; -} VirtIOBlkCcw; - -/* virtio-balloon-ccw */ - -#define TYPE_VIRTIO_BALLOON_CCW "virtio-balloon-ccw" -#define VIRTIO_BALLOON_CCW(obj) \ - OBJECT_CHECK(VirtIOBalloonCcw, (obj), TYPE_VIRTIO_BALLOON_CCW) - -typedef struct VirtIOBalloonCcw { - VirtioCcwDevice parent_obj; - VirtIOBalloon vdev; -} VirtIOBalloonCcw; - -/* virtio-serial-ccw */ - -#define TYPE_VIRTIO_SERIAL_CCW "virtio-serial-ccw" -#define VIRTIO_SERIAL_CCW(obj) \ - OBJECT_CHECK(VirtioSerialCcw, (obj), TYPE_VIRTIO_SERIAL_CCW) - -typedef struct VirtioSerialCcw { - VirtioCcwDevice parent_obj; - VirtIOSerial vdev; -} VirtioSerialCcw; - -/* virtio-net-ccw */ - -#define TYPE_VIRTIO_NET_CCW "virtio-net-ccw" -#define VIRTIO_NET_CCW(obj) \ - OBJECT_CHECK(VirtIONetCcw, (obj), TYPE_VIRTIO_NET_CCW) - -typedef struct VirtIONetCcw { - VirtioCcwDevice parent_obj; - VirtIONet vdev; -} VirtIONetCcw; - -/* virtio-rng-ccw */ - -#define TYPE_VIRTIO_RNG_CCW "virtio-rng-ccw" -#define VIRTIO_RNG_CCW(obj) \ - OBJECT_CHECK(VirtIORNGCcw, (obj), TYPE_VIRTIO_RNG_CCW) - -typedef struct VirtIORNGCcw { - VirtioCcwDevice parent_obj; - VirtIORNG vdev; -} VirtIORNGCcw; - -VirtualCssBus *virtual_css_bus_init(void); -void virtio_ccw_device_update_status(SubchDev *sch); -VirtIODevice *virtio_ccw_get_vdev(SubchDev *sch); - -#ifdef CONFIG_VIRTFS -#include "hw/9pfs/virtio-9p.h" - -#define TYPE_VIRTIO_9P_CCW "virtio-9p-ccw" -#define VIRTIO_9P_CCW(obj) \ - OBJECT_CHECK(V9fsCCWState, (obj), TYPE_VIRTIO_9P_CCW) - -typedef struct V9fsCCWState { - VirtioCcwDevice parent_obj; - V9fsVirtioState vdev; -} V9fsCCWState; - -#endif /* CONFIG_VIRTFS */ - -#endif |