Commit a257c741 authored by Peter Maydell's avatar Peter Maydell
Browse files

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



First batch of s390x patches for 2.7:
- The new machine for 2.7
- Make use of the runtime instrumentation support introduced in
  the kernel
- Enhance our ipl (boot) process: We can now start from devices
  in subchannel sets > 0 as well. As a bonus, the conversion to
  diag308 in the bios allows us to get rid of the gr7 hack.
- Xiaoqiang Zhao's SCLP qomification patches
- Several fixes in the s390x pci implementation

# gpg: Signature made Tue 17 May 2016 15:35:32 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-20160517:
  s390x/pci: remove whitespace
  s390x/pci: add length checking for pci sclp handlers
  s390x/pci: enhance mpcifc_service_call
  s390x/pci: fix s390_pci_sclp_deconfigure
  s390x/pci: introduce S390PCIBusDevice.iommu_enabled
  s390x/pci: export pci_dereg_ioat and pci_dereg_irqs
  s390x/pci: separate s390_pcihost_iommu_configure function
  s390x/pci: separate s390_sclp_configure function
  s390x/pci: fix reg_irqs()
  hw/char: QOM'ify sclpconsole.c
  hw/char: QOM'ify sclpconsole-lm.c
  s390x/ipl: Remove redundant usage of gr7
  s390-ccw.img: rebuild image
  pc-bios/s390-ccw: Get device address via diag 308/6
  s390x/ipl: Add ssid field to IplParameterBlock
  s390x/ipl: Provide ipl parameter block
  s390x/ipl: Add type and length checks for IplParameterBlock values
  s390x/ipl: Extend the IplParameterBlock struct
  s390x: enable runtime instrumentation
  s390x: add compat machine for 2.7

Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 5a3fd960 c2691694
Loading
Loading
Loading
Loading
+9 −5
Original line number Diff line number Diff line
@@ -44,6 +44,10 @@ typedef struct SCLPConsoleLM {
    uint8_t buf[SIZE_CONSOLE_BUFFER];
} SCLPConsoleLM;

#define TYPE_SCLPLM_CONSOLE "sclplmconsole"
#define SCLPLM_CONSOLE(obj) \
    OBJECT_CHECK(SCLPConsoleLM, (obj), TYPE_SCLPLM_CONSOLE)

/*
*  Character layer call-back functions
 *
@@ -116,7 +120,7 @@ static int get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
{
    int len;

    SCLPConsoleLM *cons = DO_UPCAST(SCLPConsoleLM, event, event);
    SCLPConsoleLM *cons = SCLPLM_CONSOLE(event);

    len = cons->length;
    /* data need to fit into provided SCLP buffer */
@@ -190,7 +194,7 @@ static int write_console_data(SCLPEvent *event, const uint8_t *buf, int len)
    int ret = 0;
    const uint8_t *buf_offset;

    SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
    SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);

    if (!scon->chr) {
        /* If there's no backend, we can just say we consumed all data. */
@@ -244,7 +248,7 @@ static int write_event_data(SCLPEvent *event, EventBufferHeader *ebh)
    int errors = 0;
    MDBO *mdbo;
    SclpMsg *data = (SclpMsg *) ebh;
    SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
    SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);

    len = be16_to_cpu(data->mdb.header.length);
    if (len < sizeof(data->mdb.header)) {
@@ -313,7 +317,7 @@ static int console_init(SCLPEvent *event)
{
    static bool console_available;

    SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
    SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);

    if (console_available) {
        error_report("Multiple line-mode operator consoles are not supported");
@@ -336,7 +340,7 @@ static int console_exit(SCLPEvent *event)
static void console_reset(DeviceState *dev)
{
   SCLPEvent *event = SCLP_EVENT(dev);
   SCLPConsoleLM *scon = DO_UPCAST(SCLPConsoleLM, event, event);
   SCLPConsoleLM *scon = SCLPLM_CONSOLE(event);

   event->event_pending = false;
   scon->length = 0;
+8 −4
Original line number Diff line number Diff line
@@ -40,6 +40,10 @@ typedef struct SCLPConsole {
    bool notify;            /* qemu_notify_event() req'd if true           */
} SCLPConsole;

#define TYPE_SCLP_CONSOLE "sclpconsole"
#define SCLP_CONSOLE(obj) \
    OBJECT_CHECK(SCLPConsole, (obj), TYPE_SCLP_CONSOLE)

/* character layer call-back functions */

/* Return number of bytes that fit into iov buffer */
@@ -95,7 +99,7 @@ static unsigned int receive_mask(void)
static void get_console_data(SCLPEvent *event, uint8_t *buf, size_t *size,
                             int avail)
{
    SCLPConsole *cons = DO_UPCAST(SCLPConsole, event, event);
    SCLPConsole *cons = SCLP_CONSOLE(event);

    /* first byte is hex 0 saying an ascii string follows */
    *buf++ = '\0';
@@ -157,7 +161,7 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
static ssize_t write_console_data(SCLPEvent *event, const uint8_t *buf,
                                  size_t len)
{
    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
    SCLPConsole *scon = SCLP_CONSOLE(event);

    if (!scon->chr) {
        /* If there's no backend, we can just say we consumed all data. */
@@ -214,7 +218,7 @@ static int console_init(SCLPEvent *event)
{
    static bool console_available;

    SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
    SCLPConsole *scon = SCLP_CONSOLE(event);

    if (console_available) {
        error_report("Multiple VT220 operator consoles are not supported");
@@ -232,7 +236,7 @@ static int console_init(SCLPEvent *event)
static void console_reset(DeviceState *dev)
{
   SCLPEvent *event = SCLP_EVENT(dev);
   SCLPConsole *scon = DO_UPCAST(SCLPConsole, event, event);
   SCLPConsole *scon = SCLP_CONSOLE(event);

   event->event_pending = false;
   scon->iov_sclp = 0;
+37 −26
Original line number Diff line number Diff line
@@ -30,6 +30,24 @@
#define ZIPL_IMAGE_START                0x009000UL
#define IPL_PSW_MASK                    (PSW_MASK_32 | PSW_MASK_64)

static bool iplb_extended_needed(void *opaque)
{
    S390IPLState *ipl = S390_IPL(object_resolve_path(TYPE_S390_IPL, NULL));

    return ipl->iplbext_migration;
}

static const VMStateDescription vmstate_iplb_extended = {
    .name = "ipl/iplb_extended",
    .version_id = 0,
    .minimum_version_id = 0,
    .needed = iplb_extended_needed,
    .fields = (VMStateField[]) {
        VMSTATE_UINT8_ARRAY(reserved_ext, IplParameterBlock, 4096 - 200),
        VMSTATE_END_OF_LIST()
    }
};

static const VMStateDescription vmstate_iplb = {
    .name = "ipl/iplb",
    .version_id = 0,
@@ -39,6 +57,10 @@ static const VMStateDescription vmstate_iplb = {
        VMSTATE_UINT16(devno, IplParameterBlock),
        VMSTATE_UINT8_ARRAY(reserved2, IplParameterBlock, 88),
        VMSTATE_END_OF_LIST()
    },
    .subsections = (const VMStateDescription*[]) {
        &vmstate_iplb_extended,
        NULL
    }
};

@@ -181,46 +203,32 @@ static Property s390_ipl_properties[] = {
    DEFINE_PROP_STRING("cmdline", S390IPLState, cmdline),
    DEFINE_PROP_STRING("firmware", S390IPLState, firmware),
    DEFINE_PROP_BOOL("enforce_bios", S390IPLState, enforce_bios, false),
    DEFINE_PROP_BOOL("iplbext_migration", S390IPLState, iplbext_migration,
                     true),
    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)
static bool s390_gen_initial_iplb(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;
            ipl->iplb.len = cpu_to_be32(S390_IPLB_MIN_CCW_LEN);
            ipl->iplb.blk0_len =
                cpu_to_be32(S390_IPLB_MIN_CCW_LEN - S390_IPLB_HEADER_LEN);
            ipl->iplb.pbt = S390_IPL_TYPE_CCW;
            ipl->iplb.ccw.devno = cpu_to_be16(ccw_dev->sch->devno);
            ipl->iplb.ccw.ssid = ccw_dev->sch->ssid & 3;
            return true;
        }
    }

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

void s390_ipl_update_diag308(IplParameterBlock *iplb)
@@ -258,7 +266,9 @@ void s390_ipl_prepare_cpu(S390CPU *cpu)

    if (!ipl->kernel || ipl->iplb_valid) {
        cpu->env.psw.addr = ipl->bios_start_addr;
        cpu->env.regs[7] = s390_update_iplstate(ipl);
        if (!ipl->iplb_valid) {
            ipl->iplb_valid = s390_gen_initial_iplb(ipl);
        }
    }
}

@@ -268,6 +278,7 @@ static void s390_ipl_reset(DeviceState *dev)

    if (!ipl->reipl_requested) {
        ipl->iplb_valid = false;
        memset(&ipl->iplb, 0, sizeof(IplParameterBlock));
    }
    ipl->reipl_requested = false;
}
+79 −5
Original line number Diff line number Diff line
@@ -15,11 +15,60 @@
#include "hw/qdev.h"
#include "cpu.h"

typedef struct IplParameterBlock {
struct IplBlockCcw {
    uint8_t  reserved0[85];
    uint8_t  ssid;
    uint16_t devno;
    uint8_t  vm_flags;
    uint8_t  reserved3[3];
    uint32_t vm_parm_len;
    uint8_t  nss_name[8];
    uint8_t  vm_parm[64];
    uint8_t  reserved4[8];
} QEMU_PACKED;
typedef struct IplBlockCcw IplBlockCcw;

struct IplBlockFcp {
    uint8_t  reserved1[305 - 1];
    uint8_t  opt;
    uint8_t  reserved2[3];
    uint16_t reserved3;
    uint16_t devno;
    uint8_t  reserved4[4];
    uint64_t wwpn;
    uint64_t lun;
    uint32_t bootprog;
    uint8_t  reserved5[12];
    uint64_t br_lba;
    uint32_t scp_data_len;
    uint8_t  reserved6[260];
    uint8_t  scp_data[];
} QEMU_PACKED;
typedef struct IplBlockFcp IplBlockFcp;

union IplParameterBlock {
    struct {
        uint32_t len;
        uint8_t  reserved0[3];
        uint8_t  version;
        uint32_t blk0_len;
        uint8_t  pbt;
        uint8_t  flags;
        uint16_t reserved01;
        uint8_t  loadparm[8];
        union {
            IplBlockCcw ccw;
            IplBlockFcp fcp;
        };
    } QEMU_PACKED;
    struct {
        uint8_t  reserved1[110];
        uint16_t devno;
        uint8_t  reserved2[88];
} IplParameterBlock;
        uint8_t  reserved_ext[4096 - 200];
    } QEMU_PACKED;
} QEMU_PACKED;
typedef union IplParameterBlock IplParameterBlock;

void s390_ipl_update_diag308(IplParameterBlock *iplb);
void s390_ipl_prepare_cpu(S390CPU *cpu);
@@ -47,7 +96,32 @@ struct S390IPLState {
    uint8_t cssid;
    uint8_t ssid;
    uint16_t devno;
    bool iplbext_migration;
};
typedef struct S390IPLState S390IPLState;

#define S390_IPL_TYPE_FCP 0x00
#define S390_IPL_TYPE_CCW 0x02

#define S390_IPLB_HEADER_LEN 8
#define S390_IPLB_MIN_CCW_LEN 200
#define S390_IPLB_MIN_FCP_LEN 384

static inline bool iplb_valid_len(IplParameterBlock *iplb)
{
    return be32_to_cpu(iplb->len) <= sizeof(IplParameterBlock);
}

static inline bool iplb_valid_ccw(IplParameterBlock *iplb)
{
    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_CCW_LEN &&
           iplb->pbt == S390_IPL_TYPE_CCW;
}

static inline bool iplb_valid_fcp(IplParameterBlock *iplb)
{
    return be32_to_cpu(iplb->len) >= S390_IPLB_MIN_FCP_LEN &&
           iplb->pbt == S390_IPL_TYPE_FCP;
}

#endif
+56 −17
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include "qemu-common.h"
#include "cpu.h"
#include "s390-pci-bus.h"
#include "s390-pci-inst.h"
#include <hw/pci/pci_bus.h>
#include <hw/pci/msi.h>
#include <qemu/error-report.h>
@@ -106,25 +107,61 @@ S390PCIBusDevice *s390_pci_find_dev_by_fid(uint32_t fid)
    return NULL;
}

void s390_pci_sclp_configure(int configure, SCCB *sccb)
void s390_pci_sclp_configure(SCCB *sccb)
{
    PciCfgSccb *psccb = (PciCfgSccb *)sccb;
    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
    uint16_t rc;

    if (be16_to_cpu(sccb->h.length) < 16) {
        rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH;
        goto out;
    }

    if (pbdev) {
        if ((configure == 1 && pbdev->configured == true) ||
            (configure == 0 && pbdev->configured == false)) {
        if (pbdev->configured) {
            rc = SCLP_RC_NO_ACTION_REQUIRED;
        } else {
            pbdev->configured = !pbdev->configured;
            pbdev->configured = true;
            rc = SCLP_RC_NORMAL_COMPLETION;
        }
    } else {
        DPRINTF("sclp config %d no dev found\n", configure);
        DPRINTF("sclp config no dev found\n");
        rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
    }
out:
    psccb->header.response_code = cpu_to_be16(rc);
}

void s390_pci_sclp_deconfigure(SCCB *sccb)
{
    PciCfgSccb *psccb = (PciCfgSccb *)sccb;
    S390PCIBusDevice *pbdev = s390_pci_find_dev_by_fid(be32_to_cpu(psccb->aid));
    uint16_t rc;

    if (be16_to_cpu(sccb->h.length) < 16) {
        rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH;
        goto out;
    }

    if (pbdev) {
        if (!pbdev->configured) {
            rc = SCLP_RC_NO_ACTION_REQUIRED;
        } else {
            if (pbdev->summary_ind) {
                pci_dereg_irqs(pbdev);
            }
            if (pbdev->iommu_enabled) {
                pci_dereg_ioat(pbdev);
            }
            pbdev->configured = false;
            rc = SCLP_RC_NORMAL_COMPLETION;
        }
    } else {
        DPRINTF("sclp deconfig no dev found\n");
        rc = SCLP_RC_ADAPTER_ID_NOT_RECOGNIZED;
    }
out:
    psccb->header.response_code = cpu_to_be16(rc);
}

@@ -320,7 +357,8 @@ static IOMMUTLBEntry s390_translate_iommu(MemoryRegion *iommu, hwaddr addr,
        .perm = IOMMU_NONE,
    };

    if (!pbdev->configured || !pbdev->pdev || !(pbdev->fh & FH_ENABLED)) {
    if (!pbdev->configured || !pbdev->pdev ||
        !(pbdev->fh & FH_ENABLED) || !pbdev->iommu_enabled) {
        return ret;
    }

@@ -458,20 +496,21 @@ static const MemoryRegionOps s390_msi_ctrl_ops = {
    .endianness = DEVICE_LITTLE_ENDIAN,
};

void s390_pcihost_iommu_configure(S390PCIBusDevice *pbdev, bool enable)
void s390_pci_iommu_enable(S390PCIBusDevice *pbdev)
{
    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->iommu_enabled = true;
}

    pbdev->configured = true;
void s390_pci_iommu_disable(S390PCIBusDevice *pbdev)
{
    memory_region_del_subregion(&pbdev->mr, &pbdev->iommu_mr);
    object_unparent(OBJECT(&pbdev->iommu_mr));
    pbdev->iommu_enabled = false;
}

static void s390_pcihost_init_as(S390pciState *s)
Loading