summaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2016-05-17 16:49:11 +0100
committerPeter Maydell <peter.maydell@linaro.org>2016-05-17 16:49:11 +0100
commita257c741491ff1c3c192d13a89c136dd6401c54d (patch)
tree5e1b706fb4f5b082c4cf928caad2a21fe7213a97 /hw
parent5a3fd960f39c17cef5ffa8703652bea3828bbe48 (diff)
parentc26916942a4a085b316fd102d1725412a6544b04 (diff)
downloadqemu-a257c741491ff1c3c192d13a89c136dd6401c54d.zip
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: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/char/sclpconsole-lm.c14
-rw-r--r--hw/char/sclpconsole.c12
-rw-r--r--hw/s390x/ipl.c63
-rw-r--r--hw/s390x/ipl.h84
-rw-r--r--hw/s390x/s390-pci-bus.c73
-rw-r--r--hw/s390x/s390-pci-bus.h17
-rw-r--r--hw/s390x/s390-pci-inst.c79
-rw-r--r--hw/s390x/s390-pci-inst.h11
-rw-r--r--hw/s390x/s390-virtio-ccw.c47
-rw-r--r--hw/s390x/sclp.c4
10 files changed, 323 insertions, 81 deletions
diff --git a/hw/char/sclpconsole-lm.c b/hw/char/sclpconsole-lm.c
index 7d4ff8120a..a22ad8d016 100644
--- a/hw/char/sclpconsole-lm.c
+++ b/hw/char/sclpconsole-lm.c
@@ -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;
diff --git a/hw/char/sclpconsole.c b/hw/char/sclpconsole.c
index 45997ff4ae..15a5b2b2b5 100644
--- a/hw/char/sclpconsole.c
+++ b/hw/char/sclpconsole.c
@@ -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;
diff --git a/hw/s390x/ipl.c b/hw/s390x/ipl.c
index f104200273..5786b5e451 100644
--- a/hw/s390x/ipl.c
+++ b/hw/s390x/ipl.c
@@ -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;
}
diff --git a/hw/s390x/ipl.h b/hw/s390x/ipl.h
index 6b48ed7b93..9aa4d942a7 100644
--- a/hw/s390x/ipl.h
+++ b/hw/s390x/ipl.h
@@ -15,11 +15,60 @@
#include "hw/qdev.h"
#include "cpu.h"
-typedef struct IplParameterBlock {
- uint8_t reserved1[110];
- uint16_t devno;
- uint8_t reserved2[88];
-} 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];
+ 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
diff --git a/hw/s390x/s390-pci-bus.c b/hw/s390x/s390-pci-bus.c
index 918b58543e..a77c10ce9e 100644
--- a/hw/s390x/s390-pci-bus.c
+++ b/hw/s390x/s390-pci-bus.c
@@ -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;
+ uint64_t size = pbdev->pal - pbdev->pba + 1;
- 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);
- }
+ 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);
+ 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)
diff --git a/hw/s390x/s390-pci-bus.h b/hw/s390x/s390-pci-bus.h
index 59fd5c9583..2c852d47fa 100644
--- a/hw/s390x/s390-pci-bus.h
+++ b/hw/s390x/s390-pci-bus.h
@@ -198,11 +198,11 @@ typedef struct ChscSeiNt2Res {
} QEMU_PACKED ChscSeiNt2Res;
typedef struct PciCfgSccb {
- SCCBHeader header;
- uint8_t atype;
- uint8_t reserved1;
- uint16_t reserved2;
- uint32_t aid;
+ SCCBHeader header;
+ uint8_t atype;
+ uint8_t reserved1;
+ uint16_t reserved2;
+ uint32_t aid;
} QEMU_PACKED PciCfgSccb;
typedef struct S390MsixInfo {
@@ -219,6 +219,7 @@ typedef struct S390PCIBusDevice {
bool configured;
bool error_state;
bool lgstg_blocked;
+ bool iommu_enabled;
uint32_t fh;
uint32_t fid;
uint64_t g_iota;
@@ -247,8 +248,10 @@ typedef struct 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);
+void s390_pci_sclp_configure(SCCB *sccb);
+void s390_pci_sclp_deconfigure(SCCB *sccb);
+void s390_pci_iommu_enable(S390PCIBusDevice *pbdev);
+void s390_pci_iommu_disable(S390PCIBusDevice *pbdev);
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);
diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c
index b28e7d14f8..479375f65d 100644
--- a/hw/s390x/s390-pci-inst.c
+++ b/hw/s390x/s390-pci-inst.c
@@ -634,8 +634,15 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
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);
+ ret = map_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
+ if (ret) {
+ goto out;
+ }
+
+ ret = map_indicator(&pbdev->routes.adapter, pbdev->indicator);
+ if (ret) {
+ goto out;
+ }
pbdev->routes.adapter.summary_addr = ldq_p(&fib.aisb);
pbdev->routes.adapter.summary_offset = FIB_DATA_AISBO(ldl_p(&fib.data));
@@ -647,9 +654,15 @@ static int reg_irqs(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
DPRINTF("reg_irqs adapter id %d\n", pbdev->routes.adapter.adapter_id);
return 0;
+out:
+ release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
+ release_indicator(&pbdev->routes.adapter, pbdev->indicator);
+ pbdev->summary_ind = NULL;
+ pbdev->indicator = NULL;
+ return ret;
}
-static int dereg_irqs(S390PCIBusDevice *pbdev)
+int pci_dereg_irqs(S390PCIBusDevice *pbdev)
{
release_indicator(&pbdev->routes.adapter, pbdev->summary_ind);
release_indicator(&pbdev->routes.adapter, pbdev->indicator);
@@ -692,24 +705,23 @@ static int reg_ioat(CPUS390XState *env, S390PCIBusDevice *pbdev, ZpciFib fib)
pbdev->pal = pal;
pbdev->g_iota = g_iota;
- s390_pcihost_iommu_configure(pbdev, true);
+ s390_pci_iommu_enable(pbdev);
return 0;
}
-static void dereg_ioat(S390PCIBusDevice *pbdev)
+void pci_dereg_ioat(S390PCIBusDevice *pbdev)
{
+ s390_pci_iommu_disable(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;
+ uint8_t oc, dmaas;
uint32_t fh;
ZpciFib fib;
S390PCIBusDevice *pbdev;
@@ -721,6 +733,7 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
}
oc = env->regs[r1] & 0xff;
+ dmaas = (env->regs[r1] >> 16) & 0xff;
fh = env->regs[r1] >> 32;
if (fiba & 0x7) {
@@ -739,27 +752,65 @@ int mpcifc_service_call(S390CPU *cpu, uint8_t r1, uint64_t fiba, uint8_t ar)
return 0;
}
+ if (fib.fmt != 0) {
+ program_interrupt(env, PGM_OPERAND, 6);
+ return 0;
+ }
+
switch (oc) {
case ZPCI_MOD_FC_REG_INT:
- if (reg_irqs(env, pbdev, fib)) {
+ if (pbdev->summary_ind) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ } else if (reg_irqs(env, pbdev, fib)) {
cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_RES_NOT_AVAIL);
}
break;
case ZPCI_MOD_FC_DEREG_INT:
- dereg_irqs(pbdev);
+ if (!pbdev->summary_ind) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ } else {
+ pci_dereg_irqs(pbdev);
+ }
break;
case ZPCI_MOD_FC_REG_IOAT:
- if (reg_ioat(env, pbdev, fib)) {
+ if (dmaas != 0) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
+ } else if (pbdev->iommu_enabled) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ } else if (reg_ioat(env, pbdev, fib)) {
cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
}
break;
case ZPCI_MOD_FC_DEREG_IOAT:
- dereg_ioat(pbdev);
+ if (dmaas != 0) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
+ } else if (!pbdev->iommu_enabled) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ } else {
+ pci_dereg_ioat(pbdev);
+ }
break;
case ZPCI_MOD_FC_REREG_IOAT:
- dereg_ioat(pbdev);
- if (reg_ioat(env, pbdev, fib)) {
+ if (dmaas != 0) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_DMAAS_INVAL);
+ } else if (!pbdev->iommu_enabled) {
cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_SEQUENCE);
+ } else {
+ pci_dereg_ioat(pbdev);
+ if (reg_ioat(env, pbdev, fib)) {
+ cc = ZPCI_PCI_LS_ERR;
+ s390_set_status_code(env, r1, ZPCI_MOD_ST_INSUF_RES);
+ }
}
break;
case ZPCI_MOD_FC_RESET_ERROR:
diff --git a/hw/s390x/s390-pci-inst.h b/hw/s390x/s390-pci-inst.h
index 70fa71395f..b084f2346b 100644
--- a/hw/s390x/s390-pci-inst.h
+++ b/hw/s390x/s390-pci-inst.h
@@ -14,6 +14,7 @@
#ifndef HW_S390_PCI_INST_H
#define HW_S390_PCI_INST_H
+#include "s390-pci-bus.h"
#include <sysemu/dma.h>
/* CLP common request & response block size */
@@ -230,6 +231,14 @@ typedef struct ClpReqRspQueryPciGrp {
#define ZPCI_PCI_LS_BUSY 2
#define ZPCI_PCI_LS_INVAL_HANDLE 3
+/* Modify PCI status codes */
+#define ZPCI_MOD_ST_RES_NOT_AVAIL 4
+#define ZPCI_MOD_ST_INSUF_RES 16
+#define ZPCI_MOD_ST_SEQUENCE 24
+#define ZPCI_MOD_ST_DMAAS_INVAL 28
+#define ZPCI_MOD_ST_FRAME_INVAL 32
+#define ZPCI_MOD_ST_ERROR_RECOVER 40
+
/* Modify PCI Function Controls */
#define ZPCI_MOD_FC_REG_INT 2
#define ZPCI_MOD_FC_DEREG_INT 3
@@ -277,6 +286,8 @@ typedef struct ZpciFib {
uint32_t gd;
} QEMU_PACKED ZpciFib;
+int pci_dereg_irqs(S390PCIBusDevice *pbdev);
+void pci_dereg_ioat(S390PCIBusDevice *pbdev);
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);
diff --git a/hw/s390x/s390-virtio-ccw.c b/hw/s390x/s390-virtio-ccw.c
index e3df9c78ba..4456fce9f1 100644
--- a/hw/s390x/s390-virtio-ccw.c
+++ b/hw/s390x/s390-virtio-ccw.c
@@ -25,6 +25,7 @@
#include "s390-pci-bus.h"
#include "hw/s390x/storage-keys.h"
#include "hw/compat.h"
+#include "ipl.h"
#include "hw/s390x/s390-virtio-ccw.h"
static const char *const reset_dev_types[] = {
@@ -190,7 +191,9 @@ 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);
+ S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+ s390mc->ri_allowed = true;
mc->init = ccw_init;
mc->reset = s390_machine_reset;
mc->hot_add_cpu = s390_hot_add_cpu;
@@ -237,6 +240,20 @@ static inline void machine_set_dea_key_wrap(Object *obj, bool value,
ms->dea_key_wrap = value;
}
+bool ri_allowed(void)
+{
+ if (kvm_enabled()) {
+ MachineClass *mc = MACHINE_GET_CLASS(qdev_get_machine());
+ if (object_class_dynamic_cast(OBJECT_CLASS(mc),
+ TYPE_S390_CCW_MACHINE)) {
+ S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+ return s390mc->ri_allowed;
+ }
+ }
+ return 0;
+}
+
static inline void s390_machine_initfn(Object *obj)
{
object_property_add_bool(obj, "aes-key-wrap",
@@ -262,6 +279,7 @@ static const TypeInfo ccw_machine_info = {
.abstract = true,
.instance_size = sizeof(S390CcwMachineState),
.instance_init = s390_machine_initfn,
+ .class_size = sizeof(S390CcwMachineClass),
.class_init = ccw_machine_class_init,
.interfaces = (InterfaceInfo[]) {
{ TYPE_NMI },
@@ -299,7 +317,16 @@ static const TypeInfo ccw_machine_info = {
} \
type_init(ccw_machine_register_##suffix)
+#define CCW_COMPAT_2_6 \
+ HW_COMPAT_2_6 \
+ {\
+ .driver = TYPE_S390_IPL,\
+ .property = "iplbext_migration",\
+ .value = "off",\
+ },
+
#define CCW_COMPAT_2_5 \
+ CCW_COMPAT_2_6 \
HW_COMPAT_2_5
#define CCW_COMPAT_2_4 \
@@ -343,21 +370,38 @@ static const TypeInfo ccw_machine_info = {
.value = "0",\
},
+static void ccw_machine_2_7_instance_options(MachineState *machine)
+{
+}
+
+static void ccw_machine_2_7_class_options(MachineClass *mc)
+{
+}
+DEFINE_CCW_MACHINE(2_7, "2.7", true);
+
static void ccw_machine_2_6_instance_options(MachineState *machine)
{
+ ccw_machine_2_7_instance_options(machine);
}
static void ccw_machine_2_6_class_options(MachineClass *mc)
{
+ S390CcwMachineClass *s390mc = S390_MACHINE_CLASS(mc);
+
+ s390mc->ri_allowed = false;
+ ccw_machine_2_7_class_options(mc);
+ SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_6);
}
-DEFINE_CCW_MACHINE(2_6, "2.6", true);
+DEFINE_CCW_MACHINE(2_6, "2.6", false);
static void ccw_machine_2_5_instance_options(MachineState *machine)
{
+ ccw_machine_2_6_instance_options(machine);
}
static void ccw_machine_2_5_class_options(MachineClass *mc)
{
+ ccw_machine_2_6_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_5);
}
DEFINE_CCW_MACHINE(2_5, "2.5", false);
@@ -369,6 +413,7 @@ static void ccw_machine_2_4_instance_options(MachineState *machine)
static void ccw_machine_2_4_class_options(MachineClass *mc)
{
+ ccw_machine_2_5_class_options(mc);
SET_MACHINE_COMPAT(mc, CCW_COMPAT_2_4);
}
DEFINE_CCW_MACHINE(2_4, "2.4", false);
diff --git a/hw/s390x/sclp.c b/hw/s390x/sclp.c
index 85dbe1b600..fca37f511e 100644
--- a/hw/s390x/sclp.c
+++ b/hw/s390x/sclp.c
@@ -357,10 +357,10 @@ static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
sclp_c->unassign_storage(sclp, sccb);
break;
case SCLP_CMDW_CONFIGURE_PCI:
- s390_pci_sclp_configure(1, sccb);
+ s390_pci_sclp_configure(sccb);
break;
case SCLP_CMDW_DECONFIGURE_PCI:
- s390_pci_sclp_configure(0, sccb);
+ s390_pci_sclp_deconfigure(sccb);
break;
default:
efc->command_handler(ef, sccb, code);