diff options
Diffstat (limited to 'drivers/edac/xgene_edac.c')
-rw-r--r-- | drivers/edac/xgene_edac.c | 70 |
1 files changed, 69 insertions, 1 deletions
diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c index 41f876414a18..bf19b6e3bd12 100644 --- a/drivers/edac/xgene_edac.c +++ b/drivers/edac/xgene_edac.c | |||
@@ -61,6 +61,7 @@ struct xgene_edac { | |||
61 | struct regmap *mcba_map; | 61 | struct regmap *mcba_map; |
62 | struct regmap *mcbb_map; | 62 | struct regmap *mcbb_map; |
63 | struct regmap *efuse_map; | 63 | struct regmap *efuse_map; |
64 | struct regmap *rb_map; | ||
64 | void __iomem *pcp_csr; | 65 | void __iomem *pcp_csr; |
65 | spinlock_t lock; | 66 | spinlock_t lock; |
66 | struct dentry *dfs; | 67 | struct dentry *dfs; |
@@ -1057,7 +1058,7 @@ static bool xgene_edac_l3_promote_to_uc_err(u32 l3cesr, u32 l3celr) | |||
1057 | case 0x041: | 1058 | case 0x041: |
1058 | return true; | 1059 | return true; |
1059 | } | 1060 | } |
1060 | } else if (L3C_ELR_ERRSYN(l3celr) == 9) | 1061 | } else if (L3C_ELR_ERRWAY(l3celr) == 9) |
1061 | return true; | 1062 | return true; |
1062 | 1063 | ||
1063 | return false; | 1064 | return false; |
@@ -1353,6 +1354,17 @@ static int xgene_edac_l3_remove(struct xgene_edac_dev_ctx *l3) | |||
1353 | #define GLBL_MDED_ERRH 0x0848 | 1354 | #define GLBL_MDED_ERRH 0x0848 |
1354 | #define GLBL_MDED_ERRHMASK 0x084c | 1355 | #define GLBL_MDED_ERRHMASK 0x084c |
1355 | 1356 | ||
1357 | /* IO Bus Registers */ | ||
1358 | #define RBCSR 0x0000 | ||
1359 | #define STICKYERR_MASK BIT(0) | ||
1360 | #define RBEIR 0x0008 | ||
1361 | #define AGENT_OFFLINE_ERR_MASK BIT(30) | ||
1362 | #define UNIMPL_RBPAGE_ERR_MASK BIT(29) | ||
1363 | #define WORD_ALIGNED_ERR_MASK BIT(28) | ||
1364 | #define PAGE_ACCESS_ERR_MASK BIT(27) | ||
1365 | #define WRITE_ACCESS_MASK BIT(26) | ||
1366 | #define RBERRADDR_RD(src) ((src) & 0x03FFFFFF) | ||
1367 | |||
1356 | static const char * const soc_mem_err_v1[] = { | 1368 | static const char * const soc_mem_err_v1[] = { |
1357 | "10GbE0", | 1369 | "10GbE0", |
1358 | "10GbE1", | 1370 | "10GbE1", |
@@ -1470,6 +1482,51 @@ static void xgene_edac_rb_report(struct edac_device_ctl_info *edac_dev) | |||
1470 | u32 err_addr_hi; | 1482 | u32 err_addr_hi; |
1471 | u32 reg; | 1483 | u32 reg; |
1472 | 1484 | ||
1485 | /* If the register bus resource isn't available, just skip it */ | ||
1486 | if (!ctx->edac->rb_map) | ||
1487 | goto rb_skip; | ||
1488 | |||
1489 | /* | ||
1490 | * Check RB access errors | ||
1491 | * 1. Out of range | ||
1492 | * 2. Un-implemented page | ||
1493 | * 3. Un-aligned access | ||
1494 | * 4. Offline slave IP | ||
1495 | */ | ||
1496 | if (regmap_read(ctx->edac->rb_map, RBCSR, ®)) | ||
1497 | return; | ||
1498 | if (reg & STICKYERR_MASK) { | ||
1499 | bool write; | ||
1500 | u32 address; | ||
1501 | |||
1502 | dev_err(edac_dev->dev, "IOB bus access error(s)\n"); | ||
1503 | if (regmap_read(ctx->edac->rb_map, RBEIR, ®)) | ||
1504 | return; | ||
1505 | write = reg & WRITE_ACCESS_MASK ? 1 : 0; | ||
1506 | address = RBERRADDR_RD(reg); | ||
1507 | if (reg & AGENT_OFFLINE_ERR_MASK) | ||
1508 | dev_err(edac_dev->dev, | ||
1509 | "IOB bus %s access to offline agent error\n", | ||
1510 | write ? "write" : "read"); | ||
1511 | if (reg & UNIMPL_RBPAGE_ERR_MASK) | ||
1512 | dev_err(edac_dev->dev, | ||
1513 | "IOB bus %s access to unimplemented page error\n", | ||
1514 | write ? "write" : "read"); | ||
1515 | if (reg & WORD_ALIGNED_ERR_MASK) | ||
1516 | dev_err(edac_dev->dev, | ||
1517 | "IOB bus %s word aligned access error\n", | ||
1518 | write ? "write" : "read"); | ||
1519 | if (reg & PAGE_ACCESS_ERR_MASK) | ||
1520 | dev_err(edac_dev->dev, | ||
1521 | "IOB bus %s to page out of range access error\n", | ||
1522 | write ? "write" : "read"); | ||
1523 | if (regmap_write(ctx->edac->rb_map, RBEIR, 0)) | ||
1524 | return; | ||
1525 | if (regmap_write(ctx->edac->rb_map, RBCSR, 0)) | ||
1526 | return; | ||
1527 | } | ||
1528 | rb_skip: | ||
1529 | |||
1473 | /* IOB Bridge agent transaction error interrupt */ | 1530 | /* IOB Bridge agent transaction error interrupt */ |
1474 | reg = readl(ctx->dev_csr + IOBBATRANSERRINTSTS); | 1531 | reg = readl(ctx->dev_csr + IOBBATRANSERRINTSTS); |
1475 | if (!reg) | 1532 | if (!reg) |
@@ -1852,6 +1909,17 @@ static int xgene_edac_probe(struct platform_device *pdev) | |||
1852 | goto out_err; | 1909 | goto out_err; |
1853 | } | 1910 | } |
1854 | 1911 | ||
1912 | /* | ||
1913 | * NOTE: The register bus resource is optional for compatibility | ||
1914 | * reason. | ||
1915 | */ | ||
1916 | edac->rb_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node, | ||
1917 | "regmap-rb"); | ||
1918 | if (IS_ERR(edac->rb_map)) { | ||
1919 | dev_warn(edac->dev, "missing syscon regmap rb\n"); | ||
1920 | edac->rb_map = NULL; | ||
1921 | } | ||
1922 | |||
1855 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1923 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1856 | edac->pcp_csr = devm_ioremap_resource(&pdev->dev, res); | 1924 | edac->pcp_csr = devm_ioremap_resource(&pdev->dev, res); |
1857 | if (IS_ERR(edac->pcp_csr)) { | 1925 | if (IS_ERR(edac->pcp_csr)) { |