EDAC, xgene: Add missing SoC register bus error handling

Add missing register bus error handling for APM X-Gene EDAC SoC and fix
a checking condition for CE error promoted to UE.

Signed-off-by: Loc Ho <lho@apm.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-edac <linux-edac@vger.kernel.org>
Cc: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
Cc: patches@apm.com
Link: http://lkml.kernel.org/r/1453495625-28006-3-git-send-email-lho@apm.com
Signed-off-by: Borislav Petkov <bp@suse.de>
This commit is contained in:
Loc Ho 2016-01-22 13:47:04 -07:00 committed by Borislav Petkov
parent 5979b84dc1
commit 4d67e3ce75
1 changed files with 69 additions and 1 deletions

View File

@ -61,6 +61,7 @@ struct xgene_edac {
struct regmap *mcba_map;
struct regmap *mcbb_map;
struct regmap *efuse_map;
struct regmap *rb_map;
void __iomem *pcp_csr;
spinlock_t lock;
struct dentry *dfs;
@ -1057,7 +1058,7 @@ static bool xgene_edac_l3_promote_to_uc_err(u32 l3cesr, u32 l3celr)
case 0x041:
return true;
}
} else if (L3C_ELR_ERRSYN(l3celr) == 9)
} else if (L3C_ELR_ERRWAY(l3celr) == 9)
return true;
return false;
@ -1353,6 +1354,17 @@ static int xgene_edac_l3_remove(struct xgene_edac_dev_ctx *l3)
#define GLBL_MDED_ERRH 0x0848
#define GLBL_MDED_ERRHMASK 0x084c
/* IO Bus Registers */
#define RBCSR 0x0000
#define STICKYERR_MASK BIT(0)
#define RBEIR 0x0008
#define AGENT_OFFLINE_ERR_MASK BIT(30)
#define UNIMPL_RBPAGE_ERR_MASK BIT(29)
#define WORD_ALIGNED_ERR_MASK BIT(28)
#define PAGE_ACCESS_ERR_MASK BIT(27)
#define WRITE_ACCESS_MASK BIT(26)
#define RBERRADDR_RD(src) ((src) & 0x03FFFFFF)
static const char * const soc_mem_err_v1[] = {
"10GbE0",
"10GbE1",
@ -1470,6 +1482,51 @@ static void xgene_edac_rb_report(struct edac_device_ctl_info *edac_dev)
u32 err_addr_hi;
u32 reg;
/* If the register bus resource isn't available, just skip it */
if (!ctx->edac->rb_map)
goto rb_skip;
/*
* Check RB access errors
* 1. Out of range
* 2. Un-implemented page
* 3. Un-aligned access
* 4. Offline slave IP
*/
if (regmap_read(ctx->edac->rb_map, RBCSR, &reg))
return;
if (reg & STICKYERR_MASK) {
bool write;
u32 address;
dev_err(edac_dev->dev, "IOB bus access error(s)\n");
if (regmap_read(ctx->edac->rb_map, RBEIR, &reg))
return;
write = reg & WRITE_ACCESS_MASK ? 1 : 0;
address = RBERRADDR_RD(reg);
if (reg & AGENT_OFFLINE_ERR_MASK)
dev_err(edac_dev->dev,
"IOB bus %s access to offline agent error\n",
write ? "write" : "read");
if (reg & UNIMPL_RBPAGE_ERR_MASK)
dev_err(edac_dev->dev,
"IOB bus %s access to unimplemented page error\n",
write ? "write" : "read");
if (reg & WORD_ALIGNED_ERR_MASK)
dev_err(edac_dev->dev,
"IOB bus %s word aligned access error\n",
write ? "write" : "read");
if (reg & PAGE_ACCESS_ERR_MASK)
dev_err(edac_dev->dev,
"IOB bus %s to page out of range access error\n",
write ? "write" : "read");
if (regmap_write(ctx->edac->rb_map, RBEIR, 0))
return;
if (regmap_write(ctx->edac->rb_map, RBCSR, 0))
return;
}
rb_skip:
/* IOB Bridge agent transaction error interrupt */
reg = readl(ctx->dev_csr + IOBBATRANSERRINTSTS);
if (!reg)
@ -1852,6 +1909,17 @@ static int xgene_edac_probe(struct platform_device *pdev)
goto out_err;
}
/*
* NOTE: The register bus resource is optional for compatibility
* reason.
*/
edac->rb_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
"regmap-rb");
if (IS_ERR(edac->rb_map)) {
dev_warn(edac->dev, "missing syscon regmap rb\n");
edac->rb_map = NULL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
edac->pcp_csr = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(edac->pcp_csr)) {