From a6d9d4f26afc2c2fcfe6a89f0766371a60143d5a Mon Sep 17 00:00:00 2001 From: Yi Min Zhao Date: Thu, 28 Apr 2016 13:24:07 +0800 Subject: [PATCH] s390x/pci: enhance mpcifc_service_call Enhance error handling for mpcifc_service_call() to propagate errors to guest by setting status codes or triggering program interrupts. Signed-off-by: Yi Min Zhao Reviewed-by: Pierre Morel Signed-off-by: Cornelia Huck --- hw/s390x/s390-pci-inst.c | 53 +++++++++++++++++++++++++++++++++++++++++------- hw/s390x/s390-pci-inst.h | 8 ++++++++ 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/hw/s390x/s390-pci-inst.c b/hw/s390x/s390-pci-inst.c index 4b4dd63b5f..479375f65d 100644 --- a/hw/s390x/s390-pci-inst.c +++ b/hw/s390x/s390-pci-inst.c @@ -721,7 +721,7 @@ void pci_dereg_ioat(S390PCIBusDevice *pbdev) 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; @@ -733,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) { @@ -751,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: - pci_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: - pci_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: - pci_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 9fc94e91cc..b084f2346b 100644 --- a/hw/s390x/s390-pci-inst.h +++ b/hw/s390x/s390-pci-inst.h @@ -231,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 -- 2.11.4.GIT