aboutsummaryrefslogtreecommitdiff
path: root/hw/p7ioc-phb.c
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 /hw/p7ioc-phb.c
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>
Diffstat (limited to 'hw/p7ioc-phb.c')
-rw-r--r--hw/p7ioc-phb.c427
1 files changed, 226 insertions, 201 deletions
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,