Commit 5317b0f6 authored by Peter Maydell's avatar Peter Maydell
Browse files

Merge remote-tracking branch 'remotes/cohuck/tags/s390x-20150702-v3' into staging



Several s390x patches including:
- missing virtio-1 related code for virtio-ccw
- bugfixes in ipl device, gdb, virtio-ccw
- bugfix in s390-ccw bios + rebuild
- introduce versioned machines for s390-ccw-virtio

# gpg: Signature made Thu Jul  2 15:05:34 2015 BST using RSA key ID C6F02FAF
# gpg: Good signature from "Cornelia Huck <huckc@linux.vnet.ibm.com>"
# gpg:                 aka "Cornelia Huck <cornelia.huck@de.ibm.com>"

* remotes/cohuck/tags/s390x-20150702-v3:
  s390x/migration: Introduce 2.4 machine
  s390x/gdb: synchronize cpu state after modifying acrs
  s390x/ipl: Fix boot if no bootindex was specified
  virtio-ccw: migrate ->revision
  s390x/virtio-ccw: support virtio-1 set_vq format
  s390x/virtio-ccw: add virtio set-revision call
  s390x/css: Add a callback for when subchannel gets disabled
  s390-ccw.img: update
  s390-ccw.img: Consume service interrupts
  css: mss/mcss-e vs. migration
  virtio-ccw: complete handling of guest-initiated resets

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 6686ce3f c4d3c0a2
Loading
Loading
Loading
Loading
+27 −0
Original line number Diff line number Diff line
@@ -588,6 +588,7 @@ 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;

@@ -610,6 +611,7 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
    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);
@@ -625,6 +627,12 @@ int css_do_msch(SubchDev *sch, const SCHIB *orig_schib)
            (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:
@@ -1464,6 +1472,21 @@ int subch_device_load(SubchDev *s, QEMUFile *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;
}

@@ -1483,6 +1506,10 @@ 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 |
+1 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ struct SubchDev {
    uint8_t ccw_no_data_cnt;
    /* transport-provided data: */
    int (*ccw_cb) (SubchDev *, CCW1);
    void (*disable_cb)(SubchDev *);
    SenseId id;
    void *driver_data;
};
+2 −2
Original line number Diff line number Diff line
@@ -218,7 +218,7 @@ static Property s390_ipl_properties[] = {
 * - -1 if no valid boot device was found
 * - ccw id of the boot device otherwise
 */
static uint32_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
static uint64_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)
{
    DeviceState *dev_st;

@@ -248,7 +248,7 @@ static uint32_t s390_update_iplstate(CPUS390XState *env, S390IPLState *ipl)

    return -1;
out:
    return ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno;
    return (uint32_t) (ipl->cssid << 24 | ipl->ssid << 16 | ipl->devno);
}

int s390_ipl_update_diag308(IplParameterBlock *iplb)
+18 −4
Original line number Diff line number Diff line
@@ -204,9 +204,6 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
    MachineClass *mc = MACHINE_CLASS(oc);
    NMIClass *nc = NMI_CLASS(oc);

    mc->name = "s390-ccw-virtio";
    mc->alias = "s390-ccw";
    mc->desc = "VirtIO-ccw based S390 machine";
    mc->init = ccw_init;
    mc->block_default_type = IF_VIRTIO;
    mc->no_cdrom = 1;
@@ -216,7 +213,6 @@ static void ccw_machine_class_init(ObjectClass *oc, void *data)
    mc->no_sdcard = 1;
    mc->use_sclp = 1;
    mc->max_cpus = 255;
    mc->is_default = 1;
    nc->nmi_monitor_handler = s390_nmi;
}

@@ -272,6 +268,7 @@ static inline void s390_machine_initfn(Object *obj)
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,
@@ -281,9 +278,26 @@ static const TypeInfo ccw_machine_info = {
    },
};

static void ccw_machine_2_4_class_init(ObjectClass *oc, void *data)
{
    MachineClass *mc = MACHINE_CLASS(oc);

    mc->name = "s390-ccw-virtio-2.4";
    mc->alias = "s390-ccw-virtio";
    mc->desc = "VirtIO-ccw based S390 machine v2.4";
    mc->is_default = 1;
}

static const TypeInfo ccw_machine_2_4_info = {
    .name          = TYPE_S390_CCW_MACHINE "2.4",
    .parent        = TYPE_S390_CCW_MACHINE,
    .class_init    = ccw_machine_2_4_class_init,
};

static void ccw_machine_register_types(void)
{
    type_register_static(&ccw_machine_info);
    type_register_static(&ccw_machine_2_4_info);
}

type_init(ccw_machine_register_types)
+192 −60
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#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"
@@ -237,11 +238,20 @@ VirtualCssBus *virtual_css_bus_init(void)
}

/* Communication blocks used by several channel commands. */
typedef struct VqInfoBlock {
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 {
@@ -261,18 +271,27 @@ typedef struct VirtioThinintInfo {
    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, uint64_t addr, uint32_t align,
                              uint16_t index, uint16_t num)
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 (addr && (align != 4096)) {
    if (linfo && desc && (linfo->align != 4096)) {
        return -EINVAL;
    }

@@ -280,8 +299,12 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
        return -EINVAL;
    }

    virtio_queue_set_addr(vdev, index, addr);
    if (!addr) {
    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 {
        /* Fail if we don't have a big enough queue. */
@@ -296,10 +319,98 @@ static int virtio_ccw_set_vqs(SubchDev *sch, uint64_t addr, uint32_t align,
    return 0;
}

static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
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;
@@ -323,44 +434,10 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
    /* Look at the command. */
    switch (ccw.cmd_code) {
    case CCW_CMD_SET_VQ:
        if (check_len) {
            if (ccw.count != sizeof(info)) {
                ret = -EINVAL;
                break;
            }
        } else if (ccw.count < sizeof(info)) {
            /* Can't execute command. */
            ret = -EINVAL;
            break;
        }
        if (!ccw.cda) {
            ret = -EFAULT;
        } else {
            info.queue = address_space_ldq(&address_space_memory, ccw.cda,
                                           MEMTXATTRS_UNSPECIFIED, NULL);
            info.align = address_space_ldl(&address_space_memory,
                                           ccw.cda + sizeof(info.queue),
                                           MEMTXATTRS_UNSPECIFIED,
                                           NULL);
            info.index = address_space_lduw(&address_space_memory,
                                            ccw.cda + sizeof(info.queue)
                                            + sizeof(info.align),
                                            MEMTXATTRS_UNSPECIFIED,
                                            NULL);
            info.num = address_space_lduw(&address_space_memory,
                                          ccw.cda + sizeof(info.queue)
                                          + sizeof(info.align)
                                          + sizeof(info.index),
                                          MEMTXATTRS_UNSPECIFIED,
                                          NULL);
            ret = virtio_ccw_set_vqs(sch, info.queue, info.align, info.index,
                                     info.num);
            sch->curr_status.scsw.count = 0;
        }
        ret = virtio_ccw_handle_set_vq(sch, ccw, check_len, dev->revision < 1);
        break;
    case CCW_CMD_VDEV_RESET:
        virtio_ccw_stop_ioeventfd(dev);
        virtio_reset(vdev);
        virtio_ccw_reset_virtio(dev, vdev);
        ret = 0;
        break;
    case CCW_CMD_READ_FEAT:
@@ -383,7 +460,16 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
                                                MEMTXATTRS_UNSPECIFIED,
                                                NULL);
            if (features.index == 0) {
                features.features = vdev->host_features;
                features.features = (uint32_t)vdev->host_features;
            } else if (features.index == 1) {
                features.features = (uint32_t)(vdev->host_features >> 32);
                /*
                 * Don't offer version 1 to the guest if it did not
                 * negotiate at least revision 1.
                 */
                if (dev->revision <= 0) {
                    features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
                }
            } else {
                /* Return zeroes if the guest supports more feature bits. */
                features.features = 0;
@@ -419,7 +505,20 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
                                                     MEMTXATTRS_UNSPECIFIED,
                                                     NULL);
            if (features.index == 0) {
                virtio_set_features(vdev, features.features);
                virtio_set_features(vdev,
                                    (vdev->guest_features & 0xffffffff00000000ULL) |
                                    features.features);
            } else if (features.index == 1) {
                /*
                 * The guest should not set version 1 if it didn't
                 * negotiate a revision >= 1.
                 */
                if (dev->revision <= 0) {
                    features.features &= ~(1 << (VIRTIO_F_VERSION_1 - 32));
                }
                virtio_set_features(vdev,
                                    (vdev->guest_features & 0x00000000ffffffffULL) |
                                    ((uint64_t)features.features << 32));
            } else {
                /*
                 * If the guest supports more feature bits, assert that it
@@ -500,7 +599,7 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
            }
            if (virtio_set_status(vdev, status) == 0) {
                if (vdev->status == 0) {
                    virtio_reset(vdev);
                    virtio_ccw_reset_virtio(dev, vdev);
                }
                if (status & VIRTIO_CONFIG_S_DRIVER_OK) {
                    virtio_ccw_start_ioeventfd(dev);
@@ -640,6 +739,40 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
            }
        }
        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(vdev)) {
            ret = -ENOSYS;
            break;
        }
        ret = 0;
        dev->revision = revinfo.revision;
        break;
    default:
        ret = -ENOSYS;
        break;
@@ -647,6 +780,13 @@ static int virtio_ccw_cb(SubchDev *sch, CCW1 ccw)
    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;
@@ -766,12 +906,15 @@ static void virtio_ccw_device_realize(VirtioCcwDevice *dev, Error **errp)
    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);
    }
@@ -1081,21 +1224,8 @@ static void virtio_ccw_reset(DeviceState *d)
    VirtioCcwDevice *dev = VIRTIO_CCW_DEVICE(d);
    VirtIODevice *vdev = virtio_bus_get_device(&dev->bus);

    virtio_ccw_stop_ioeventfd(dev);
    virtio_reset(vdev);
    virtio_ccw_reset_virtio(dev, vdev);
    css_reset_sch(dev->sch);
    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;
    }
}

static void virtio_ccw_vmstate_change(DeviceState *d, bool running)
@@ -1342,6 +1472,7 @@ static void virtio_ccw_save_config(DeviceState *d, QEMUFile *f)
    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)
@@ -1382,6 +1513,7 @@ static int virtio_ccw_load_config(DeviceState *d, QEMUFile *f)
                                       dev->thinint_isc, true, false,
                                       &dev->routes.adapter.adapter_id);
    }
    dev->revision = qemu_get_be32(f);

    return 0;
}
Loading