From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([2001:4830:134:3::10]:47312) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YVaK4-0004e2-8S for qemu-devel@nongnu.org; Wed, 11 Mar 2015 02:40:55 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1YVaJs-0002mo-SN for qemu-devel@nongnu.org; Wed, 11 Mar 2015 02:40:52 -0400 Received: from e23smtp09.au.ibm.com ([202.81.31.142]:37039) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1YVaJr-0002ke-UE for qemu-devel@nongnu.org; Wed, 11 Mar 2015 02:40:40 -0400 Received: from /spool/local by e23smtp09.au.ibm.com with IBM ESMTP SMTP Gateway: Authorized Use Only! Violators will be prosecuted for from ; Wed, 11 Mar 2015 16:40:37 +1000 From: Gavin Shan Date: Wed, 11 Mar 2015 17:39:32 +1100 Message-Id: <1426055972-23775-4-git-send-email-gwshan@linux.vnet.ibm.com> In-Reply-To: <1426055972-23775-1-git-send-email-gwshan@linux.vnet.ibm.com> References: <1426055972-23775-1-git-send-email-gwshan@linux.vnet.ibm.com> Subject: [Qemu-devel] [PATCH 3/3] sPAPR: Support RTAS call ibm,errinjct List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org Cc: aik@ozlabs.ru, agraf@suse.de, Gavin Shan , alex.williamson@redhat.com, qemu-ppc@nongnu.org, david@gibson.dropbear.id.au The patch supports RTAS call "ibm,errinjct" to allow injecting EEH errors to VFIO PCI devices. The implementation is similiar to EEH support for VFIO PCI devices: The RTAS request is captured by QEMU and routed to sPAPRPHBClass::eeh_error_inject() where the request is translated to VFIO container IOCTL command to be handled by the host. Signed-off-by: Gavin Shan --- hw/ppc/spapr_pci.c | 47 +++++++++++++++++++++ hw/ppc/spapr_pci_vfio.c | 99 +++++++++++++++++++++++++++++++++++++++++++++ hw/ppc/spapr_rtas.c | 87 ++++++++++++++++++++++++++++++++++++++- include/hw/pci-host/spapr.h | 2 + include/hw/ppc/spapr.h | 48 +++++++++++++++++++++- 5 files changed, 280 insertions(+), 3 deletions(-) diff --git a/hw/ppc/spapr_pci.c b/hw/ppc/spapr_pci.c index 05f4fac..5f88d87 100644 --- a/hw/ppc/spapr_pci.c +++ b/hw/ppc/spapr_pci.c @@ -658,6 +658,53 @@ param_error_exit: rtas_st(rets, 0, RTAS_OUT_PARAM_ERROR); } +int spapr_rtas_errinjct_ioa(sPAPREnvironment *spapr, + target_ulong param_buf, + bool is_64bits) +{ + sPAPRPHBState *sphb; + sPAPRPHBClass *spc; + uint64_t buid, addr, mask; + uint32_t func; + int ret; + + if (is_64bits) { + addr = rtas_ldq(param_buf, 0); + mask = rtas_ldq(param_buf, 1); + buid = ((uint64_t)rtas_ld(param_buf, 5) << 32) | rtas_ld(param_buf, 6); + func = rtas_ld(param_buf, 7); + } else { + addr = rtas_ld(param_buf, 0); + mask = rtas_ld(param_buf, 1); + buid = ((uint64_t)rtas_ld(param_buf, 3) << 32) | rtas_ld(param_buf, 4); + func = rtas_ld(param_buf, 5); + } + + /* Check function is valid */ + if (func > RTAS_ERRINJCT_IOA_DMA_WR_MEM_TARGET) { + return RTAS_OUT_PARAM_ERROR; + } + + /* Find PHB */ + sphb = find_phb(spapr, buid); + if (!sphb) { + return RTAS_OUT_PARAM_ERROR; + } + + spc = SPAPR_PCI_HOST_BRIDGE_GET_CLASS(sphb); + if (!spc->eeh_error_inject) { + return RTAS_OUT_PARAM_ERROR; + } + + /* Handle the request */ + ret = spc->eeh_error_inject(sphb, func, addr, mask, is_64bits); + if (ret < 0) { + return RTAS_OUT_HW_ERROR; + } + + return RTAS_OUT_SUCCESS; +} + static int pci_spapr_swizzle(int slot, int pin) { return (slot + pin) % PCI_NUM_PINS; diff --git a/hw/ppc/spapr_pci_vfio.c b/hw/ppc/spapr_pci_vfio.c index 0cd96d3..6b8f7d2 100644 --- a/hw/ppc/spapr_pci_vfio.c +++ b/hw/ppc/spapr_pci_vfio.c @@ -199,6 +199,104 @@ static int spapr_phb_vfio_eeh_configure(sPAPRPHBState *sphb) return RTAS_OUT_SUCCESS; } +static int spapr_phb_vfio_eeh_error_inject(sPAPRPHBState *sphb, + uint32_t func, uint64_t addr, + uint64_t mask, bool is_64bits) +{ + sPAPRPHBVFIOState *svphb = SPAPR_PCI_VFIO_HOST_BRIDGE(sphb); + struct vfio_eeh_pe_op *op; + struct vfio_eeh_pe_err *err; + int argsz = sizeof(*op) + sizeof(*err); + int ret = RTAS_OUT_SUCCESS; + + op = g_malloc0(argsz); + err = (struct vfio_eeh_pe_err *)op->data; + op->argsz = argsz; + op->flags = 0; + op->op = VFIO_EEH_PE_INJECT_ERR; + err->type = is_64bits ? VFIO_EEH_ERR_TYPE_64 : VFIO_EEH_ERR_TYPE_32; + err->addr = addr; + err->mask = mask; + + switch (func) { + case RTAS_ERRINJCT_IOA_LD_MEM_ADDR: + err->func = VFIO_EEH_ERR_FUNC_LD_MEM_ADDR; + break; + case RTAS_ERRINJCT_IOA_LD_MEM_DATA: + err->func = VFIO_EEH_ERR_FUNC_LD_MEM_DATA; + break; + case RTAS_ERRINJCT_IOA_LD_IO_ADDR: + err->func = VFIO_EEH_ERR_FUNC_LD_IO_ADDR; + break; + case RTAS_ERRINJCT_IOA_LD_IO_DATA: + err->func = VFIO_EEH_ERR_FUNC_LD_IO_DATA; + break; + case RTAS_ERRINJCT_IOA_LD_CONFIG_ADDR: + err->func = VFIO_EEH_ERR_FUNC_LD_CFG_ADDR; + break; + case RTAS_ERRINJCT_IOA_LD_CONFIG_DATA: + err->func = VFIO_EEH_ERR_FUNC_LD_CFG_DATA; + break; + case RTAS_ERRINJCT_IOA_ST_MEM_ADDR: + err->func = VFIO_EEH_ERR_FUNC_ST_MEM_ADDR; + break; + case RTAS_ERRINJCT_IOA_ST_MEM_DATA: + err->func = VFIO_EEH_ERR_FUNC_ST_MEM_DATA; + break; + case RTAS_ERRINJCT_IOA_ST_IO_ADDR: + err->func = VFIO_EEH_ERR_FUNC_ST_IO_ADDR; + break; + case RTAS_ERRINJCT_IOA_ST_IO_DATA: + err->func = VFIO_EEH_ERR_FUNC_ST_IO_DATA; + break; + case RTAS_ERRINJCT_IOA_ST_CONFIG_ADDR: + err->func = VFIO_EEH_ERR_FUNC_ST_CFG_ADDR; + break; + case RTAS_ERRINJCT_IOA_ST_CONFIG_DATA: + err->func = VFIO_EEH_ERR_FUNC_ST_CFG_DATA; + break; + case RTAS_ERRINJCT_IOA_DMA_RD_MEM_ADDR: + err->func = VFIO_EEH_ERR_FUNC_DMA_RD_ADDR; + break; + case RTAS_ERRINJCT_IOA_DMA_RD_MEM_DATA: + err->func = VFIO_EEH_ERR_FUNC_DMA_RD_DATA; + break; + case RTAS_ERRINJCT_IOA_DMA_RD_MEM_MASTER: + err->func = VFIO_EEH_ERR_FUNC_DMA_RD_MASTER; + break; + case RTAS_ERRINJCT_IOA_DMA_RD_MEM_TARGET: + err->func = VFIO_EEH_ERR_FUNC_DMA_RD_TARGET; + break; + case RTAS_ERRINJCT_IOA_DMA_WR_MEM_ADDR: + err->func = VFIO_EEH_ERR_FUNC_DMA_WR_ADDR; + break; + case RTAS_ERRINJCT_IOA_DMA_WR_MEM_DATA: + err->func = VFIO_EEH_ERR_FUNC_DMA_WR_DATA; + break; + case RTAS_ERRINJCT_IOA_DMA_WR_MEM_MASTER: + err->func = VFIO_EEH_ERR_FUNC_DMA_WR_MASTER; + break; + case RTAS_ERRINJCT_IOA_DMA_WR_MEM_TARGET: + err->func = VFIO_EEH_ERR_FUNC_DMA_WR_TARGET; + break; + default: + ret = RTAS_OUT_PARAM_ERROR; + goto out; + } + + if (vfio_container_ioctl(&svphb->phb.iommu_as, svphb->iommugroupid, + VFIO_EEH_PE_OP, op) < 0) { + ret = RTAS_OUT_HW_ERROR; + goto out; + } + + /* Success */ + ret = RTAS_OUT_SUCCESS; +out: + g_free(op); + return ret; +} + static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -211,6 +309,7 @@ static void spapr_phb_vfio_class_init(ObjectClass *klass, void *data) spc->eeh_get_state = spapr_phb_vfio_eeh_get_state; spc->eeh_reset = spapr_phb_vfio_eeh_reset; spc->eeh_configure = spapr_phb_vfio_eeh_configure; + spc->eeh_error_inject = spapr_phb_vfio_eeh_error_inject; } static const TypeInfo spapr_phb_vfio_info = { diff --git a/hw/ppc/spapr_rtas.c b/hw/ppc/spapr_rtas.c index 0afc5dd..ed110aa 100644 --- a/hw/ppc/spapr_rtas.c +++ b/hw/ppc/spapr_rtas.c @@ -279,6 +279,53 @@ out: rtas_st(rets, 1, ret); } +static void rtas_ibm_errinjct(PowerPCCPU *cpu, + sPAPREnvironment *spapr, + uint32_t token, uint32_t nargs, + target_ulong args, uint32_t nret, + target_ulong rets) +{ + target_ulong param_buf; + uint32_t type, open_token; + int32_t ret; + + /* Sanity check on number of arguments */ + if ((nargs != 3) || (nret != 1)) { + ret = RTAS_OUT_PARAM_ERROR; + goto out; + } + + /* Check if we had opened token */ + open_token = rtas_ld(args, 1); + if (spapr->errinjct_token != open_token) { + ret = RTAS_OUT_TOKEN_OPENED; + goto out; + } + + /* The parameter buffer should be 1KB aligned */ + param_buf = rtas_ld(args, 2); + if (param_buf & 0x3ff) { + ret = RTAS_OUT_PARAM_ERROR; + goto out; + } + + /* Check the error type */ + type = rtas_ld(args, 0); + switch (type) { + case RTAS_ERRINJCT_TYPE_IOA_BUS_ERROR: + ret = spapr_rtas_errinjct_ioa(spapr, param_buf, false); + break; + case RTAS_ERRINJCT_TYPE_IOA_BUS_ERROR64: + ret = spapr_rtas_errinjct_ioa(spapr, param_buf, true); + break; + default: + ret = RTAS_OUT_PARAM_ERROR; + } + +out: + rtas_st(rets, 0, ret); +} + static void rtas_ibm_close_errinjct(PowerPCCPU *cpu, sPAPREnvironment *spapr, uint32_t token, uint32_t nargs, @@ -367,8 +414,42 @@ void spapr_rtas_register(int token, const char *name, spapr_rtas_fn fn) int spapr_rtas_device_tree_setup(void *fdt, hwaddr rtas_addr, hwaddr rtas_size) { - int ret; - int i; + const char *tokens[] = { + "fatal", + "recovered-random-event", + "recovered-special-event", + "corrupted-page", + "corrupted-slb", + "translator-failure", + "ioa-bus-error", + "ioa-bus-error-64", + "platform-specific", + "corrupted-dcache-start", + "corrupted-dcache-end", + "corrupted-icache-start", + "corrupted-icache-end", + "corrupted-tlb-start", + "corrupted-tlb-end" + }; + char errinjct_tokens[1024]; + int fdt_offset, offset, i, ret; + + /* ibm,errinjct-tokens */ + offset = 0; + for (i = 0; i < ARRAY_SIZE(tokens); i++) { + offset += sprintf(errinjct_tokens + offset, "%s", tokens[i]); + errinjct_tokens[offset++] = '\0'; + *(int *)(&errinjct_tokens[offset]) = i+1; + offset += sizeof(int); + } + + fdt_offset = fdt_path_offset(fdt, "/rtas"); + ret = fdt_setprop(fdt, fdt_offset, "ibm,errinjct-tokens", + errinjct_tokens, offset); + if (ret < 0) { + fprintf(stderr, "Couldn't add ibm,errinjct-tokens\n"); + return ret; + } ret = fdt_add_mem_rsv(fdt, rtas_addr, rtas_size); if (ret < 0) { @@ -441,6 +522,8 @@ static void core_rtas_register_types(void) rtas_ibm_os_term); spapr_rtas_register(RTAS_IBM_OPEN_ERRINJCT, "ibm,open-errinjct", rtas_ibm_open_errinjct); + spapr_rtas_register(RTAS_IBM_ERRINJCT, "ibm,errinjct", + rtas_ibm_errinjct); spapr_rtas_register(RTAS_IBM_CLOSE_ERRINJCT, "ibm,close-errinjct", rtas_ibm_close_errinjct); } diff --git a/include/hw/pci-host/spapr.h b/include/hw/pci-host/spapr.h index 895d273..3546dc6 100644 --- a/include/hw/pci-host/spapr.h +++ b/include/hw/pci-host/spapr.h @@ -53,6 +53,8 @@ struct sPAPRPHBClass { int (*eeh_get_state)(sPAPRPHBState *sphb, int *state); int (*eeh_reset)(sPAPRPHBState *sphb, int option); int (*eeh_configure)(sPAPRPHBState *sphb); + int (*eeh_error_inject)(sPAPRPHBState *sphb, uint32_t func, + uint64_t addr, uint64_t mask, bool is_64bits); }; typedef struct spapr_pci_msi { diff --git a/include/hw/ppc/spapr.h b/include/hw/ppc/spapr.h index 4f7cc2e..de0466a 100644 --- a/include/hw/ppc/spapr.h +++ b/include/hw/ppc/spapr.h @@ -375,6 +375,44 @@ int spapr_allocate_irq_block(int num, bool lsi, bool msi); #define RTAS_SLOT_TEMP_ERR_LOG 1 #define RTAS_SLOT_PERM_ERR_LOG 2 +/* ibm,errinjct */ +#define RTAS_ERRINJCT_TYPE_FATAL 1 +#define RTAS_ERRINJCT_TYPE_RANDOM_EVENT 2 +#define RTAS_ERRINJCT_TYPE_SPECIAL_EVENT 3 +#define RTAS_ERRINJCT_TYPE_CORRUPTED_PAGE 4 +#define RTAS_ERRINJCT_TYPE_CORRUPTED_SLB 5 +#define RTAS_ERRINJCT_TYPE_TRANSLATOR_FAILURE 6 +#define RTAS_ERRINJCT_TYPE_IOA_BUS_ERROR 7 +#define RTAS_ERRINJCT_TYPE_IOA_BUS_ERROR64 8 +#define RTAS_ERRINJCT_IOA_LD_MEM_ADDR 0 +#define RTAS_ERRINJCT_IOA_LD_MEM_DATA 1 +#define RTAS_ERRINJCT_IOA_LD_IO_ADDR 2 +#define RTAS_ERRINJCT_IOA_LD_IO_DATA 3 +#define RTAS_ERRINJCT_IOA_LD_CONFIG_ADDR 4 +#define RTAS_ERRINJCT_IOA_LD_CONFIG_DATA 5 +#define RTAS_ERRINJCT_IOA_ST_MEM_ADDR 6 +#define RTAS_ERRINJCT_IOA_ST_MEM_DATA 7 +#define RTAS_ERRINJCT_IOA_ST_IO_ADDR 8 +#define RTAS_ERRINJCT_IOA_ST_IO_DATA 9 +#define RTAS_ERRINJCT_IOA_ST_CONFIG_ADDR 10 +#define RTAS_ERRINJCT_IOA_ST_CONFIG_DATA 11 +#define RTAS_ERRINJCT_IOA_DMA_RD_MEM_ADDR 12 +#define RTAS_ERRINJCT_IOA_DMA_RD_MEM_DATA 13 +#define RTAS_ERRINJCT_IOA_DMA_RD_MEM_MASTER 14 +#define RTAS_ERRINJCT_IOA_DMA_RD_MEM_TARGET 15 +#define RTAS_ERRINJCT_IOA_DMA_WR_MEM_ADDR 16 +#define RTAS_ERRINJCT_IOA_DMA_WR_MEM_DATA 17 +#define RTAS_ERRINJCT_IOA_DMA_WR_MEM_MASTER 18 +#define RTAS_ERRINJCT_IOA_DMA_WR_MEM_TARGET 19 +#define RTAS_ERRINJCT_TYPE_PLATFORM_SPECIFIC 9 +#define RTAS_ERRINJCT_TYPE_DCACHE_START 10 +#define RTAS_ERRINJCT_TYPE_DCACHE_END 11 +#define RTAS_ERRINJCT_TYPE_ICACHE_START 12 +#define RTAS_ERRINJCT_TYPE_ICACHE_END 13 +#define RTAS_ERRINJCT_TYPE_TLB_START 14 +#define RTAS_ERRINJCT_TYPE_TLB_END 15 +#define RTAS_ERRINJCT_TYPE_UPSTREAM_IO_ERROR 16 + /* RTAS return codes */ #define RTAS_OUT_SUCCESS 0 #define RTAS_OUT_NO_ERRORS_FOUND 1 @@ -429,8 +467,9 @@ int spapr_allocate_irq_block(int num, bool lsi, bool msi); #define RTAS_IBM_SLOT_ERROR_DETAIL (RTAS_TOKEN_BASE + 0x25) #define RTAS_IBM_OPEN_ERRINJCT (RTAS_TOKEN_BASE + 0x26) #define RTAS_IBM_CLOSE_ERRINJCT (RTAS_TOKEN_BASE + 0x27) +#define RTAS_IBM_ERRINJCT (RTAS_TOKEN_BASE + 0x28) -#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x28) +#define RTAS_TOKEN_MAX (RTAS_TOKEN_BASE + 0x29) /* RTAS ibm,get-system-parameter token values */ #define RTAS_SYSPARM_SPLPAR_CHARACTERISTICS 20 @@ -455,6 +494,11 @@ static inline uint32_t rtas_ld(target_ulong phys, int n) return ldl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n)); } +static inline uint64_t rtas_ldq(target_ulong phys, int n) +{ + return ldq_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 8*n)); +} + static inline void rtas_st(target_ulong phys, int n, uint32_t val) { stl_be_phys(&address_space_memory, ppc64_phys_to_real(phys + 4*n), val); @@ -528,6 +572,8 @@ int spapr_dma_dt(void *fdt, int node_off, const char *propname, int spapr_tcet_dma_dt(void *fdt, int node_off, const char *propname, sPAPRTCETable *tcet); void spapr_pci_switch_vga(bool big_endian); +int spapr_rtas_errinjct_ioa(sPAPREnvironment *spapr, + target_ulong param_buf, bool is_64bits); #define TYPE_SPAPR_RTC "spapr-rtc" -- 1.8.3.2