aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGavin Shan <gwshan@linux.vnet.ibm.com>2014-10-02 16:30:14 +1000
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2014-10-08 14:07:46 +1100
commit266b47c446d5fda1b7263fe15cfeb399863f2a3f (patch)
tree7f5b6a640b0caf72adfac59cd73b96f213332b5b
parentc7e777f83513b74ebc53f9c37aa817caa7ec089d (diff)
downloadskiboot-266b47c446d5fda1b7263fe15cfeb399863f2a3f.zip
skiboot-266b47c446d5fda1b7263fe15cfeb399863f2a3f.tar.gz
skiboot-266b47c446d5fda1b7263fe15cfeb399863f2a3f.tar.bz2
PHB3: Support DMA error injection
The patch enables injecting PCI errors to DMA address address, including 32-bits and 64-bits ranges. BZ: 115222 Signed-off-by: Gavin Shan <gwshan@linux.vnet.ibm.com> Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
-rw-r--r--hw/phb3.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/hw/phb3.c b/hw/phb3.c
index 9b6b4f8..24a3b8e 100644
--- a/hw/phb3.c
+++ b/hw/phb3.c
@@ -2782,6 +2782,84 @@ static int64_t phb3_err_inject_cfg(struct phb3 *p, uint32_t pe_no,
return phb3_err_inject_finalize(p, a, m, ctrl, is_write);
}
+static int64_t phb3_err_inject_dma(struct phb3 *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write, bool is_64bits)
+{
+ uint32_t index, page_size;
+ uint64_t tve, table_entries;
+ uint64_t base, start, end, len, a, m;
+ uint64_t ctrl = PHB_PAPR_ERR_INJ_CTL_INB;
+
+ /* TVE index and base address */
+ if (!is_64bits) {
+ index = (pe_no << 1);
+ base = 0x0ull;
+ } else {
+ index = ((pe_no << 1) + 1);
+ base = (0x1ull << 59);
+ }
+
+ /* Raw data of table entries and page size */
+ tve = p->tve_cache[index];
+ table_entries = GETFIELD(IODA2_TVT_TCE_TABLE_SIZE, tve);
+ table_entries = (0x1ull << (table_entries + 8));
+ page_size = GETFIELD(IODA2_TVT_IO_PSIZE, tve);
+ if (!page_size && !(tve & PPC_BIT(51)))
+ return OPAL_UNSUPPORTED;
+
+ /* Check the page size */
+ switch (page_size) {
+ case 0: /* bypass */
+ start = ((tve & (0x3ull << 10)) << 14) |
+ ((tve & (0xffffffull << 40)) >> 40);
+ end = ((tve & (0x3ull << 8)) << 16) |
+ ((tve & (0xffffffull << 16)) >> 16);
+
+ /* 16MB aligned size */
+ len = (end - start) << 24;
+ break;
+ case 5: /* 64KB */
+ len = table_entries * 0x10000ull;
+ break;
+ case 13: /* 16MB */
+ len = table_entries * 0x1000000ull;
+ break;
+ case 17: /* 256MB */
+ len = table_entries * 0x10000000ull;
+ break;
+ case 1: /* 4KB */
+ default:
+ len = table_entries * 0x1000ull;
+ }
+
+ /* The specified address is in range */
+ if (addr && addr >= base && addr < (base + len)) {
+ a = addr;
+ m = mask;
+ } else {
+ a = base;
+ len = len & ~(len - 1);
+ m = ~(len - 1);
+ }
+
+ return phb3_err_inject_finalize(p, a, m, ctrl, is_write);
+}
+
+static int64_t phb3_err_inject_dma32(struct phb3 *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ return phb3_err_inject_dma(p, pe_no, addr, mask, is_write, false);
+}
+
+static int64_t phb3_err_inject_dma64(struct phb3 *p, uint32_t pe_no,
+ uint64_t addr, uint64_t mask,
+ bool is_write)
+{
+ return phb3_err_inject_dma(p, pe_no, addr, mask, is_write, true);
+}
+
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)
@@ -2829,6 +2907,26 @@ static int64_t phb3_err_inject(struct phb *phb, uint32_t pe_no,
is_write = true;
handler = phb3_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;
+ if (type == OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64)
+ handler = phb3_err_inject_dma64;
+ else
+ handler = phb3_err_inject_dma32;
+ 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;
+ if (type == OPAL_ERR_INJECT_TYPE_IOA_BUS_ERR64)
+ handler = phb3_err_inject_dma64;
+ else
+ handler = phb3_err_inject_dma32;
+ break;
default:
return OPAL_PARAMETER;
}