diff options
-rw-r--r-- | core/pci-opal.c | 17 | ||||
-rw-r--r-- | hw/p7ioc-phb.c | 427 | ||||
-rw-r--r-- | hw/phb3.c | 260 | ||||
-rw-r--r-- | include/opal.h | 54 | ||||
-rw-r--r-- | include/pci.h | 4 |
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, @@ -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, |