[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-ppc] [PATCH 3/3] sPAPR: Support RTAS call ibm,errinjct
From: |
Gavin Shan |
Subject: |
[Qemu-ppc] [PATCH 3/3] sPAPR: Support RTAS call ibm,errinjct |
Date: |
Wed, 11 Mar 2015 17:39:32 +1100 |
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 <address@hidden>
---
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