aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2014-10-02 16:30:11 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-08 14:07:46 +1100
commit4bb318eeeb67d40071020de87dedbf5a04538b48 (patch)
tree857b5c0a039952041651de01c960dede95ea975e
parent38de7930a078da0b69e5803ef7003fe809bf67b1 (diff)
downloadskiboot-4bb318eeeb67d40071020de87dedbf5a04538b48.zip
skiboot-4bb318eeeb67d40071020de87dedbf5a04538b48.tar.gz
skiboot-4bb318eeeb67d40071020de87dedbf5a04538b48.tar.bz2
PCI: Refactor error injection
The patch refactors the code we had for PCI error injection. It doesn't change the logic: * Rename names of error types and functions according to the comments given by Michael Ellerman when reviewing the kernel counterpart. * Split The backend of error injection for PHB3 and P7IOC to multiple functions to improve code readability. Some logics are simplified without affecting their original functionality. * Misc cleanup like renaming variables and functions. Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--core/pci-opal.c17
-rw-r--r--hw/p7ioc-phb.c427
-rw-r--r--hw/phb3.c260
-rw-r--r--include/opal.h54
-rw-r--r--include/pci.h4
5 files changed, 401 insertions, 361 deletions
diff --git a/core/pci-opal.c b/core/pci-opal.c
index 47c9377..bb6bb70 100644
--- a/core/pci-opal.c
+++ b/core/pci-opal.c
@@ -112,31 +112,30 @@ static int64_t opal_pci_eeh_freeze_set(uint64_t phb_id, uint64_t pe_number,
}
opal_call(OPAL_PCI_EEH_FREEZE_SET, opal_pci_eeh_freeze_set, 3);
-static int64_t opal_pci_err_injct(uint64_t phb_id, uint32_t pe_no,
- uint32_t type, uint32_t function,
- uint64_t addr, uint64_t mask)
+static int64_t opal_pci_err_inject(uint64_t phb_id, uint32_t pe_no,
+ uint32_t type, uint32_t func,
+ uint64_t addr, uint64_t mask)
{
struct phb *phb = pci_get_phb(phb_id);
int64_t rc;
if (!phb)
return OPAL_PARAMETER;
- if (!phb->ops || !phb->ops->err_injct)
+ if (!phb->ops || !phb->ops->err_inject)
return OPAL_UNSUPPORTED;
- if (type != OpalErrinjctTypeIoaBusError &&
- type != OpalErrinjctTypeIoaBusError64)
+ if (type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR &&
+ type != OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64)
return OPAL_PARAMETER;
phb->ops->lock(phb);
- rc = phb->ops->err_injct(phb, pe_no, type,
- function, addr, mask);
+ rc = phb->ops->err_inject(phb, pe_no, type, func, addr, mask);
phb->ops->unlock(phb);
pci_put_phb(phb);
return rc;
}
-opal_call(OPAL_PCI_ERR_INJCT, opal_pci_err_injct, 6);
+opal_call(OPAL_PCI_ERR_INJECT, opal_pci_err_inject, 6);
static int64_t opal_pci_phb_mmio_enable(uint64_t phb_id, uint16_t window_type,
uint16_t window_num, uint16_t enable)
diff --git a/hw/p7ioc-phb.c b/hw/p7ioc-phb.c
index 89f7ee1..34ee683 100644
--- a/hw/p7ioc-phb.c
+++ b/hw/p7ioc-phb.c
@@ -1329,237 +1329,262 @@ static int64_t p7ioc_eeh_freeze_set(struct phb *phb, uint64_t pe_number,
return OPAL_SUCCESS;
}
-
-static int64_t p7ioc_err_injct(struct phb *phb, uint32_t pe_no,
- uint32_t type, uint32_t function,
- uint64_t address, uint64_t mask)
+static int64_t p7ioc_err_inject_finalize(struct p7ioc_phb *p, uint64_t addr,
+ uint64_t mask, uint64_t ctrl,
+ bool is_write)
{
- struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
- uint64_t pelt, ctl = 0;
- uint64_t base, prefer, addr, msk;
- int index = 0, bus_valid = 0;
+ if (is_write)
+ ctrl |= PHB_PAPR_ERR_INJ_CTL_WR;
+ else
+ ctrl |= PHB_PAPR_ERR_INJ_CTL_RD;
- /* To support 64-bits error later */
- if (type == OpalErrinjctTypeIoaBusError64)
- return OPAL_UNSUPPORTED;
- /*
- * The control register might have something left from
- * the error injection of last time. We need clear it
- * for consistency
+ /* HW100549: Take read and write for outbound errors
+ * on DD10 chip
*/
- out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul);
+ if (p->rev == P7IOC_REV_DD10)
+ ctrl |= (PHB_PAPR_ERR_INJ_CTL_RD | PHB_PAPR_ERR_INJ_CTL_WR);
- /* We shouldn't inject error to the reserved PE#127 */
- if (pe_no > 126 ||
- function > OpalEjtIoaDmaWriteMemTarget)
- return OPAL_PARAMETER;
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_ADDR, addr);
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_MASK, mask);
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, ctrl);
+
+ return OPAL_SUCCESS;
+}
- /* Looking into PELTM cache to see if the PE# is valid */
- pelt = p->peltm_cache[pe_no];
- if (pelt == 0x0001f80000000000)
+static int64_t p7ioc_err_inject_mem32(struct p7ioc_phb *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ uint64_t a, m, prefer, base;
+ uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_OUTB;
+ int32_t index;
+
+ a = 0x0ull;
+ prefer = 0x0ull;
+ for (index = 0; index < 128; index++) {
+ if (GETFIELD(IODA_XXDT_PE, p->m32d_cache[index]) != pe_no)
+ continue;
+
+ base = p->m32_base + M32_PCI_START +
+ (M32_PCI_SIZE / 128) * index;
+
+ /* Update preferred address */
+ if (!prefer) {
+ prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, base);
+ prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO,
+ 0x0ull, prefer);
+ }
+
+ /* The input address matches ? */
+ if (addr >= base &&
+ addr < base + (M32_PCI_SIZE / 128)) {
+ a = addr;
+ break;
+ }
+ }
+
+ /* Invalid PE number */
+ if (!prefer)
return OPAL_PARAMETER;
- /*
- * HW100549: For error injection on outbound opertions, we
- * need have read and write on DD10 chip.
- */
- switch (function) {
- case OpalEjtIoaLoadMemAddr:
- case OpalEjtIoaLoadMemData:
- case OpalEjtIoaStoreMemAddr:
- case OpalEjtIoaStoreMemData:
- ctl |= PHB_PAPR_ERR_INJ_CTL_OUTB;
- if (function == OpalEjtIoaLoadMemAddr ||
- function == OpalEjtIoaLoadMemData)
- ctl |= PHB_PAPR_ERR_INJ_CTL_RD;
- else
- ctl |= PHB_PAPR_ERR_INJ_CTL_WR;
-
- if (p->rev == P7IOC_REV_DD10)
- ctl |= (PHB_PAPR_ERR_INJ_CTL_RD |
- PHB_PAPR_ERR_INJ_CTL_WR);
+ /* Specified address is out of range */
+ if (!a) {
+ a = prefer;
+ m = PHB_PAPR_ERR_INJ_MASK_MMIO_MASK;
+ } else {
+ m = mask;
+ }
- /*
- * For now, we only care about M32. Looking into M32DT to see
- * if the input address has been assigned to the PE.
- */
- addr = 0x0ul;
- prefer = 0x0ul;
- for (index = 0; index < 128; index++) {
- if (SETFIELD(IODA_XXDT_PE, 0ull, pe_no) ==
- p->m32d_cache[index]) {
- base = p->m32_base + M32_PCI_START +
- (M32_PCI_SIZE / 128) * index;
-
- /* Update prefer address */
- if (!prefer) {
- prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, base);
- prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, 0x0ul, prefer);
- }
+ return p7ioc_err_inject_finalize(p, a, m, ctrl, is_write);
+}
- /* The input address matches ? */
- if (address >= base &&
- address < base + (M32_PCI_SIZE / 128)) {
- addr = address;
- break;
- }
- }
+static int64_t p7ioc_err_inject_io32(struct p7ioc_phb *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ uint64_t a, m, prefer, base;
+ uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_OUTB;
+ int32_t index;
+
+ addr = 0x0ull;
+ prefer = 0x0ull;
+ for (index = 0; index < 128; index++) {
+ if (GETFIELD(IODA_XXDT_PE, p->iod_cache[index]) != pe_no)
+ continue;
+
+ base = p->io_base + (PHB_IO_SIZE / 128) * index;
+
+ /* Update preferred address */
+ if (!prefer) {
+ prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_IO, base);
+ prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_IO, 0x0ull, prefer);
}
- /* Need amend the address ? */
- if (!addr) {
- if (!prefer)
- return OPAL_PARAMETER;
-
- addr = prefer;
- msk = PHB_PAPR_ERR_INJ_MASK_MMIO_MASK;
- } else {
- msk = mask;
+ /* The input address matches ? */
+ if (addr >= base &&
+ addr < base + (PHB_IO_SIZE / 128)) {
+ a = addr;
+ break;
}
+ }
- break;
- case OpalEjtIoaLoadIoAddr:
- case OpalEjtIoaLoadIoData:
- case OpalEjtIoaStoreIoAddr:
- case OpalEjtIoaStoreIoData:
- ctl |= PHB_PAPR_ERR_INJ_CTL_OUTB;
- if (function == OpalEjtIoaLoadIoAddr ||
- function == OpalEjtIoaLoadIoData)
- ctl |= PHB_PAPR_ERR_INJ_CTL_RD;
- else
- ctl |= PHB_PAPR_ERR_INJ_CTL_WR;
-
- if (p->rev == P7IOC_REV_DD10)
- ctl |= (PHB_PAPR_ERR_INJ_CTL_RD |
- PHB_PAPR_ERR_INJ_CTL_WR);
+ /* Invalid PE number */
+ if (!prefer)
+ return OPAL_PARAMETER;
- /*
- * Similar to M32 case. Looking into IO domain to see
- * if the input address is owned by the designated PE.
- * Otherwise, we have to pick one up from IO domain.
- */
- addr = 0x0ul;
- prefer = 0x0ul;
- for (index = 0; index < 128; index++) {
- if (SETFIELD(IODA_XXDT_PE, 0ull, pe_no) ==
- p->iod_cache[index]) {
- base = p->io_base + (PHB_IO_SIZE / 128) * index;
-
- /* Update prefer address */
- if (!prefer) {
- prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_IO, base);
- prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_IO, 0x0ul, prefer);
- }
+ /* Specified address is out of range */
+ if (!a) {
+ a = prefer;
+ m = PHB_PAPR_ERR_INJ_MASK_IO_MASK;
+ } else {
+ m = mask;
+ }
- /* The input address matches ? */
- if (address >= base &&
- address < base + (PHB_IO_SIZE / 128)) {
- addr = address;
- break;
- }
- }
- }
+ return p7ioc_err_inject_finalize(p, a, m, ctrl, is_write);
+}
- /* Need amend the address ? */
- if (!addr) {
- if (!prefer)
- return OPAL_PARAMETER;
+static int64_t p7ioc_err_inject_cfg(struct p7ioc_phb *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ uint64_t a, m;
+ uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_CFG;
+ uint8_t v_bits, base, bus_no;
- addr = prefer;
- msk = PHB_PAPR_ERR_INJ_MASK_IO_MASK;
- } else {
- msk = mask;
+ /* Looking into PELTM to see if the PCI bus# is owned
+ * by the PE#. Otherwise, we have to figure one out.
+ */
+ base = GETFIELD(IODA_PELTM_BUS, p->peltm_cache[pe_no]);
+ v_bits = GETFIELD(IODA_PELTM_BUS_VALID, p->peltm_cache[pe_no]);
+ switch (v_bits) {
+ case IODA_BUS_VALID_3_BITS:
+ case IODA_BUS_VALID_4_BITS:
+ case IODA_BUS_VALID_5_BITS:
+ case IODA_BUS_VALID_6_BITS:
+ case IODA_BUS_VALID_7_BITS:
+ case IODA_BUS_VALID_ALL:
+ base = GETFIELD(IODA_PELTM_BUS, p->peltm_cache[pe_no]);
+ base &= (0xff - (((1 << (7 - v_bits)) - 1)));
+ a = SETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, 0x0ul, base);
+ m = PHB_PAPR_ERR_INJ_MASK_CFG_MASK;
+
+ bus_no = GETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, addr);
+ bus_no &= (0xff - (((1 << (7 - v_bits)) - 1)));
+ if (base == bus_no) {
+ a = addr;
+ m = mask;
}
break;
- case OpalEjtIoaLoadConfigAddr:
- case OpalEjtIoaLoadConfigData:
- case OpalEjtIoaStoreConfigAddr:
- case OpalEjtIoaStoreConfigData:
- ctl |= PHB_PAPR_ERR_INJ_CTL_CFG;
- if (function == OpalEjtIoaLoadConfigAddr ||
- function == OpalEjtIoaLoadConfigData)
- ctl |= PHB_PAPR_ERR_INJ_CTL_RD;
- else
- ctl |= PHB_PAPR_ERR_INJ_CTL_WR;
-
- if (p->rev == P7IOC_REV_DD10)
- ctl |= (PHB_PAPR_ERR_INJ_CTL_RD |
- PHB_PAPR_ERR_INJ_CTL_WR);
+ case IODA_BUS_VALID_ANY:
+ default:
+ return OPAL_PARAMETER;
+ }
- /*
- * Looking into PELTM to see if the PCI bus# is owned
- * by the PE#. Otherwise, we have to figure one out.
- */
- bus_valid = GETFIELD(IODA_PELTM_BUS_VALID, pelt);
- base = GETFIELD(IODA_PELTM_BUS, pelt);
- addr = 0x0ul;
- prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, 0x0ul, base);
- switch (bus_valid) {
- case 0x0:
- addr = address;
- break;
- case 0x1:
- return OPAL_HARDWARE;
- default:
- if (GETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, address) >= base
- && GETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, address)
- < base + (0x1ul << (7 - bus_valid)))
- addr = address;
- break;
- }
+ return p7ioc_err_inject_finalize(p, a, m, ctrl, is_write);
+}
- /* Address needs amend ? */
- if (!addr) {
- addr = prefer;
- msk = PHB_PAPR_ERR_INJ_MASK_CFG_MASK;
- } else {
- msk = mask;
- }
+static int64_t p7ioc_err_inject_dma(struct p7ioc_phb *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_INB;
+ int32_t index;
+
+ /* For DMA, we just pick address from TVT */
+ for (index = 0; index < 128; index++) {
+ if (GETFIELD(IODA_TVT1_PE_NUM, p->tve_hi_cache[index]) != pe_no)
+ continue;
+ addr = SETFIELD(PHB_PAPR_ERR_INJ_MASK_DMA, 0ul, index);
+ mask = PHB_PAPR_ERR_INJ_MASK_DMA_MASK;
break;
- case OpalEjtIoaDmaReadMemAddr:
- case OpalEjtIoaDmaReadMemData:
- case OpalEjtIoaDmaReadMemMaster:
- case OpalEjtIoaDmaReadMemTarget:
- case OpalEjtIoaDmaWriteMemAddr:
- case OpalEjtIoaDmaWriteMemData:
- case OpalEjtIoaDmaWriteMemMaster:
- case OpalEjtIoaDmaWriteMemTarget:
- ctl |= PHB_PAPR_ERR_INJ_CTL_INB;
- if (function == OpalEjtIoaDmaReadMemAddr ||
- function == OpalEjtIoaDmaReadMemData ||
- function == OpalEjtIoaDmaReadMemMaster ||
- function == OpalEjtIoaDmaReadMemTarget)
- ctl |= PHB_PAPR_ERR_INJ_CTL_RD;
- else
- ctl |= PHB_PAPR_ERR_INJ_CTL_WR;
-
- /* For DMA, we just pick address from TVT */
- addr = 0x0;
- for (index = 0; index < 128; index++) {
- if (GETFIELD(IODA_TVT1_PE_NUM, p->tve_hi_cache[index])
- == pe_no) {
- addr = SETFIELD(PHB_PAPR_ERR_INJ_MASK_DMA, 0ul, index);
- msk = PHB_PAPR_ERR_INJ_MASK_DMA_MASK;
- break;
- }
- }
+ }
- /* Some PE might not have DMA capability */
- if (index >= 128)
- return OPAL_PARAMETER;
+ /* Some PE might not have DMA capability */
+ if (index >= 128)
+ return OPAL_PARAMETER;
+
+ return p7ioc_err_inject_finalize(p, addr, mask, ctrl, is_write);
+}
+static int64_t p7ioc_err_inject(struct phb *phb, uint32_t pe_no,
+ uint32_t type, uint32_t func,
+ uint64_t addr, uint64_t mask)
+{
+ struct p7ioc_phb *p = phb_to_p7ioc_phb(phb);
+ int64_t (*handler)(struct p7ioc_phb *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask, bool is_write);
+ bool is_write;
+
+ /* To support 64-bits error later */
+ if (type == OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64)
+ return OPAL_UNSUPPORTED;
+
+ /* We can't inject error to the reserved PE#127 */
+ if (pe_no > 126)
+ return OPAL_PARAMETER;
+
+ /* Clear the leftover from last time */
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul);
+
+ /* Check if PE number is valid one in PELTM cache */
+ if (p->peltm_cache[pe_no] == 0x0001f80000000000ull)
+ return OPAL_PARAMETER;
+
+ /* Clear the leftover from last time */
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul);
+
+ switch (func) {
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_DATA:
+ is_write = false;
+ handler = p7ioc_err_inject_mem32;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_DATA:
+ is_write = true;
+ handler = p7ioc_err_inject_mem32;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_IO_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_IO_DATA:
+ is_write = false;
+ handler = p7ioc_err_inject_io32;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_IO_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_IO_DATA:
+ is_write = true;
+ handler = p7ioc_err_inject_io32;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_DATA:
+ is_write = false;
+ handler = p7ioc_err_inject_cfg;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_DATA:
+ is_write = true;
+ handler = p7ioc_err_inject_cfg;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_DATA:
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_MASTER:
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_TARGET:
+ is_write = false;
+ handler = p7ioc_err_inject_dma;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_DATA:
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_MASTER:
+ case OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET:
+ is_write = true;
+ handler = p7ioc_err_inject_dma;
break;
default:
return OPAL_PARAMETER;
}
- out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, ctl);
- out_be64(p->regs + PHB_PAPR_ERR_INJ_ADDR, addr);
- out_be64(p->regs + PHB_PAPR_ERR_INJ_MASK, msk);
-
- return OPAL_SUCCESS;
+ return handler(p, pe_no, addr, mask, is_write);
}
static int64_t p7ioc_get_diag_data(struct phb *phb, void *diag_buffer,
@@ -2556,7 +2581,7 @@ static const struct phb_ops p7ioc_phb_ops = {
.eeh_freeze_status = p7ioc_eeh_freeze_status,
.eeh_freeze_clear = p7ioc_eeh_freeze_clear,
.eeh_freeze_set = p7ioc_eeh_freeze_set,
- .err_injct = p7ioc_err_injct,
+ .err_inject = p7ioc_err_inject,
.get_diag_data = NULL,
.get_diag_data2 = p7ioc_get_diag_data,
.next_error = p7ioc_eeh_next_error,
diff --git a/hw/phb3.c b/hw/phb3.c
index f2af4a5..2623d5a 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -2593,148 +2593,162 @@ static int64_t phb3_eeh_next_error(struct phb *phb,
return OPAL_SUCCESS;
}
-static int64_t phb3_err_injct(struct phb *phb, uint32_t pe_no,
- uint32_t type, uint32_t function,
- uint64_t address, uint64_t mask)
+static int64_t phb3_err_inject_finalize(struct phb3 *p, uint64_t addr,
+ uint64_t mask, uint64_t ctrl,
+ bool is_write)
{
- struct phb3 *p = phb_to_phb3(phb);
- uint64_t ctl = 0;
- uint64_t base, prefer, addr, msk;
- int index = 0;
- bool bus_valid = false;
+ if (is_write)
+ ctrl |= PHB_PAPR_ERR_INJ_CTL_WR;
+ else
+ ctrl |= PHB_PAPR_ERR_INJ_CTL_RD;
- /* To support 64-bits error injection later */
- if (type == OpalErrinjctTypeIoaBusError64)
- return OPAL_UNSUPPORTED;
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_ADDR, addr);
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_MASK, mask);
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, ctrl);
- /*
- * How could we get here without valid RTT? But it's
- * worthy to check.
- */
- if (!p->tbl_rtt)
- return OPAL_HARDWARE;
+ return OPAL_SUCCESS;
+}
- /*
- * PE#0 is reserved PE on PHB3 and we shouldn't inject
- * errors to it.
- */
- if (pe_no == 0x0 ||
- pe_no >= PHB3_MAX_PE_NUM ||
- function > OpalEjtIoaDmaWriteMemTarget)
+static int64_t phb3_err_inject_mem32(struct phb3 *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ uint64_t a, m, prefer, base;
+ uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_OUTB;
+ int index;
+
+ a = 0x0ull;
+ prefer = 0x0ull;
+ for (index = 0; index < PHB3_MAX_PE_NUM; index++) {
+ if (GETFIELD(IODA2_M32DT_PE, p->m32d_cache[index]) != pe_no)
+ continue;
+
+ base = p->mm1_base + (M32_PCI_SIZE / PHB3_MAX_PE_NUM) * index;
+
+ /* Update preferred address */
+ if (!prefer) {
+ prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, base);
+ prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, 0x0ull, prefer);
+ }
+
+ /* The input address matches ? */
+ if (addr >= base &&
+ addr < base + M32_PCI_SIZE / PHB3_MAX_PE_NUM) {
+ a = addr;
+ break;
+ }
+ }
+
+ /* Invalid PE number */
+ if (!prefer)
return OPAL_PARAMETER;
- /* We might have leftover from last error injection */
- out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul);
+ /* Specified address is out of range */
+ if (!a) {
+ a = prefer;
+ m = PHB_PAPR_ERR_INJ_MASK_MMIO_MASK;
+ } else {
+ m = mask;
+ }
+
+ return phb3_err_inject_finalize(p, a, m, ctrl, is_write);
+}
- switch (function) {
- case OpalEjtIoaLoadMemAddr:
- case OpalEjtIoaLoadMemData:
- case OpalEjtIoaStoreMemAddr:
- case OpalEjtIoaStoreMemData:
- ctl |= PHB_PAPR_ERR_INJ_CTL_OUTB;
- if (function == OpalEjtIoaLoadMemAddr ||
- function == OpalEjtIoaLoadMemData)
- ctl |= PHB_PAPR_ERR_INJ_CTL_RD;
- else
- ctl |= PHB_PAPR_ERR_INJ_CTL_WR;
+static int64_t phb3_err_inject_cfg(struct phb3 *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ uint64_t a, m, prefer;
+ uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_CFG;
+ int bus_no, bdfn;
+
+ a = 0xffffull;
+ prefer = 0xffffull;
+ for (bdfn = 0; bdfn < RTT_TABLE_ENTRIES; bdfn++) {
+ if (p->rte_cache[bdfn] != pe_no)
+ continue;
- /*
- * For now, we only care about M32. Looking into M32DT to see
- * if the input address has been assigned to the PE. Otherwise,
- * we have to figure one out from M32DT.
+ /* Select minimal bus number as PE
+ * primary bus number
*/
- addr = 0x0ul;
- prefer = 0x0ul;
- for (index = 0; index < 256; index++) {
- if (GETFIELD(IODA2_M32DT_PE, p->m32d_cache[index]) ==
- pe_no) {
- base = p->mm1_base +
- (M32_PCI_SIZE / PHB3_MAX_PE_NUM) * index;
-
- /* Update prefer address */
- if (!prefer) {
- prefer = GETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, base);
- prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_MMIO, 0x0ul, prefer);
- }
+ bus_no = (bdfn >> 8);
+ if (prefer == 0xffffull)
+ prefer = SETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, 0x0ull, bus_no);
- /* The input address matches ? */
- if (address >= base &&
- address < base + M32_PCI_SIZE / PHB3_MAX_PE_NUM) {
- addr = address;
- break;
- }
- }
+ /* Address should no greater than max bus
+ * number within PE
+ */
+ if ((GETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, addr) == bus_no)) {
+ a = addr;
+ break;
}
+ }
- /* Need amend the address ? */
- if (!addr) {
- if (!prefer)
- return OPAL_PARAMETER;
- addr = prefer;
- msk = PHB_PAPR_ERR_INJ_MASK_MMIO_MASK;
- } else {
- msk = mask;
- }
+ /* Invalid PE number */
+ if (prefer == 0xffffull)
+ return OPAL_PARAMETER;
- break;
- case OpalEjtIoaLoadConfigAddr:
- case OpalEjtIoaLoadConfigData:
- case OpalEjtIoaStoreConfigAddr:
- case OpalEjtIoaStoreConfigData:
- ctl |= PHB_PAPR_ERR_INJ_CTL_CFG;
- if (function == OpalEjtIoaLoadConfigAddr ||
- function == OpalEjtIoaLoadConfigData)
- ctl |= PHB_PAPR_ERR_INJ_CTL_RD;
- else
- ctl |= PHB_PAPR_ERR_INJ_CTL_WR;
-
- addr = 0x0ul;
- prefer = 0x0ul;
- for (index = 0; index < RTT_TABLE_ENTRIES; index++) {
- if (p->rte_cache[index] == pe_no) {
- /*
- * Select minimal bus number as PE
- * primary bus number
- */
- if (!prefer)
- prefer = index >> 8;
- else if (prefer > (index >> 8))
- prefer = index >> 8;
-
- /*
- * Address should no greater than max bus
- * number within PE
- */
- if ((GETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG,
- address) <= (index >> 8)))
- bus_valid = true;
- }
- }
+ /* Specified address is out of range */
+ if (a == 0xffffull) {
+ a = prefer;
+ m = PHB_PAPR_ERR_INJ_MASK_CFG_MASK;
+ } else {
+ m = mask;
+ }
- /* Check if address is in a reasonable region */
- if (GETFIELD(PHB_PAPR_ERR_INJ_MASK_CFG, address) >= prefer
- && bus_valid)
- addr = address;
+ return phb3_err_inject_finalize(p, a, m, ctrl, is_write);
+}
- if (!addr) {
- if (!prefer)
- return OPAL_PARAMETER;
- addr = prefer;
- msk = PHB_PAPR_ERR_INJ_MASK_CFG_MASK;
- } else {
- msk = mask;
- }
+static int64_t phb3_err_inject(struct phb *phb, uint32_t pe_no,
+ uint32_t type, uint32_t func,
+ uint64_t addr, uint64_t mask)
+{
+ struct phb3 *p = phb_to_phb3(phb);
+ int64_t (*handler)(struct phb3 *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask, bool is_write);
+ bool is_write;
+ /* To support 64-bits error injection later */
+ if (type == OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64)
+ return OPAL_UNSUPPORTED;
+
+ /* How could we get here without valid RTT? */
+ if (!p->tbl_rtt)
+ return OPAL_HARDWARE;
+
+ /* We can't inject error to the reserved PE#0 */
+ if (pe_no == 0x0 || pe_no >= PHB3_MAX_PE_NUM)
+ return OPAL_PARAMETER;
+
+ /* Clear leftover from last time */
+ out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, 0x0ul);
+
+ switch (func) {
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_DATA:
+ is_write = false;
+ handler = phb3_err_inject_mem32;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_DATA:
+ is_write = true;
+ handler = phb3_err_inject_mem32;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_DATA:
+ is_write = false;
+ handler = phb3_err_inject_cfg;
+ break;
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_ADDR:
+ case OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_DATA:
+ is_write = true;
+ handler = phb3_err_inject_cfg;
break;
default:
- return OPAL_UNSUPPORTED;
+ return OPAL_PARAMETER;
}
- out_be64(p->regs + PHB_PAPR_ERR_INJ_CTL, ctl);
- out_be64(p->regs + PHB_PAPR_ERR_INJ_ADDR, addr);
- out_be64(p->regs + PHB_PAPR_ERR_INJ_MASK, msk);
-
- return OPAL_SUCCESS;
+ return handler(p, pe_no, addr, mask, is_write);
}
static int64_t phb3_get_diag_data(struct phb *phb,
@@ -3130,7 +3144,7 @@ static const struct phb_ops phb3_ops = {
.eeh_freeze_clear = phb3_eeh_freeze_clear,
.eeh_freeze_set = phb3_eeh_freeze_set,
.next_error = phb3_eeh_next_error,
- .err_injct = phb3_err_injct,
+ .err_inject = phb3_err_inject,
.get_diag_data = NULL,
.get_diag_data2 = phb3_get_diag_data,
.set_capi_mode = phb3_set_capi_mode,
diff --git a/include/opal.h b/include/opal.h
index fb0cee4..acb2bb5 100644
--- a/include/opal.h
+++ b/include/opal.h
@@ -131,7 +131,7 @@
#define OPAL_PCI_SET_PHB_CAPI_MODE 93
#define OPAL_DUMP_INFO2 94
#define OPAL_WRITE_OPPANEL_ASYNC 95
-#define OPAL_PCI_ERR_INJCT 96
+#define OPAL_PCI_ERR_INJECT 96
#define OPAL_PCI_EEH_FREEZE_SET 97
#define OPAL_HANDLE_HMI 98
#define OPAL_CONFIG_CPU_IDLE_STATE 99
@@ -191,31 +191,33 @@ enum OpalPciErrorSeverity {
OPAL_EEH_SEV_INF = 5
};
-enum OpalErrinjctType {
- OpalErrinjctTypeIoaBusError = 0,
- OpalErrinjctTypeIoaBusError64 = 1,
-
- /* IoaBusError & IoaBusError64 */
- OpalEjtIoaLoadMemAddr = 0,
- OpalEjtIoaLoadMemData = 1,
- OpalEjtIoaLoadIoAddr = 2,
- OpalEjtIoaLoadIoData = 3,
- OpalEjtIoaLoadConfigAddr = 4,
- OpalEjtIoaLoadConfigData = 5,
- OpalEjtIoaStoreMemAddr = 6,
- OpalEjtIoaStoreMemData = 7,
- OpalEjtIoaStoreIoAddr = 8,
- OpalEjtIoaStoreIoData = 9,
- OpalEjtIoaStoreConfigAddr = 10,
- OpalEjtIoaStoreConfigData = 11,
- OpalEjtIoaDmaReadMemAddr = 12,
- OpalEjtIoaDmaReadMemData = 13,
- OpalEjtIoaDmaReadMemMaster = 14,
- OpalEjtIoaDmaReadMemTarget = 15,
- OpalEjtIoaDmaWriteMemAddr = 16,
- OpalEjtIoaDmaWriteMemData = 17,
- OpalEjtIoaDmaWriteMemMaster = 18,
- OpalEjtIoaDmaWriteMemTarget = 19,
+enum OpalErrinjectType {
+ OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR = 0,
+ OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64 = 1,
+};
+
+enum OpalErrinjectFunc {
+ /* IOA bus specific errors */
+ OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_ADDR = 0,
+ OPAL_ERR_INJECT_FUNC_IOA_LD_MEM_DATA = 1,
+ OPAL_ERR_INJECT_FUNC_IOA_LD_IO_ADDR = 2,
+ OPAL_ERR_INJECT_FUNC_IOA_LD_IO_DATA = 3,
+ OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_ADDR = 4,
+ OPAL_ERR_INJECT_FUNC_IOA_LD_CFG_DATA = 5,
+ OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_ADDR = 6,
+ OPAL_ERR_INJECT_FUNC_IOA_ST_MEM_DATA = 7,
+ OPAL_ERR_INJECT_FUNC_IOA_ST_IO_ADDR = 8,
+ OPAL_ERR_INJECT_FUNC_IOA_ST_IO_DATA = 9,
+ OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_ADDR = 10,
+ OPAL_ERR_INJECT_FUNC_IOA_ST_CFG_DATA = 11,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_ADDR = 12,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_DATA = 13,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_MASTER = 14,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_RD_TARGET = 15,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_ADDR = 16,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_DATA = 17,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_MASTER = 18,
+ OPAL_ERR_INJECT_FUNC_IOA_DMA_WR_TARGET = 19,
};
enum OpalShpcAction {
diff --git a/include/pci.h b/include/pci.h
index c15935c..9573961 100644
--- a/include/pci.h
+++ b/include/pci.h
@@ -257,8 +257,8 @@ struct phb_ops {
uint64_t eeh_action_token);
int64_t (*eeh_freeze_set)(struct phb *phb, uint64_t pe_number,
uint64_t eeh_action_token);
- int64_t (*err_injct)(struct phb *phb, uint32_t pe_no, uint32_t type,
- uint32_t function, uint64_t addr, uint64_t mask);
+ int64_t (*err_inject)(struct phb *phb, uint32_t pe_no, uint32_t type,
+ uint32_t func, uint64_t addr, uint64_t mask);
int64_t (*get_diag_data)(struct phb *phb, void *diag_buffer,
uint64_t diag_buffer_len);
int64_t (*get_diag_data2)(struct phb *phb, void *diag_buffer,