xref: /openbmc/linux/drivers/edac/xgene_edac.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
11ccea77eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
20d442930SLoc Ho /*
30d442930SLoc Ho  * APM X-Gene SoC EDAC (error detection and correction)
40d442930SLoc Ho  *
50d442930SLoc Ho  * Copyright (c) 2015, Applied Micro Circuits Corporation
60d442930SLoc Ho  * Author: Feng Kan <fkan@apm.com>
70d442930SLoc Ho  *         Loc Ho <lho@apm.com>
80d442930SLoc Ho  */
90d442930SLoc Ho 
100d442930SLoc Ho #include <linux/ctype.h>
110d442930SLoc Ho #include <linux/edac.h>
120d442930SLoc Ho #include <linux/interrupt.h>
130d442930SLoc Ho #include <linux/mfd/syscon.h>
140d442930SLoc Ho #include <linux/module.h>
150d442930SLoc Ho #include <linux/of.h>
160d442930SLoc Ho #include <linux/of_address.h>
170d442930SLoc Ho #include <linux/regmap.h>
180d442930SLoc Ho 
1909bd1b4fSBorislav Petkov #include "edac_module.h"
200d442930SLoc Ho 
210d442930SLoc Ho #define EDAC_MOD_STR			"xgene_edac"
220d442930SLoc Ho 
230d442930SLoc Ho /* Global error configuration status registers (CSR) */
240d442930SLoc Ho #define PCPHPERRINTSTS			0x0000
250d442930SLoc Ho #define PCPHPERRINTMSK			0x0004
260d442930SLoc Ho #define  MCU_CTL_ERR_MASK		BIT(12)
270d442930SLoc Ho #define  IOB_PA_ERR_MASK		BIT(11)
280d442930SLoc Ho #define  IOB_BA_ERR_MASK		BIT(10)
290d442930SLoc Ho #define  IOB_XGIC_ERR_MASK		BIT(9)
300d442930SLoc Ho #define  IOB_RB_ERR_MASK		BIT(8)
310d442930SLoc Ho #define  L3C_UNCORR_ERR_MASK		BIT(5)
320d442930SLoc Ho #define  MCU_UNCORR_ERR_MASK		BIT(4)
330d442930SLoc Ho #define  PMD3_MERR_MASK			BIT(3)
340d442930SLoc Ho #define  PMD2_MERR_MASK			BIT(2)
350d442930SLoc Ho #define  PMD1_MERR_MASK			BIT(1)
360d442930SLoc Ho #define  PMD0_MERR_MASK			BIT(0)
370d442930SLoc Ho #define PCPLPERRINTSTS			0x0008
380d442930SLoc Ho #define PCPLPERRINTMSK			0x000C
390d442930SLoc Ho #define  CSW_SWITCH_TRACE_ERR_MASK	BIT(2)
400d442930SLoc Ho #define  L3C_CORR_ERR_MASK		BIT(1)
410d442930SLoc Ho #define  MCU_CORR_ERR_MASK		BIT(0)
420d442930SLoc Ho #define MEMERRINTSTS			0x0010
430d442930SLoc Ho #define MEMERRINTMSK			0x0014
440d442930SLoc Ho 
450d442930SLoc Ho struct xgene_edac {
460d442930SLoc Ho 	struct device		*dev;
470d442930SLoc Ho 	struct regmap		*csw_map;
480d442930SLoc Ho 	struct regmap		*mcba_map;
490d442930SLoc Ho 	struct regmap		*mcbb_map;
500d442930SLoc Ho 	struct regmap		*efuse_map;
514d67e3ceSLoc Ho 	struct regmap		*rb_map;
520d442930SLoc Ho 	void __iomem		*pcp_csr;
530d442930SLoc Ho 	spinlock_t		lock;
540d442930SLoc Ho 	struct dentry           *dfs;
550d442930SLoc Ho 
560d442930SLoc Ho 	struct list_head	mcus;
570d442930SLoc Ho 	struct list_head	pmds;
589347473cSLoc Ho 	struct list_head	l3s;
59f864b79bSLoc Ho 	struct list_head	socs;
600d442930SLoc Ho 
610d442930SLoc Ho 	struct mutex		mc_lock;
620d442930SLoc Ho 	int			mc_active_mask;
630d442930SLoc Ho 	int			mc_registered_mask;
640d442930SLoc Ho };
650d442930SLoc Ho 
xgene_edac_pcp_rd(struct xgene_edac * edac,u32 reg,u32 * val)660d442930SLoc Ho static void xgene_edac_pcp_rd(struct xgene_edac *edac, u32 reg, u32 *val)
670d442930SLoc Ho {
680d442930SLoc Ho 	*val = readl(edac->pcp_csr + reg);
690d442930SLoc Ho }
700d442930SLoc Ho 
xgene_edac_pcp_clrbits(struct xgene_edac * edac,u32 reg,u32 bits_mask)710d442930SLoc Ho static void xgene_edac_pcp_clrbits(struct xgene_edac *edac, u32 reg,
720d442930SLoc Ho 				   u32 bits_mask)
730d442930SLoc Ho {
740d442930SLoc Ho 	u32 val;
750d442930SLoc Ho 
760d442930SLoc Ho 	spin_lock(&edac->lock);
770d442930SLoc Ho 	val = readl(edac->pcp_csr + reg);
780d442930SLoc Ho 	val &= ~bits_mask;
790d442930SLoc Ho 	writel(val, edac->pcp_csr + reg);
800d442930SLoc Ho 	spin_unlock(&edac->lock);
810d442930SLoc Ho }
820d442930SLoc Ho 
xgene_edac_pcp_setbits(struct xgene_edac * edac,u32 reg,u32 bits_mask)830d442930SLoc Ho static void xgene_edac_pcp_setbits(struct xgene_edac *edac, u32 reg,
840d442930SLoc Ho 				   u32 bits_mask)
850d442930SLoc Ho {
860d442930SLoc Ho 	u32 val;
870d442930SLoc Ho 
880d442930SLoc Ho 	spin_lock(&edac->lock);
890d442930SLoc Ho 	val = readl(edac->pcp_csr + reg);
900d442930SLoc Ho 	val |= bits_mask;
910d442930SLoc Ho 	writel(val, edac->pcp_csr + reg);
920d442930SLoc Ho 	spin_unlock(&edac->lock);
930d442930SLoc Ho }
940d442930SLoc Ho 
950d442930SLoc Ho /* Memory controller error CSR */
960d442930SLoc Ho #define MCU_MAX_RANK			8
970d442930SLoc Ho #define MCU_RANK_STRIDE			0x40
980d442930SLoc Ho 
990d442930SLoc Ho #define MCUGECR				0x0110
1000d442930SLoc Ho #define  MCU_GECR_DEMANDUCINTREN_MASK	BIT(0)
1010d442930SLoc Ho #define  MCU_GECR_BACKUCINTREN_MASK	BIT(1)
1020d442930SLoc Ho #define  MCU_GECR_CINTREN_MASK		BIT(2)
1030d442930SLoc Ho #define  MUC_GECR_MCUADDRERREN_MASK	BIT(9)
1040d442930SLoc Ho #define MCUGESR				0x0114
1050d442930SLoc Ho #define  MCU_GESR_ADDRNOMATCH_ERR_MASK	BIT(7)
1060d442930SLoc Ho #define  MCU_GESR_ADDRMULTIMATCH_ERR_MASK	BIT(6)
1070d442930SLoc Ho #define  MCU_GESR_PHYP_ERR_MASK		BIT(3)
1080d442930SLoc Ho #define MCUESRR0			0x0314
1090d442930SLoc Ho #define  MCU_ESRR_MULTUCERR_MASK	BIT(3)
1100d442930SLoc Ho #define  MCU_ESRR_BACKUCERR_MASK	BIT(2)
1110d442930SLoc Ho #define  MCU_ESRR_DEMANDUCERR_MASK	BIT(1)
1120d442930SLoc Ho #define  MCU_ESRR_CERR_MASK		BIT(0)
1130d442930SLoc Ho #define MCUESRRA0			0x0318
1140d442930SLoc Ho #define MCUEBLRR0			0x031c
1150d442930SLoc Ho #define  MCU_EBLRR_ERRBANK_RD(src)	(((src) & 0x00000007) >> 0)
1160d442930SLoc Ho #define MCUERCRR0			0x0320
1170d442930SLoc Ho #define  MCU_ERCRR_ERRROW_RD(src)	(((src) & 0xFFFF0000) >> 16)
1180d442930SLoc Ho #define  MCU_ERCRR_ERRCOL_RD(src)	((src) & 0x00000FFF)
1190d442930SLoc Ho #define MCUSBECNT0			0x0324
1200d442930SLoc Ho #define MCU_SBECNT_COUNT(src)		((src) & 0xFFFF)
1210d442930SLoc Ho 
1220d442930SLoc Ho #define CSW_CSWCR			0x0000
1230d442930SLoc Ho #define  CSW_CSWCR_DUALMCB_MASK		BIT(0)
1240d442930SLoc Ho 
1250d442930SLoc Ho #define MCBADDRMR			0x0000
1260d442930SLoc Ho #define  MCBADDRMR_MCU_INTLV_MODE_MASK	BIT(3)
1270d442930SLoc Ho #define  MCBADDRMR_DUALMCU_MODE_MASK	BIT(2)
1280d442930SLoc Ho #define  MCBADDRMR_MCB_INTLV_MODE_MASK	BIT(1)
1290d442930SLoc Ho #define  MCBADDRMR_ADDRESS_MODE_MASK	BIT(0)
1300d442930SLoc Ho 
1310d442930SLoc Ho struct xgene_edac_mc_ctx {
1320d442930SLoc Ho 	struct list_head	next;
1330d442930SLoc Ho 	char			*name;
1340d442930SLoc Ho 	struct mem_ctl_info	*mci;
1350d442930SLoc Ho 	struct xgene_edac	*edac;
1360d442930SLoc Ho 	void __iomem		*mcu_csr;
1370d442930SLoc Ho 	u32			mcu_id;
1380d442930SLoc Ho };
1390d442930SLoc Ho 
xgene_edac_mc_err_inject_write(struct file * file,const char __user * data,size_t count,loff_t * ppos)1400d442930SLoc Ho static ssize_t xgene_edac_mc_err_inject_write(struct file *file,
1410d442930SLoc Ho 					      const char __user *data,
1420d442930SLoc Ho 					      size_t count, loff_t *ppos)
1430d442930SLoc Ho {
1440d442930SLoc Ho 	struct mem_ctl_info *mci = file->private_data;
1450d442930SLoc Ho 	struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
1460d442930SLoc Ho 	int i;
1470d442930SLoc Ho 
1480d442930SLoc Ho 	for (i = 0; i < MCU_MAX_RANK; i++) {
1490d442930SLoc Ho 		writel(MCU_ESRR_MULTUCERR_MASK | MCU_ESRR_BACKUCERR_MASK |
1500d442930SLoc Ho 		       MCU_ESRR_DEMANDUCERR_MASK | MCU_ESRR_CERR_MASK,
1510d442930SLoc Ho 		       ctx->mcu_csr + MCUESRRA0 + i * MCU_RANK_STRIDE);
1520d442930SLoc Ho 	}
1530d442930SLoc Ho 	return count;
1540d442930SLoc Ho }
1550d442930SLoc Ho 
1560d442930SLoc Ho static const struct file_operations xgene_edac_mc_debug_inject_fops = {
1570d442930SLoc Ho 	.open = simple_open,
1580d442930SLoc Ho 	.write = xgene_edac_mc_err_inject_write,
1590d442930SLoc Ho 	.llseek = generic_file_llseek,
1600d442930SLoc Ho };
1610d442930SLoc Ho 
xgene_edac_mc_create_debugfs_node(struct mem_ctl_info * mci)1620d442930SLoc Ho static void xgene_edac_mc_create_debugfs_node(struct mem_ctl_info *mci)
1630d442930SLoc Ho {
1640d442930SLoc Ho 	if (!IS_ENABLED(CONFIG_EDAC_DEBUG))
1650d442930SLoc Ho 		return;
16609bd1b4fSBorislav Petkov 
1670d442930SLoc Ho 	if (!mci->debugfs)
1680d442930SLoc Ho 		return;
16909bd1b4fSBorislav Petkov 
17009bd1b4fSBorislav Petkov 	edac_debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci,
1710d442930SLoc Ho 				 &xgene_edac_mc_debug_inject_fops);
1720d442930SLoc Ho }
1730d442930SLoc Ho 
xgene_edac_mc_check(struct mem_ctl_info * mci)1740d442930SLoc Ho static void xgene_edac_mc_check(struct mem_ctl_info *mci)
1750d442930SLoc Ho {
1760d442930SLoc Ho 	struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
1770d442930SLoc Ho 	unsigned int pcp_hp_stat;
1780d442930SLoc Ho 	unsigned int pcp_lp_stat;
1790d442930SLoc Ho 	u32 reg;
1800d442930SLoc Ho 	u32 rank;
1810d442930SLoc Ho 	u32 bank;
1820d442930SLoc Ho 	u32 count;
1830d442930SLoc Ho 	u32 col_row;
1840d442930SLoc Ho 
1850d442930SLoc Ho 	xgene_edac_pcp_rd(ctx->edac, PCPHPERRINTSTS, &pcp_hp_stat);
1860d442930SLoc Ho 	xgene_edac_pcp_rd(ctx->edac, PCPLPERRINTSTS, &pcp_lp_stat);
1870d442930SLoc Ho 	if (!((MCU_UNCORR_ERR_MASK & pcp_hp_stat) ||
1880d442930SLoc Ho 	      (MCU_CTL_ERR_MASK & pcp_hp_stat) ||
1890d442930SLoc Ho 	      (MCU_CORR_ERR_MASK & pcp_lp_stat)))
1900d442930SLoc Ho 		return;
1910d442930SLoc Ho 
1920d442930SLoc Ho 	for (rank = 0; rank < MCU_MAX_RANK; rank++) {
1930d442930SLoc Ho 		reg = readl(ctx->mcu_csr + MCUESRR0 + rank * MCU_RANK_STRIDE);
1940d442930SLoc Ho 
1950d442930SLoc Ho 		/* Detect uncorrectable memory error */
1960d442930SLoc Ho 		if (reg & (MCU_ESRR_DEMANDUCERR_MASK |
1970d442930SLoc Ho 			   MCU_ESRR_BACKUCERR_MASK)) {
1980d442930SLoc Ho 			/* Detected uncorrectable memory error */
1990d442930SLoc Ho 			edac_mc_chipset_printk(mci, KERN_ERR, "X-Gene",
2000d442930SLoc Ho 				"MCU uncorrectable error at rank %d\n", rank);
2010d442930SLoc Ho 
2020d442930SLoc Ho 			edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
2030d442930SLoc Ho 				1, 0, 0, 0, 0, 0, -1, mci->ctl_name, "");
2040d442930SLoc Ho 		}
2050d442930SLoc Ho 
2060d442930SLoc Ho 		/* Detect correctable memory error */
2070d442930SLoc Ho 		if (reg & MCU_ESRR_CERR_MASK) {
2080d442930SLoc Ho 			bank = readl(ctx->mcu_csr + MCUEBLRR0 +
2090d442930SLoc Ho 				     rank * MCU_RANK_STRIDE);
2100d442930SLoc Ho 			col_row = readl(ctx->mcu_csr + MCUERCRR0 +
2110d442930SLoc Ho 					rank * MCU_RANK_STRIDE);
2120d442930SLoc Ho 			count = readl(ctx->mcu_csr + MCUSBECNT0 +
2130d442930SLoc Ho 				      rank * MCU_RANK_STRIDE);
2140d442930SLoc Ho 			edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
2150d442930SLoc Ho 				"MCU correctable error at rank %d bank %d column %d row %d count %d\n",
2160d442930SLoc Ho 				rank, MCU_EBLRR_ERRBANK_RD(bank),
2170d442930SLoc Ho 				MCU_ERCRR_ERRCOL_RD(col_row),
2180d442930SLoc Ho 				MCU_ERCRR_ERRROW_RD(col_row),
2190d442930SLoc Ho 				MCU_SBECNT_COUNT(count));
2200d442930SLoc Ho 
2210d442930SLoc Ho 			edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
2220d442930SLoc Ho 				1, 0, 0, 0, 0, 0, -1, mci->ctl_name, "");
2230d442930SLoc Ho 		}
2240d442930SLoc Ho 
2250d442930SLoc Ho 		/* Clear all error registers */
2260d442930SLoc Ho 		writel(0x0, ctx->mcu_csr + MCUEBLRR0 + rank * MCU_RANK_STRIDE);
2270d442930SLoc Ho 		writel(0x0, ctx->mcu_csr + MCUERCRR0 + rank * MCU_RANK_STRIDE);
2280d442930SLoc Ho 		writel(0x0, ctx->mcu_csr + MCUSBECNT0 +
2290d442930SLoc Ho 		       rank * MCU_RANK_STRIDE);
2300d442930SLoc Ho 		writel(reg, ctx->mcu_csr + MCUESRR0 + rank * MCU_RANK_STRIDE);
2310d442930SLoc Ho 	}
2320d442930SLoc Ho 
2330d442930SLoc Ho 	/* Detect memory controller error */
2340d442930SLoc Ho 	reg = readl(ctx->mcu_csr + MCUGESR);
2350d442930SLoc Ho 	if (reg) {
2360d442930SLoc Ho 		if (reg & MCU_GESR_ADDRNOMATCH_ERR_MASK)
2370d442930SLoc Ho 			edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
2380d442930SLoc Ho 				"MCU address miss-match error\n");
2390d442930SLoc Ho 		if (reg & MCU_GESR_ADDRMULTIMATCH_ERR_MASK)
2400d442930SLoc Ho 			edac_mc_chipset_printk(mci, KERN_WARNING, "X-Gene",
2410d442930SLoc Ho 				"MCU address multi-match error\n");
2420d442930SLoc Ho 
2430d442930SLoc Ho 		writel(reg, ctx->mcu_csr + MCUGESR);
2440d442930SLoc Ho 	}
2450d442930SLoc Ho }
2460d442930SLoc Ho 
xgene_edac_mc_irq_ctl(struct mem_ctl_info * mci,bool enable)2470d442930SLoc Ho static void xgene_edac_mc_irq_ctl(struct mem_ctl_info *mci, bool enable)
2480d442930SLoc Ho {
2490d442930SLoc Ho 	struct xgene_edac_mc_ctx *ctx = mci->pvt_info;
2500d442930SLoc Ho 	unsigned int val;
2510d442930SLoc Ho 
2520d442930SLoc Ho 	if (edac_op_state != EDAC_OPSTATE_INT)
2530d442930SLoc Ho 		return;
2540d442930SLoc Ho 
2550d442930SLoc Ho 	mutex_lock(&ctx->edac->mc_lock);
2560d442930SLoc Ho 
2570d442930SLoc Ho 	/*
2580d442930SLoc Ho 	 * As there is only single bit for enable error and interrupt mask,
2590d442930SLoc Ho 	 * we must only enable top level interrupt after all MCUs are
2600d442930SLoc Ho 	 * registered. Otherwise, if there is an error and the corresponding
2610d442930SLoc Ho 	 * MCU has not registered, the interrupt will never get cleared. To
2620d442930SLoc Ho 	 * determine all MCU have registered, we will keep track of active
2630d442930SLoc Ho 	 * MCUs and registered MCUs.
2640d442930SLoc Ho 	 */
2650d442930SLoc Ho 	if (enable) {
2660d442930SLoc Ho 		/* Set registered MCU bit */
2670d442930SLoc Ho 		ctx->edac->mc_registered_mask |= 1 << ctx->mcu_id;
2680d442930SLoc Ho 
2690d442930SLoc Ho 		/* Enable interrupt after all active MCU registered */
2700d442930SLoc Ho 		if (ctx->edac->mc_registered_mask ==
2710d442930SLoc Ho 		    ctx->edac->mc_active_mask) {
2720d442930SLoc Ho 			/* Enable memory controller top level interrupt */
2730d442930SLoc Ho 			xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
2740d442930SLoc Ho 					       MCU_UNCORR_ERR_MASK |
2750d442930SLoc Ho 					       MCU_CTL_ERR_MASK);
2760d442930SLoc Ho 			xgene_edac_pcp_clrbits(ctx->edac, PCPLPERRINTMSK,
2770d442930SLoc Ho 					       MCU_CORR_ERR_MASK);
2780d442930SLoc Ho 		}
2790d442930SLoc Ho 
2800d442930SLoc Ho 		/* Enable MCU interrupt and error reporting */
2810d442930SLoc Ho 		val = readl(ctx->mcu_csr + MCUGECR);
2820d442930SLoc Ho 		val |= MCU_GECR_DEMANDUCINTREN_MASK |
2830d442930SLoc Ho 		       MCU_GECR_BACKUCINTREN_MASK |
2840d442930SLoc Ho 		       MCU_GECR_CINTREN_MASK |
2850d442930SLoc Ho 		       MUC_GECR_MCUADDRERREN_MASK;
2860d442930SLoc Ho 		writel(val, ctx->mcu_csr + MCUGECR);
2870d442930SLoc Ho 	} else {
2880d442930SLoc Ho 		/* Disable MCU interrupt */
2890d442930SLoc Ho 		val = readl(ctx->mcu_csr + MCUGECR);
2900d442930SLoc Ho 		val &= ~(MCU_GECR_DEMANDUCINTREN_MASK |
2910d442930SLoc Ho 			 MCU_GECR_BACKUCINTREN_MASK |
2920d442930SLoc Ho 			 MCU_GECR_CINTREN_MASK |
2930d442930SLoc Ho 			 MUC_GECR_MCUADDRERREN_MASK);
2940d442930SLoc Ho 		writel(val, ctx->mcu_csr + MCUGECR);
2950d442930SLoc Ho 
2960d442930SLoc Ho 		/* Disable memory controller top level interrupt */
2970d442930SLoc Ho 		xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
2980d442930SLoc Ho 				       MCU_UNCORR_ERR_MASK | MCU_CTL_ERR_MASK);
2990d442930SLoc Ho 		xgene_edac_pcp_setbits(ctx->edac, PCPLPERRINTMSK,
3000d442930SLoc Ho 				       MCU_CORR_ERR_MASK);
3010d442930SLoc Ho 
3020d442930SLoc Ho 		/* Clear registered MCU bit */
3030d442930SLoc Ho 		ctx->edac->mc_registered_mask &= ~(1 << ctx->mcu_id);
3040d442930SLoc Ho 	}
3050d442930SLoc Ho 
3060d442930SLoc Ho 	mutex_unlock(&ctx->edac->mc_lock);
3070d442930SLoc Ho }
3080d442930SLoc Ho 
xgene_edac_mc_is_active(struct xgene_edac_mc_ctx * ctx,int mc_idx)3090d442930SLoc Ho static int xgene_edac_mc_is_active(struct xgene_edac_mc_ctx *ctx, int mc_idx)
3100d442930SLoc Ho {
3110d442930SLoc Ho 	unsigned int reg;
3120d442930SLoc Ho 	u32 mcu_mask;
3130d442930SLoc Ho 
3140d442930SLoc Ho 	if (regmap_read(ctx->edac->csw_map, CSW_CSWCR, &reg))
3150d442930SLoc Ho 		return 0;
3160d442930SLoc Ho 
3170d442930SLoc Ho 	if (reg & CSW_CSWCR_DUALMCB_MASK) {
3180d442930SLoc Ho 		/*
3190d442930SLoc Ho 		 * Dual MCB active - Determine if all 4 active or just MCU0
3200d442930SLoc Ho 		 * and MCU2 active
3210d442930SLoc Ho 		 */
3220d442930SLoc Ho 		if (regmap_read(ctx->edac->mcbb_map, MCBADDRMR, &reg))
3230d442930SLoc Ho 			return 0;
3240d442930SLoc Ho 		mcu_mask = (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0xF : 0x5;
3250d442930SLoc Ho 	} else {
3260d442930SLoc Ho 		/*
3270d442930SLoc Ho 		 * Single MCB active - Determine if MCU0/MCU1 or just MCU0
3280d442930SLoc Ho 		 * active
3290d442930SLoc Ho 		 */
3300d442930SLoc Ho 		if (regmap_read(ctx->edac->mcba_map, MCBADDRMR, &reg))
3310d442930SLoc Ho 			return 0;
3320d442930SLoc Ho 		mcu_mask = (reg & MCBADDRMR_DUALMCU_MODE_MASK) ? 0x3 : 0x1;
3330d442930SLoc Ho 	}
3340d442930SLoc Ho 
3350d442930SLoc Ho 	/* Save active MC mask if hasn't set already */
3360d442930SLoc Ho 	if (!ctx->edac->mc_active_mask)
3370d442930SLoc Ho 		ctx->edac->mc_active_mask = mcu_mask;
3380d442930SLoc Ho 
3390d442930SLoc Ho 	return (mcu_mask & (1 << mc_idx)) ? 1 : 0;
3400d442930SLoc Ho }
3410d442930SLoc Ho 
xgene_edac_mc_add(struct xgene_edac * edac,struct device_node * np)3420d442930SLoc Ho static int xgene_edac_mc_add(struct xgene_edac *edac, struct device_node *np)
3430d442930SLoc Ho {
3440d442930SLoc Ho 	struct mem_ctl_info *mci;
3450d442930SLoc Ho 	struct edac_mc_layer layers[2];
3460d442930SLoc Ho 	struct xgene_edac_mc_ctx tmp_ctx;
3470d442930SLoc Ho 	struct xgene_edac_mc_ctx *ctx;
3480d442930SLoc Ho 	struct resource res;
3490d442930SLoc Ho 	int rc;
3500d442930SLoc Ho 
3510d442930SLoc Ho 	memset(&tmp_ctx, 0, sizeof(tmp_ctx));
3520d442930SLoc Ho 	tmp_ctx.edac = edac;
3530d442930SLoc Ho 
3540d442930SLoc Ho 	if (!devres_open_group(edac->dev, xgene_edac_mc_add, GFP_KERNEL))
3550d442930SLoc Ho 		return -ENOMEM;
3560d442930SLoc Ho 
3570d442930SLoc Ho 	rc = of_address_to_resource(np, 0, &res);
3580d442930SLoc Ho 	if (rc < 0) {
3590d442930SLoc Ho 		dev_err(edac->dev, "no MCU resource address\n");
3600d442930SLoc Ho 		goto err_group;
3610d442930SLoc Ho 	}
3620d442930SLoc Ho 	tmp_ctx.mcu_csr = devm_ioremap_resource(edac->dev, &res);
3630d442930SLoc Ho 	if (IS_ERR(tmp_ctx.mcu_csr)) {
3640d442930SLoc Ho 		dev_err(edac->dev, "unable to map MCU resource\n");
3650d442930SLoc Ho 		rc = PTR_ERR(tmp_ctx.mcu_csr);
3660d442930SLoc Ho 		goto err_group;
3670d442930SLoc Ho 	}
3680d442930SLoc Ho 
3690d442930SLoc Ho 	/* Ignore non-active MCU */
3700d442930SLoc Ho 	if (of_property_read_u32(np, "memory-controller", &tmp_ctx.mcu_id)) {
3710d442930SLoc Ho 		dev_err(edac->dev, "no memory-controller property\n");
3720d442930SLoc Ho 		rc = -ENODEV;
3730d442930SLoc Ho 		goto err_group;
3740d442930SLoc Ho 	}
3750d442930SLoc Ho 	if (!xgene_edac_mc_is_active(&tmp_ctx, tmp_ctx.mcu_id)) {
3760d442930SLoc Ho 		rc = -ENODEV;
3770d442930SLoc Ho 		goto err_group;
3780d442930SLoc Ho 	}
3790d442930SLoc Ho 
3800d442930SLoc Ho 	layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
3810d442930SLoc Ho 	layers[0].size = 4;
3820d442930SLoc Ho 	layers[0].is_virt_csrow = true;
3830d442930SLoc Ho 	layers[1].type = EDAC_MC_LAYER_CHANNEL;
3840d442930SLoc Ho 	layers[1].size = 2;
3850d442930SLoc Ho 	layers[1].is_virt_csrow = false;
3860d442930SLoc Ho 	mci = edac_mc_alloc(tmp_ctx.mcu_id, ARRAY_SIZE(layers), layers,
3870d442930SLoc Ho 			    sizeof(*ctx));
3880d442930SLoc Ho 	if (!mci) {
3890d442930SLoc Ho 		rc = -ENOMEM;
3900d442930SLoc Ho 		goto err_group;
3910d442930SLoc Ho 	}
3920d442930SLoc Ho 
3930d442930SLoc Ho 	ctx = mci->pvt_info;
3940d442930SLoc Ho 	*ctx = tmp_ctx;		/* Copy over resource value */
3950d442930SLoc Ho 	ctx->name = "xgene_edac_mc_err";
3960d442930SLoc Ho 	ctx->mci = mci;
3970d442930SLoc Ho 	mci->pdev = &mci->dev;
3980d442930SLoc Ho 	mci->ctl_name = ctx->name;
3990d442930SLoc Ho 	mci->dev_name = ctx->name;
4000d442930SLoc Ho 
4010d442930SLoc Ho 	mci->mtype_cap = MEM_FLAG_RDDR | MEM_FLAG_RDDR2 | MEM_FLAG_RDDR3 |
4020d442930SLoc Ho 			 MEM_FLAG_DDR | MEM_FLAG_DDR2 | MEM_FLAG_DDR3;
4030d442930SLoc Ho 	mci->edac_ctl_cap = EDAC_FLAG_SECDED;
4040d442930SLoc Ho 	mci->edac_cap = EDAC_FLAG_SECDED;
4050d442930SLoc Ho 	mci->mod_name = EDAC_MOD_STR;
4060d442930SLoc Ho 	mci->ctl_page_to_phys = NULL;
4070d442930SLoc Ho 	mci->scrub_cap = SCRUB_FLAG_HW_SRC;
4080d442930SLoc Ho 	mci->scrub_mode = SCRUB_HW_SRC;
4090d442930SLoc Ho 
4100d442930SLoc Ho 	if (edac_op_state == EDAC_OPSTATE_POLL)
4110d442930SLoc Ho 		mci->edac_check = xgene_edac_mc_check;
4120d442930SLoc Ho 
4130d442930SLoc Ho 	if (edac_mc_add_mc(mci)) {
4140d442930SLoc Ho 		dev_err(edac->dev, "edac_mc_add_mc failed\n");
4150d442930SLoc Ho 		rc = -EINVAL;
4160d442930SLoc Ho 		goto err_free;
4170d442930SLoc Ho 	}
4180d442930SLoc Ho 
4190d442930SLoc Ho 	xgene_edac_mc_create_debugfs_node(mci);
4200d442930SLoc Ho 
4210d442930SLoc Ho 	list_add(&ctx->next, &edac->mcus);
4220d442930SLoc Ho 
4230d442930SLoc Ho 	xgene_edac_mc_irq_ctl(mci, true);
4240d442930SLoc Ho 
4250d442930SLoc Ho 	devres_remove_group(edac->dev, xgene_edac_mc_add);
4260d442930SLoc Ho 
4270d442930SLoc Ho 	dev_info(edac->dev, "X-Gene EDAC MC registered\n");
4280d442930SLoc Ho 	return 0;
4290d442930SLoc Ho 
4300d442930SLoc Ho err_free:
4310d442930SLoc Ho 	edac_mc_free(mci);
4320d442930SLoc Ho err_group:
4330d442930SLoc Ho 	devres_release_group(edac->dev, xgene_edac_mc_add);
4340d442930SLoc Ho 	return rc;
4350d442930SLoc Ho }
4360d442930SLoc Ho 
xgene_edac_mc_remove(struct xgene_edac_mc_ctx * mcu)4370d442930SLoc Ho static int xgene_edac_mc_remove(struct xgene_edac_mc_ctx *mcu)
4380d442930SLoc Ho {
4390d442930SLoc Ho 	xgene_edac_mc_irq_ctl(mcu->mci, false);
4400d442930SLoc Ho 	edac_mc_del_mc(&mcu->mci->dev);
4410d442930SLoc Ho 	edac_mc_free(mcu->mci);
4420d442930SLoc Ho 	return 0;
4430d442930SLoc Ho }
4440d442930SLoc Ho 
4450d442930SLoc Ho /* CPU L1/L2 error CSR */
4460d442930SLoc Ho #define MAX_CPU_PER_PMD				2
4470d442930SLoc Ho #define CPU_CSR_STRIDE				0x00100000
4480d442930SLoc Ho #define CPU_L2C_PAGE				0x000D0000
4490d442930SLoc Ho #define CPU_MEMERR_L2C_PAGE			0x000E0000
4500d442930SLoc Ho #define CPU_MEMERR_CPU_PAGE			0x000F0000
4510d442930SLoc Ho 
4520d442930SLoc Ho #define MEMERR_CPU_ICFECR_PAGE_OFFSET		0x0000
4530d442930SLoc Ho #define MEMERR_CPU_ICFESR_PAGE_OFFSET		0x0004
4540d442930SLoc Ho #define  MEMERR_CPU_ICFESR_ERRWAY_RD(src)	(((src) & 0xFF000000) >> 24)
4550d442930SLoc Ho #define  MEMERR_CPU_ICFESR_ERRINDEX_RD(src)	(((src) & 0x003F0000) >> 16)
4560d442930SLoc Ho #define  MEMERR_CPU_ICFESR_ERRINFO_RD(src)	(((src) & 0x0000FF00) >> 8)
4570d442930SLoc Ho #define  MEMERR_CPU_ICFESR_ERRTYPE_RD(src)	(((src) & 0x00000070) >> 4)
4580d442930SLoc Ho #define  MEMERR_CPU_ICFESR_MULTCERR_MASK	BIT(2)
4590d442930SLoc Ho #define  MEMERR_CPU_ICFESR_CERR_MASK		BIT(0)
4600d442930SLoc Ho #define MEMERR_CPU_LSUESR_PAGE_OFFSET		0x000c
4610d442930SLoc Ho #define  MEMERR_CPU_LSUESR_ERRWAY_RD(src)	(((src) & 0xFF000000) >> 24)
4620d442930SLoc Ho #define  MEMERR_CPU_LSUESR_ERRINDEX_RD(src)	(((src) & 0x003F0000) >> 16)
4630d442930SLoc Ho #define  MEMERR_CPU_LSUESR_ERRINFO_RD(src)	(((src) & 0x0000FF00) >> 8)
4640d442930SLoc Ho #define  MEMERR_CPU_LSUESR_ERRTYPE_RD(src)	(((src) & 0x00000070) >> 4)
4650d442930SLoc Ho #define  MEMERR_CPU_LSUESR_MULTCERR_MASK	BIT(2)
4660d442930SLoc Ho #define  MEMERR_CPU_LSUESR_CERR_MASK		BIT(0)
4670d442930SLoc Ho #define MEMERR_CPU_LSUECR_PAGE_OFFSET		0x0008
4680d442930SLoc Ho #define MEMERR_CPU_MMUECR_PAGE_OFFSET		0x0010
4690d442930SLoc Ho #define MEMERR_CPU_MMUESR_PAGE_OFFSET		0x0014
4700d442930SLoc Ho #define  MEMERR_CPU_MMUESR_ERRWAY_RD(src)	(((src) & 0xFF000000) >> 24)
4710d442930SLoc Ho #define  MEMERR_CPU_MMUESR_ERRINDEX_RD(src)	(((src) & 0x007F0000) >> 16)
4720d442930SLoc Ho #define  MEMERR_CPU_MMUESR_ERRINFO_RD(src)	(((src) & 0x0000FF00) >> 8)
4730d442930SLoc Ho #define  MEMERR_CPU_MMUESR_ERRREQSTR_LSU_MASK	BIT(7)
4740d442930SLoc Ho #define  MEMERR_CPU_MMUESR_ERRTYPE_RD(src)	(((src) & 0x00000070) >> 4)
4750d442930SLoc Ho #define  MEMERR_CPU_MMUESR_MULTCERR_MASK	BIT(2)
4760d442930SLoc Ho #define  MEMERR_CPU_MMUESR_CERR_MASK		BIT(0)
4770d442930SLoc Ho #define MEMERR_CPU_ICFESRA_PAGE_OFFSET		0x0804
4780d442930SLoc Ho #define MEMERR_CPU_LSUESRA_PAGE_OFFSET		0x080c
4790d442930SLoc Ho #define MEMERR_CPU_MMUESRA_PAGE_OFFSET		0x0814
4800d442930SLoc Ho 
4810d442930SLoc Ho #define MEMERR_L2C_L2ECR_PAGE_OFFSET		0x0000
4820d442930SLoc Ho #define MEMERR_L2C_L2ESR_PAGE_OFFSET		0x0004
4830d442930SLoc Ho #define  MEMERR_L2C_L2ESR_ERRSYN_RD(src)	(((src) & 0xFF000000) >> 24)
4840d442930SLoc Ho #define  MEMERR_L2C_L2ESR_ERRWAY_RD(src)	(((src) & 0x00FC0000) >> 18)
4850d442930SLoc Ho #define  MEMERR_L2C_L2ESR_ERRCPU_RD(src)	(((src) & 0x00020000) >> 17)
4860d442930SLoc Ho #define  MEMERR_L2C_L2ESR_ERRGROUP_RD(src)	(((src) & 0x0000E000) >> 13)
4870d442930SLoc Ho #define  MEMERR_L2C_L2ESR_ERRACTION_RD(src)	(((src) & 0x00001C00) >> 10)
4880d442930SLoc Ho #define  MEMERR_L2C_L2ESR_ERRTYPE_RD(src)	(((src) & 0x00000300) >> 8)
4890d442930SLoc Ho #define  MEMERR_L2C_L2ESR_MULTUCERR_MASK	BIT(3)
4900d442930SLoc Ho #define  MEMERR_L2C_L2ESR_MULTICERR_MASK	BIT(2)
4910d442930SLoc Ho #define  MEMERR_L2C_L2ESR_UCERR_MASK		BIT(1)
4920d442930SLoc Ho #define  MEMERR_L2C_L2ESR_ERR_MASK		BIT(0)
4930d442930SLoc Ho #define MEMERR_L2C_L2EALR_PAGE_OFFSET		0x0008
4940d442930SLoc Ho #define CPUX_L2C_L2RTOCR_PAGE_OFFSET		0x0010
4950d442930SLoc Ho #define MEMERR_L2C_L2EAHR_PAGE_OFFSET		0x000c
4960d442930SLoc Ho #define CPUX_L2C_L2RTOSR_PAGE_OFFSET		0x0014
4970d442930SLoc Ho #define  MEMERR_L2C_L2RTOSR_MULTERR_MASK	BIT(1)
4980d442930SLoc Ho #define  MEMERR_L2C_L2RTOSR_ERR_MASK		BIT(0)
4990d442930SLoc Ho #define CPUX_L2C_L2RTOALR_PAGE_OFFSET		0x0018
5000d442930SLoc Ho #define CPUX_L2C_L2RTOAHR_PAGE_OFFSET		0x001c
5010d442930SLoc Ho #define MEMERR_L2C_L2ESRA_PAGE_OFFSET		0x0804
5020d442930SLoc Ho 
5030d442930SLoc Ho /*
5042aeb1f5fSJulia Lawall  * Processor Module Domain (PMD) context - Context for a pair of processors.
5050d442930SLoc Ho  * Each PMD consists of 2 CPUs and a shared L2 cache. Each CPU consists of
5060d442930SLoc Ho  * its own L1 cache.
5070d442930SLoc Ho  */
5080d442930SLoc Ho struct xgene_edac_pmd_ctx {
5090d442930SLoc Ho 	struct list_head	next;
5100d442930SLoc Ho 	struct device		ddev;
5110d442930SLoc Ho 	char			*name;
5120d442930SLoc Ho 	struct xgene_edac	*edac;
5130d442930SLoc Ho 	struct edac_device_ctl_info *edac_dev;
5140d442930SLoc Ho 	void __iomem		*pmd_csr;
5150d442930SLoc Ho 	u32			pmd;
516451bb7fbSArnd Bergmann 	int			version;
5170d442930SLoc Ho };
5180d442930SLoc Ho 
xgene_edac_pmd_l1_check(struct edac_device_ctl_info * edac_dev,int cpu_idx)5190d442930SLoc Ho static void xgene_edac_pmd_l1_check(struct edac_device_ctl_info *edac_dev,
5200d442930SLoc Ho 				    int cpu_idx)
5210d442930SLoc Ho {
5220d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
5230d442930SLoc Ho 	void __iomem *pg_f;
5240d442930SLoc Ho 	u32 val;
5250d442930SLoc Ho 
5260d442930SLoc Ho 	pg_f = ctx->pmd_csr + cpu_idx * CPU_CSR_STRIDE + CPU_MEMERR_CPU_PAGE;
5270d442930SLoc Ho 
5280d442930SLoc Ho 	val = readl(pg_f + MEMERR_CPU_ICFESR_PAGE_OFFSET);
5299347473cSLoc Ho 	if (!val)
5309347473cSLoc Ho 		goto chk_lsu;
5310d442930SLoc Ho 	dev_err(edac_dev->dev,
5320d442930SLoc Ho 		"CPU%d L1 memory error ICF 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X\n",
5330d442930SLoc Ho 		ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
5340d442930SLoc Ho 		MEMERR_CPU_ICFESR_ERRWAY_RD(val),
5350d442930SLoc Ho 		MEMERR_CPU_ICFESR_ERRINDEX_RD(val),
5360d442930SLoc Ho 		MEMERR_CPU_ICFESR_ERRINFO_RD(val));
5370d442930SLoc Ho 	if (val & MEMERR_CPU_ICFESR_CERR_MASK)
5389347473cSLoc Ho 		dev_err(edac_dev->dev, "One or more correctable error\n");
5390d442930SLoc Ho 	if (val & MEMERR_CPU_ICFESR_MULTCERR_MASK)
5400d442930SLoc Ho 		dev_err(edac_dev->dev, "Multiple correctable error\n");
5410d442930SLoc Ho 	switch (MEMERR_CPU_ICFESR_ERRTYPE_RD(val)) {
5420d442930SLoc Ho 	case 1:
5430d442930SLoc Ho 		dev_err(edac_dev->dev, "L1 TLB multiple hit\n");
5440d442930SLoc Ho 		break;
5450d442930SLoc Ho 	case 2:
5460d442930SLoc Ho 		dev_err(edac_dev->dev, "Way select multiple hit\n");
5470d442930SLoc Ho 		break;
5480d442930SLoc Ho 	case 3:
5490d442930SLoc Ho 		dev_err(edac_dev->dev, "Physical tag parity error\n");
5500d442930SLoc Ho 		break;
5510d442930SLoc Ho 	case 4:
5520d442930SLoc Ho 	case 5:
5530d442930SLoc Ho 		dev_err(edac_dev->dev, "L1 data parity error\n");
5540d442930SLoc Ho 		break;
5550d442930SLoc Ho 	case 6:
5560d442930SLoc Ho 		dev_err(edac_dev->dev, "L1 pre-decode parity error\n");
5570d442930SLoc Ho 		break;
5580d442930SLoc Ho 	}
5590d442930SLoc Ho 
5600d442930SLoc Ho 	/* Clear any HW errors */
5610d442930SLoc Ho 	writel(val, pg_f + MEMERR_CPU_ICFESR_PAGE_OFFSET);
5620d442930SLoc Ho 
5630d442930SLoc Ho 	if (val & (MEMERR_CPU_ICFESR_CERR_MASK |
5640d442930SLoc Ho 		   MEMERR_CPU_ICFESR_MULTCERR_MASK))
5659347473cSLoc Ho 		edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
5660d442930SLoc Ho 
5679347473cSLoc Ho chk_lsu:
5680d442930SLoc Ho 	val = readl(pg_f + MEMERR_CPU_LSUESR_PAGE_OFFSET);
5699347473cSLoc Ho 	if (!val)
5709347473cSLoc Ho 		goto chk_mmu;
5710d442930SLoc Ho 	dev_err(edac_dev->dev,
5720d442930SLoc Ho 		"CPU%d memory error LSU 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X\n",
5730d442930SLoc Ho 		ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
5740d442930SLoc Ho 		MEMERR_CPU_LSUESR_ERRWAY_RD(val),
5750d442930SLoc Ho 		MEMERR_CPU_LSUESR_ERRINDEX_RD(val),
5760d442930SLoc Ho 		MEMERR_CPU_LSUESR_ERRINFO_RD(val));
5770d442930SLoc Ho 	if (val & MEMERR_CPU_LSUESR_CERR_MASK)
5789347473cSLoc Ho 		dev_err(edac_dev->dev, "One or more correctable error\n");
5790d442930SLoc Ho 	if (val & MEMERR_CPU_LSUESR_MULTCERR_MASK)
5800d442930SLoc Ho 		dev_err(edac_dev->dev, "Multiple correctable error\n");
5810d442930SLoc Ho 	switch (MEMERR_CPU_LSUESR_ERRTYPE_RD(val)) {
5820d442930SLoc Ho 	case 0:
5830d442930SLoc Ho 		dev_err(edac_dev->dev, "Load tag error\n");
5840d442930SLoc Ho 		break;
5850d442930SLoc Ho 	case 1:
5860d442930SLoc Ho 		dev_err(edac_dev->dev, "Load data error\n");
5870d442930SLoc Ho 		break;
5880d442930SLoc Ho 	case 2:
5890d442930SLoc Ho 		dev_err(edac_dev->dev, "WSL multihit error\n");
5900d442930SLoc Ho 		break;
5910d442930SLoc Ho 	case 3:
5920d442930SLoc Ho 		dev_err(edac_dev->dev, "Store tag error\n");
5930d442930SLoc Ho 		break;
5940d442930SLoc Ho 	case 4:
5950d442930SLoc Ho 		dev_err(edac_dev->dev,
5960d442930SLoc Ho 			"DTB multihit from load pipeline error\n");
5970d442930SLoc Ho 		break;
5980d442930SLoc Ho 	case 5:
5990d442930SLoc Ho 		dev_err(edac_dev->dev,
6000d442930SLoc Ho 			"DTB multihit from store pipeline error\n");
6010d442930SLoc Ho 		break;
6020d442930SLoc Ho 	}
6030d442930SLoc Ho 
6040d442930SLoc Ho 	/* Clear any HW errors */
6050d442930SLoc Ho 	writel(val, pg_f + MEMERR_CPU_LSUESR_PAGE_OFFSET);
6060d442930SLoc Ho 
6070d442930SLoc Ho 	if (val & (MEMERR_CPU_LSUESR_CERR_MASK |
6080d442930SLoc Ho 		   MEMERR_CPU_LSUESR_MULTCERR_MASK))
6099347473cSLoc Ho 		edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
6100d442930SLoc Ho 
6119347473cSLoc Ho chk_mmu:
6120d442930SLoc Ho 	val = readl(pg_f + MEMERR_CPU_MMUESR_PAGE_OFFSET);
6139347473cSLoc Ho 	if (!val)
6149347473cSLoc Ho 		return;
6150d442930SLoc Ho 	dev_err(edac_dev->dev,
6160d442930SLoc Ho 		"CPU%d memory error MMU 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X %s\n",
6170d442930SLoc Ho 		ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val,
6180d442930SLoc Ho 		MEMERR_CPU_MMUESR_ERRWAY_RD(val),
6190d442930SLoc Ho 		MEMERR_CPU_MMUESR_ERRINDEX_RD(val),
6200d442930SLoc Ho 		MEMERR_CPU_MMUESR_ERRINFO_RD(val),
6219347473cSLoc Ho 		val & MEMERR_CPU_MMUESR_ERRREQSTR_LSU_MASK ? "LSU" : "ICF");
6220d442930SLoc Ho 	if (val & MEMERR_CPU_MMUESR_CERR_MASK)
6239347473cSLoc Ho 		dev_err(edac_dev->dev, "One or more correctable error\n");
6240d442930SLoc Ho 	if (val & MEMERR_CPU_MMUESR_MULTCERR_MASK)
6250d442930SLoc Ho 		dev_err(edac_dev->dev, "Multiple correctable error\n");
6260d442930SLoc Ho 	switch (MEMERR_CPU_MMUESR_ERRTYPE_RD(val)) {
6270d442930SLoc Ho 	case 0:
6280d442930SLoc Ho 		dev_err(edac_dev->dev, "Stage 1 UTB hit error\n");
6290d442930SLoc Ho 		break;
6300d442930SLoc Ho 	case 1:
6310d442930SLoc Ho 		dev_err(edac_dev->dev, "Stage 1 UTB miss error\n");
6320d442930SLoc Ho 		break;
6330d442930SLoc Ho 	case 2:
6340d442930SLoc Ho 		dev_err(edac_dev->dev, "Stage 1 UTB allocate error\n");
6350d442930SLoc Ho 		break;
6360d442930SLoc Ho 	case 3:
6379347473cSLoc Ho 		dev_err(edac_dev->dev, "TMO operation single bank error\n");
6380d442930SLoc Ho 		break;
6390d442930SLoc Ho 	case 4:
6400d442930SLoc Ho 		dev_err(edac_dev->dev, "Stage 2 UTB error\n");
6410d442930SLoc Ho 		break;
6420d442930SLoc Ho 	case 5:
6430d442930SLoc Ho 		dev_err(edac_dev->dev, "Stage 2 UTB miss error\n");
6440d442930SLoc Ho 		break;
6450d442930SLoc Ho 	case 6:
6460d442930SLoc Ho 		dev_err(edac_dev->dev, "Stage 2 UTB allocate error\n");
6470d442930SLoc Ho 		break;
6480d442930SLoc Ho 	case 7:
6499347473cSLoc Ho 		dev_err(edac_dev->dev, "TMO operation multiple bank error\n");
6500d442930SLoc Ho 		break;
6510d442930SLoc Ho 	}
6520d442930SLoc Ho 
6530d442930SLoc Ho 	/* Clear any HW errors */
6540d442930SLoc Ho 	writel(val, pg_f + MEMERR_CPU_MMUESR_PAGE_OFFSET);
6550d442930SLoc Ho 
6560d442930SLoc Ho 	edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
6570d442930SLoc Ho }
6580d442930SLoc Ho 
xgene_edac_pmd_l2_check(struct edac_device_ctl_info * edac_dev)6590d442930SLoc Ho static void xgene_edac_pmd_l2_check(struct edac_device_ctl_info *edac_dev)
6600d442930SLoc Ho {
6610d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
6620d442930SLoc Ho 	void __iomem *pg_d;
6630d442930SLoc Ho 	void __iomem *pg_e;
6640d442930SLoc Ho 	u32 val_hi;
6650d442930SLoc Ho 	u32 val_lo;
6660d442930SLoc Ho 	u32 val;
6670d442930SLoc Ho 
6680d442930SLoc Ho 	/* Check L2 */
6690d442930SLoc Ho 	pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
6700d442930SLoc Ho 	val = readl(pg_e + MEMERR_L2C_L2ESR_PAGE_OFFSET);
6719347473cSLoc Ho 	if (!val)
6729347473cSLoc Ho 		goto chk_l2c;
6730d442930SLoc Ho 	val_lo = readl(pg_e + MEMERR_L2C_L2EALR_PAGE_OFFSET);
6740d442930SLoc Ho 	val_hi = readl(pg_e + MEMERR_L2C_L2EAHR_PAGE_OFFSET);
6750d442930SLoc Ho 	dev_err(edac_dev->dev,
6760d442930SLoc Ho 		"PMD%d memory error L2C L2ESR 0x%08X @ 0x%08X.%08X\n",
6770d442930SLoc Ho 		ctx->pmd, val, val_hi, val_lo);
6780d442930SLoc Ho 	dev_err(edac_dev->dev,
6790d442930SLoc Ho 		"ErrSyndrome 0x%02X ErrWay 0x%02X ErrCpu %d ErrGroup 0x%02X ErrAction 0x%02X\n",
6800d442930SLoc Ho 		MEMERR_L2C_L2ESR_ERRSYN_RD(val),
6810d442930SLoc Ho 		MEMERR_L2C_L2ESR_ERRWAY_RD(val),
6820d442930SLoc Ho 		MEMERR_L2C_L2ESR_ERRCPU_RD(val),
6830d442930SLoc Ho 		MEMERR_L2C_L2ESR_ERRGROUP_RD(val),
6840d442930SLoc Ho 		MEMERR_L2C_L2ESR_ERRACTION_RD(val));
6850d442930SLoc Ho 
6860d442930SLoc Ho 	if (val & MEMERR_L2C_L2ESR_ERR_MASK)
6879347473cSLoc Ho 		dev_err(edac_dev->dev, "One or more correctable error\n");
6880d442930SLoc Ho 	if (val & MEMERR_L2C_L2ESR_MULTICERR_MASK)
6890d442930SLoc Ho 		dev_err(edac_dev->dev, "Multiple correctable error\n");
6900d442930SLoc Ho 	if (val & MEMERR_L2C_L2ESR_UCERR_MASK)
6919347473cSLoc Ho 		dev_err(edac_dev->dev, "One or more uncorrectable error\n");
6920d442930SLoc Ho 	if (val & MEMERR_L2C_L2ESR_MULTUCERR_MASK)
6939347473cSLoc Ho 		dev_err(edac_dev->dev, "Multiple uncorrectable error\n");
6940d442930SLoc Ho 
6950d442930SLoc Ho 	switch (MEMERR_L2C_L2ESR_ERRTYPE_RD(val)) {
6960d442930SLoc Ho 	case 0:
6970d442930SLoc Ho 		dev_err(edac_dev->dev, "Outbound SDB parity error\n");
6980d442930SLoc Ho 		break;
6990d442930SLoc Ho 	case 1:
7000d442930SLoc Ho 		dev_err(edac_dev->dev, "Inbound SDB parity error\n");
7010d442930SLoc Ho 		break;
7020d442930SLoc Ho 	case 2:
7030d442930SLoc Ho 		dev_err(edac_dev->dev, "Tag ECC error\n");
7040d442930SLoc Ho 		break;
7050d442930SLoc Ho 	case 3:
7060d442930SLoc Ho 		dev_err(edac_dev->dev, "Data ECC error\n");
7070d442930SLoc Ho 		break;
7080d442930SLoc Ho 	}
7090d442930SLoc Ho 
7100d442930SLoc Ho 	/* Clear any HW errors */
7110d442930SLoc Ho 	writel(val, pg_e + MEMERR_L2C_L2ESR_PAGE_OFFSET);
7120d442930SLoc Ho 
7130d442930SLoc Ho 	if (val & (MEMERR_L2C_L2ESR_ERR_MASK |
7140d442930SLoc Ho 		   MEMERR_L2C_L2ESR_MULTICERR_MASK))
7159347473cSLoc Ho 		edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
7160d442930SLoc Ho 	if (val & (MEMERR_L2C_L2ESR_UCERR_MASK |
7170d442930SLoc Ho 		   MEMERR_L2C_L2ESR_MULTUCERR_MASK))
7189347473cSLoc Ho 		edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
7190d442930SLoc Ho 
7209347473cSLoc Ho chk_l2c:
7210d442930SLoc Ho 	/* Check if any memory request timed out on L2 cache */
7220d442930SLoc Ho 	pg_d = ctx->pmd_csr + CPU_L2C_PAGE;
7230d442930SLoc Ho 	val = readl(pg_d + CPUX_L2C_L2RTOSR_PAGE_OFFSET);
7240d442930SLoc Ho 	if (val) {
7250d442930SLoc Ho 		val_lo = readl(pg_d + CPUX_L2C_L2RTOALR_PAGE_OFFSET);
7260d442930SLoc Ho 		val_hi = readl(pg_d + CPUX_L2C_L2RTOAHR_PAGE_OFFSET);
7270d442930SLoc Ho 		dev_err(edac_dev->dev,
7280d442930SLoc Ho 			"PMD%d L2C error L2C RTOSR 0x%08X @ 0x%08X.%08X\n",
7290d442930SLoc Ho 			ctx->pmd, val, val_hi, val_lo);
7300d442930SLoc Ho 		writel(val, pg_d + CPUX_L2C_L2RTOSR_PAGE_OFFSET);
7310d442930SLoc Ho 	}
7320d442930SLoc Ho }
7330d442930SLoc Ho 
xgene_edac_pmd_check(struct edac_device_ctl_info * edac_dev)7340d442930SLoc Ho static void xgene_edac_pmd_check(struct edac_device_ctl_info *edac_dev)
7350d442930SLoc Ho {
7360d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
7370d442930SLoc Ho 	unsigned int pcp_hp_stat;
7380d442930SLoc Ho 	int i;
7390d442930SLoc Ho 
7400d442930SLoc Ho 	xgene_edac_pcp_rd(ctx->edac, PCPHPERRINTSTS, &pcp_hp_stat);
7410d442930SLoc Ho 	if (!((PMD0_MERR_MASK << ctx->pmd) & pcp_hp_stat))
7420d442930SLoc Ho 		return;
7430d442930SLoc Ho 
7440d442930SLoc Ho 	/* Check CPU L1 error */
7450d442930SLoc Ho 	for (i = 0; i < MAX_CPU_PER_PMD; i++)
7460d442930SLoc Ho 		xgene_edac_pmd_l1_check(edac_dev, i);
7470d442930SLoc Ho 
7480d442930SLoc Ho 	/* Check CPU L2 error */
7490d442930SLoc Ho 	xgene_edac_pmd_l2_check(edac_dev);
7500d442930SLoc Ho }
7510d442930SLoc Ho 
xgene_edac_pmd_cpu_hw_cfg(struct edac_device_ctl_info * edac_dev,int cpu)7520d442930SLoc Ho static void xgene_edac_pmd_cpu_hw_cfg(struct edac_device_ctl_info *edac_dev,
7530d442930SLoc Ho 				      int cpu)
7540d442930SLoc Ho {
7550d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
7560d442930SLoc Ho 	void __iomem *pg_f = ctx->pmd_csr + cpu * CPU_CSR_STRIDE +
7570d442930SLoc Ho 			     CPU_MEMERR_CPU_PAGE;
7580d442930SLoc Ho 
7590d442930SLoc Ho 	/*
7600d442930SLoc Ho 	 * Enable CPU memory error:
7610d442930SLoc Ho 	 *  MEMERR_CPU_ICFESRA, MEMERR_CPU_LSUESRA, and MEMERR_CPU_MMUESRA
7620d442930SLoc Ho 	 */
7630d442930SLoc Ho 	writel(0x00000301, pg_f + MEMERR_CPU_ICFECR_PAGE_OFFSET);
7640d442930SLoc Ho 	writel(0x00000301, pg_f + MEMERR_CPU_LSUECR_PAGE_OFFSET);
7650d442930SLoc Ho 	writel(0x00000101, pg_f + MEMERR_CPU_MMUECR_PAGE_OFFSET);
7660d442930SLoc Ho }
7670d442930SLoc Ho 
xgene_edac_pmd_hw_cfg(struct edac_device_ctl_info * edac_dev)7680d442930SLoc Ho static void xgene_edac_pmd_hw_cfg(struct edac_device_ctl_info *edac_dev)
7690d442930SLoc Ho {
7700d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
7710d442930SLoc Ho 	void __iomem *pg_d = ctx->pmd_csr + CPU_L2C_PAGE;
7720d442930SLoc Ho 	void __iomem *pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
7730d442930SLoc Ho 
7740d442930SLoc Ho 	/* Enable PMD memory error - MEMERR_L2C_L2ECR and L2C_L2RTOCR */
7750d442930SLoc Ho 	writel(0x00000703, pg_e + MEMERR_L2C_L2ECR_PAGE_OFFSET);
7760d442930SLoc Ho 	/* Configure L2C HW request time out feature if supported */
777451bb7fbSArnd Bergmann 	if (ctx->version > 1)
7780d442930SLoc Ho 		writel(0x00000119, pg_d + CPUX_L2C_L2RTOCR_PAGE_OFFSET);
7790d442930SLoc Ho }
7800d442930SLoc Ho 
xgene_edac_pmd_hw_ctl(struct edac_device_ctl_info * edac_dev,bool enable)7810d442930SLoc Ho static void xgene_edac_pmd_hw_ctl(struct edac_device_ctl_info *edac_dev,
7820d442930SLoc Ho 				  bool enable)
7830d442930SLoc Ho {
7840d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
7850d442930SLoc Ho 	int i;
7860d442930SLoc Ho 
7870d442930SLoc Ho 	/* Enable PMD error interrupt */
7880d442930SLoc Ho 	if (edac_dev->op_state == OP_RUNNING_INTERRUPT) {
7890d442930SLoc Ho 		if (enable)
7900d442930SLoc Ho 			xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
7910d442930SLoc Ho 					       PMD0_MERR_MASK << ctx->pmd);
7920d442930SLoc Ho 		else
7930d442930SLoc Ho 			xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
7940d442930SLoc Ho 					       PMD0_MERR_MASK << ctx->pmd);
7950d442930SLoc Ho 	}
7960d442930SLoc Ho 
7970d442930SLoc Ho 	if (enable) {
7980d442930SLoc Ho 		xgene_edac_pmd_hw_cfg(edac_dev);
7990d442930SLoc Ho 
8000d442930SLoc Ho 		/* Two CPUs per a PMD */
8010d442930SLoc Ho 		for (i = 0; i < MAX_CPU_PER_PMD; i++)
8020d442930SLoc Ho 			xgene_edac_pmd_cpu_hw_cfg(edac_dev, i);
8030d442930SLoc Ho 	}
8040d442930SLoc Ho }
8050d442930SLoc Ho 
xgene_edac_pmd_l1_inject_ctrl_write(struct file * file,const char __user * data,size_t count,loff_t * ppos)8060d442930SLoc Ho static ssize_t xgene_edac_pmd_l1_inject_ctrl_write(struct file *file,
8070d442930SLoc Ho 						   const char __user *data,
8080d442930SLoc Ho 						   size_t count, loff_t *ppos)
8090d442930SLoc Ho {
8100d442930SLoc Ho 	struct edac_device_ctl_info *edac_dev = file->private_data;
8110d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
8120d442930SLoc Ho 	void __iomem *cpux_pg_f;
8130d442930SLoc Ho 	int i;
8140d442930SLoc Ho 
8150d442930SLoc Ho 	for (i = 0; i < MAX_CPU_PER_PMD; i++) {
8160d442930SLoc Ho 		cpux_pg_f = ctx->pmd_csr + i * CPU_CSR_STRIDE +
8170d442930SLoc Ho 			    CPU_MEMERR_CPU_PAGE;
8180d442930SLoc Ho 
8190d442930SLoc Ho 		writel(MEMERR_CPU_ICFESR_MULTCERR_MASK |
8200d442930SLoc Ho 		       MEMERR_CPU_ICFESR_CERR_MASK,
8210d442930SLoc Ho 		       cpux_pg_f + MEMERR_CPU_ICFESRA_PAGE_OFFSET);
8220d442930SLoc Ho 		writel(MEMERR_CPU_LSUESR_MULTCERR_MASK |
8230d442930SLoc Ho 		       MEMERR_CPU_LSUESR_CERR_MASK,
8240d442930SLoc Ho 		       cpux_pg_f + MEMERR_CPU_LSUESRA_PAGE_OFFSET);
8250d442930SLoc Ho 		writel(MEMERR_CPU_MMUESR_MULTCERR_MASK |
8260d442930SLoc Ho 		       MEMERR_CPU_MMUESR_CERR_MASK,
8270d442930SLoc Ho 		       cpux_pg_f + MEMERR_CPU_MMUESRA_PAGE_OFFSET);
8280d442930SLoc Ho 	}
8290d442930SLoc Ho 	return count;
8300d442930SLoc Ho }
8310d442930SLoc Ho 
xgene_edac_pmd_l2_inject_ctrl_write(struct file * file,const char __user * data,size_t count,loff_t * ppos)8320d442930SLoc Ho static ssize_t xgene_edac_pmd_l2_inject_ctrl_write(struct file *file,
8330d442930SLoc Ho 						   const char __user *data,
8340d442930SLoc Ho 						   size_t count, loff_t *ppos)
8350d442930SLoc Ho {
8360d442930SLoc Ho 	struct edac_device_ctl_info *edac_dev = file->private_data;
8370d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
8380d442930SLoc Ho 	void __iomem *pg_e = ctx->pmd_csr + CPU_MEMERR_L2C_PAGE;
8390d442930SLoc Ho 
8400d442930SLoc Ho 	writel(MEMERR_L2C_L2ESR_MULTUCERR_MASK |
8410d442930SLoc Ho 	       MEMERR_L2C_L2ESR_MULTICERR_MASK |
8420d442930SLoc Ho 	       MEMERR_L2C_L2ESR_UCERR_MASK |
8430d442930SLoc Ho 	       MEMERR_L2C_L2ESR_ERR_MASK,
8440d442930SLoc Ho 	       pg_e + MEMERR_L2C_L2ESRA_PAGE_OFFSET);
8450d442930SLoc Ho 	return count;
8460d442930SLoc Ho }
8470d442930SLoc Ho 
8480d442930SLoc Ho static const struct file_operations xgene_edac_pmd_debug_inject_fops[] = {
8490d442930SLoc Ho 	{
8500d442930SLoc Ho 	.open = simple_open,
8510d442930SLoc Ho 	.write = xgene_edac_pmd_l1_inject_ctrl_write,
8520d442930SLoc Ho 	.llseek = generic_file_llseek, },
8530d442930SLoc Ho 	{
8540d442930SLoc Ho 	.open = simple_open,
8550d442930SLoc Ho 	.write = xgene_edac_pmd_l2_inject_ctrl_write,
8560d442930SLoc Ho 	.llseek = generic_file_llseek, },
8570d442930SLoc Ho 	{ }
8580d442930SLoc Ho };
8590d442930SLoc Ho 
8609347473cSLoc Ho static void
xgene_edac_pmd_create_debugfs_nodes(struct edac_device_ctl_info * edac_dev)8619347473cSLoc Ho xgene_edac_pmd_create_debugfs_nodes(struct edac_device_ctl_info *edac_dev)
8620d442930SLoc Ho {
8630d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx = edac_dev->pvt_info;
86409bd1b4fSBorislav Petkov 	struct dentry *dbgfs_dir;
8659347473cSLoc Ho 	char name[10];
8660d442930SLoc Ho 
8679347473cSLoc Ho 	if (!IS_ENABLED(CONFIG_EDAC_DEBUG) || !ctx->edac->dfs)
8680d442930SLoc Ho 		return;
8690d442930SLoc Ho 
8709bc1c0c0SLoc Ho 	snprintf(name, sizeof(name), "PMD%d", ctx->pmd);
87109bd1b4fSBorislav Petkov 	dbgfs_dir = edac_debugfs_create_dir_at(name, ctx->edac->dfs);
87209bd1b4fSBorislav Petkov 	if (!dbgfs_dir)
8730d442930SLoc Ho 		return;
8740d442930SLoc Ho 
87509bd1b4fSBorislav Petkov 	edac_debugfs_create_file("l1_inject_ctrl", S_IWUSR, dbgfs_dir, edac_dev,
8760d442930SLoc Ho 				 &xgene_edac_pmd_debug_inject_fops[0]);
87709bd1b4fSBorislav Petkov 	edac_debugfs_create_file("l2_inject_ctrl", S_IWUSR, dbgfs_dir, edac_dev,
8780d442930SLoc Ho 				 &xgene_edac_pmd_debug_inject_fops[1]);
8790d442930SLoc Ho }
8800d442930SLoc Ho 
xgene_edac_pmd_available(u32 efuse,int pmd)8810d442930SLoc Ho static int xgene_edac_pmd_available(u32 efuse, int pmd)
8820d442930SLoc Ho {
8830d442930SLoc Ho 	return (efuse & (1 << pmd)) ? 0 : 1;
8840d442930SLoc Ho }
8850d442930SLoc Ho 
xgene_edac_pmd_add(struct xgene_edac * edac,struct device_node * np,int version)886451bb7fbSArnd Bergmann static int xgene_edac_pmd_add(struct xgene_edac *edac, struct device_node *np,
887451bb7fbSArnd Bergmann 			      int version)
8880d442930SLoc Ho {
8890d442930SLoc Ho 	struct edac_device_ctl_info *edac_dev;
8900d442930SLoc Ho 	struct xgene_edac_pmd_ctx *ctx;
8910d442930SLoc Ho 	struct resource res;
8920d442930SLoc Ho 	char edac_name[10];
8930d442930SLoc Ho 	u32 pmd;
8940d442930SLoc Ho 	int rc;
8950d442930SLoc Ho 	u32 val;
8960d442930SLoc Ho 
8970d442930SLoc Ho 	if (!devres_open_group(edac->dev, xgene_edac_pmd_add, GFP_KERNEL))
8980d442930SLoc Ho 		return -ENOMEM;
8990d442930SLoc Ho 
9000d442930SLoc Ho 	/* Determine if this PMD is disabled */
9010d442930SLoc Ho 	if (of_property_read_u32(np, "pmd-controller", &pmd)) {
9020d442930SLoc Ho 		dev_err(edac->dev, "no pmd-controller property\n");
9030d442930SLoc Ho 		rc = -ENODEV;
9040d442930SLoc Ho 		goto err_group;
9050d442930SLoc Ho 	}
9060d442930SLoc Ho 	rc = regmap_read(edac->efuse_map, 0, &val);
9070d442930SLoc Ho 	if (rc)
9080d442930SLoc Ho 		goto err_group;
9090d442930SLoc Ho 	if (!xgene_edac_pmd_available(val, pmd)) {
9100d442930SLoc Ho 		rc = -ENODEV;
9110d442930SLoc Ho 		goto err_group;
9120d442930SLoc Ho 	}
9130d442930SLoc Ho 
9149bc1c0c0SLoc Ho 	snprintf(edac_name, sizeof(edac_name), "l2c%d", pmd);
9150d442930SLoc Ho 	edac_dev = edac_device_alloc_ctl_info(sizeof(*ctx),
9160d442930SLoc Ho 					      edac_name, 1, "l2c", 1, 2, NULL,
9170d442930SLoc Ho 					      0, edac_device_alloc_index());
9180d442930SLoc Ho 	if (!edac_dev) {
9190d442930SLoc Ho 		rc = -ENOMEM;
9200d442930SLoc Ho 		goto err_group;
9210d442930SLoc Ho 	}
9220d442930SLoc Ho 
9230d442930SLoc Ho 	ctx = edac_dev->pvt_info;
9240d442930SLoc Ho 	ctx->name = "xgene_pmd_err";
9250d442930SLoc Ho 	ctx->pmd = pmd;
9260d442930SLoc Ho 	ctx->edac = edac;
9270d442930SLoc Ho 	ctx->edac_dev = edac_dev;
9280d442930SLoc Ho 	ctx->ddev = *edac->dev;
929451bb7fbSArnd Bergmann 	ctx->version = version;
9300d442930SLoc Ho 	edac_dev->dev = &ctx->ddev;
9310d442930SLoc Ho 	edac_dev->ctl_name = ctx->name;
9320d442930SLoc Ho 	edac_dev->dev_name = ctx->name;
9330d442930SLoc Ho 	edac_dev->mod_name = EDAC_MOD_STR;
9340d442930SLoc Ho 
9350d442930SLoc Ho 	rc = of_address_to_resource(np, 0, &res);
9360d442930SLoc Ho 	if (rc < 0) {
9370d442930SLoc Ho 		dev_err(edac->dev, "no PMD resource address\n");
9380d442930SLoc Ho 		goto err_free;
9390d442930SLoc Ho 	}
9400d442930SLoc Ho 	ctx->pmd_csr = devm_ioremap_resource(edac->dev, &res);
9410d442930SLoc Ho 	if (IS_ERR(ctx->pmd_csr)) {
9420d442930SLoc Ho 		dev_err(edac->dev,
9430d442930SLoc Ho 			"devm_ioremap_resource failed for PMD resource address\n");
9440d442930SLoc Ho 		rc = PTR_ERR(ctx->pmd_csr);
9450d442930SLoc Ho 		goto err_free;
9460d442930SLoc Ho 	}
9470d442930SLoc Ho 
9480d442930SLoc Ho 	if (edac_op_state == EDAC_OPSTATE_POLL)
9490d442930SLoc Ho 		edac_dev->edac_check = xgene_edac_pmd_check;
9500d442930SLoc Ho 
9510d442930SLoc Ho 	xgene_edac_pmd_create_debugfs_nodes(edac_dev);
9520d442930SLoc Ho 
9530d442930SLoc Ho 	rc = edac_device_add_device(edac_dev);
9540d442930SLoc Ho 	if (rc > 0) {
9550d442930SLoc Ho 		dev_err(edac->dev, "edac_device_add_device failed\n");
9560d442930SLoc Ho 		rc = -ENOMEM;
9570d442930SLoc Ho 		goto err_free;
9580d442930SLoc Ho 	}
9590d442930SLoc Ho 
9600d442930SLoc Ho 	if (edac_op_state == EDAC_OPSTATE_INT)
9610d442930SLoc Ho 		edac_dev->op_state = OP_RUNNING_INTERRUPT;
9620d442930SLoc Ho 
9630d442930SLoc Ho 	list_add(&ctx->next, &edac->pmds);
9640d442930SLoc Ho 
9650d442930SLoc Ho 	xgene_edac_pmd_hw_ctl(edac_dev, 1);
9660d442930SLoc Ho 
9670d442930SLoc Ho 	devres_remove_group(edac->dev, xgene_edac_pmd_add);
9680d442930SLoc Ho 
9690d442930SLoc Ho 	dev_info(edac->dev, "X-Gene EDAC PMD%d registered\n", ctx->pmd);
9700d442930SLoc Ho 	return 0;
9710d442930SLoc Ho 
9720d442930SLoc Ho err_free:
9730d442930SLoc Ho 	edac_device_free_ctl_info(edac_dev);
9740d442930SLoc Ho err_group:
9750d442930SLoc Ho 	devres_release_group(edac->dev, xgene_edac_pmd_add);
9760d442930SLoc Ho 	return rc;
9770d442930SLoc Ho }
9780d442930SLoc Ho 
xgene_edac_pmd_remove(struct xgene_edac_pmd_ctx * pmd)9790d442930SLoc Ho static int xgene_edac_pmd_remove(struct xgene_edac_pmd_ctx *pmd)
9800d442930SLoc Ho {
9810d442930SLoc Ho 	struct edac_device_ctl_info *edac_dev = pmd->edac_dev;
9820d442930SLoc Ho 
9830d442930SLoc Ho 	xgene_edac_pmd_hw_ctl(edac_dev, 0);
9840d442930SLoc Ho 	edac_device_del_device(edac_dev->dev);
9850d442930SLoc Ho 	edac_device_free_ctl_info(edac_dev);
9860d442930SLoc Ho 	return 0;
9870d442930SLoc Ho }
9880d442930SLoc Ho 
9899347473cSLoc Ho /* L3 Error device */
9909347473cSLoc Ho #define L3C_ESR				(0x0A * 4)
9919347473cSLoc Ho #define  L3C_ESR_DATATAG_MASK		BIT(9)
9929347473cSLoc Ho #define  L3C_ESR_MULTIHIT_MASK		BIT(8)
9939347473cSLoc Ho #define  L3C_ESR_UCEVICT_MASK		BIT(6)
9949347473cSLoc Ho #define  L3C_ESR_MULTIUCERR_MASK	BIT(5)
9959347473cSLoc Ho #define  L3C_ESR_MULTICERR_MASK		BIT(4)
9969347473cSLoc Ho #define  L3C_ESR_UCERR_MASK		BIT(3)
9979347473cSLoc Ho #define  L3C_ESR_CERR_MASK		BIT(2)
9989347473cSLoc Ho #define  L3C_ESR_UCERRINTR_MASK		BIT(1)
9999347473cSLoc Ho #define  L3C_ESR_CERRINTR_MASK		BIT(0)
10009347473cSLoc Ho #define L3C_ECR				(0x0B * 4)
10019347473cSLoc Ho #define  L3C_ECR_UCINTREN		BIT(3)
10029347473cSLoc Ho #define  L3C_ECR_CINTREN		BIT(2)
10039347473cSLoc Ho #define  L3C_UCERREN			BIT(1)
10049347473cSLoc Ho #define  L3C_CERREN			BIT(0)
10059347473cSLoc Ho #define L3C_ELR				(0x0C * 4)
10069347473cSLoc Ho #define  L3C_ELR_ERRSYN(src)		((src & 0xFF800000) >> 23)
10079347473cSLoc Ho #define  L3C_ELR_ERRWAY(src)		((src & 0x007E0000) >> 17)
10089347473cSLoc Ho #define  L3C_ELR_AGENTID(src)		((src & 0x0001E000) >> 13)
10099347473cSLoc Ho #define  L3C_ELR_ERRGRP(src)		((src & 0x00000F00) >> 8)
10109347473cSLoc Ho #define  L3C_ELR_OPTYPE(src)		((src & 0x000000F0) >> 4)
10119347473cSLoc Ho #define  L3C_ELR_PADDRHIGH(src)		(src & 0x0000000F)
10129347473cSLoc Ho #define L3C_AELR			(0x0D * 4)
10139347473cSLoc Ho #define L3C_BELR			(0x0E * 4)
10149347473cSLoc Ho #define  L3C_BELR_BANK(src)		(src & 0x0000000F)
10159347473cSLoc Ho 
10169347473cSLoc Ho struct xgene_edac_dev_ctx {
10179347473cSLoc Ho 	struct list_head	next;
10189347473cSLoc Ho 	struct device		ddev;
10199347473cSLoc Ho 	char			*name;
10209347473cSLoc Ho 	struct xgene_edac	*edac;
10219347473cSLoc Ho 	struct edac_device_ctl_info *edac_dev;
10229347473cSLoc Ho 	int			edac_idx;
10239347473cSLoc Ho 	void __iomem		*dev_csr;
10249347473cSLoc Ho 	int			version;
10259347473cSLoc Ho };
10269347473cSLoc Ho 
10279347473cSLoc Ho /*
10289347473cSLoc Ho  * Version 1 of the L3 controller has broken single bit correctable logic for
10299347473cSLoc Ho  * certain error syndromes. Log them as uncorrectable in that case.
10309347473cSLoc Ho  */
xgene_edac_l3_promote_to_uc_err(u32 l3cesr,u32 l3celr)10319347473cSLoc Ho static bool xgene_edac_l3_promote_to_uc_err(u32 l3cesr, u32 l3celr)
10329347473cSLoc Ho {
10339347473cSLoc Ho 	if (l3cesr & L3C_ESR_DATATAG_MASK) {
10349347473cSLoc Ho 		switch (L3C_ELR_ERRSYN(l3celr)) {
10359347473cSLoc Ho 		case 0x13C:
10369347473cSLoc Ho 		case 0x0B4:
10379347473cSLoc Ho 		case 0x007:
10389347473cSLoc Ho 		case 0x00D:
10399347473cSLoc Ho 		case 0x00E:
10409347473cSLoc Ho 		case 0x019:
10419347473cSLoc Ho 		case 0x01A:
10429347473cSLoc Ho 		case 0x01C:
10439347473cSLoc Ho 		case 0x04E:
10449347473cSLoc Ho 		case 0x041:
10459347473cSLoc Ho 			return true;
10469347473cSLoc Ho 		}
10474d67e3ceSLoc Ho 	} else if (L3C_ELR_ERRWAY(l3celr) == 9)
10489347473cSLoc Ho 		return true;
10499347473cSLoc Ho 
10509347473cSLoc Ho 	return false;
10519347473cSLoc Ho }
10529347473cSLoc Ho 
xgene_edac_l3_check(struct edac_device_ctl_info * edac_dev)10539347473cSLoc Ho static void xgene_edac_l3_check(struct edac_device_ctl_info *edac_dev)
10549347473cSLoc Ho {
10559347473cSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
10569347473cSLoc Ho 	u32 l3cesr;
10579347473cSLoc Ho 	u32 l3celr;
10589347473cSLoc Ho 	u32 l3caelr;
10599347473cSLoc Ho 	u32 l3cbelr;
10609347473cSLoc Ho 
10619347473cSLoc Ho 	l3cesr = readl(ctx->dev_csr + L3C_ESR);
10629347473cSLoc Ho 	if (!(l3cesr & (L3C_ESR_UCERR_MASK | L3C_ESR_CERR_MASK)))
10639347473cSLoc Ho 		return;
10649347473cSLoc Ho 
10659347473cSLoc Ho 	if (l3cesr & L3C_ESR_UCERR_MASK)
10669347473cSLoc Ho 		dev_err(edac_dev->dev, "L3C uncorrectable error\n");
10679347473cSLoc Ho 	if (l3cesr & L3C_ESR_CERR_MASK)
10689347473cSLoc Ho 		dev_warn(edac_dev->dev, "L3C correctable error\n");
10699347473cSLoc Ho 
10709347473cSLoc Ho 	l3celr = readl(ctx->dev_csr + L3C_ELR);
10719347473cSLoc Ho 	l3caelr = readl(ctx->dev_csr + L3C_AELR);
10729347473cSLoc Ho 	l3cbelr = readl(ctx->dev_csr + L3C_BELR);
10739347473cSLoc Ho 	if (l3cesr & L3C_ESR_MULTIHIT_MASK)
10749347473cSLoc Ho 		dev_err(edac_dev->dev, "L3C multiple hit error\n");
10759347473cSLoc Ho 	if (l3cesr & L3C_ESR_UCEVICT_MASK)
10769347473cSLoc Ho 		dev_err(edac_dev->dev,
10779347473cSLoc Ho 			"L3C dropped eviction of line with error\n");
10789347473cSLoc Ho 	if (l3cesr & L3C_ESR_MULTIUCERR_MASK)
10799347473cSLoc Ho 		dev_err(edac_dev->dev, "L3C multiple uncorrectable error\n");
10809347473cSLoc Ho 	if (l3cesr & L3C_ESR_DATATAG_MASK)
10819347473cSLoc Ho 		dev_err(edac_dev->dev,
10829347473cSLoc Ho 			"L3C data error syndrome 0x%X group 0x%X\n",
10839347473cSLoc Ho 			L3C_ELR_ERRSYN(l3celr), L3C_ELR_ERRGRP(l3celr));
10849347473cSLoc Ho 	else
10859347473cSLoc Ho 		dev_err(edac_dev->dev,
10869347473cSLoc Ho 			"L3C tag error syndrome 0x%X Way of Tag 0x%X Agent ID 0x%X Operation type 0x%X\n",
10879347473cSLoc Ho 			L3C_ELR_ERRSYN(l3celr), L3C_ELR_ERRWAY(l3celr),
10889347473cSLoc Ho 			L3C_ELR_AGENTID(l3celr), L3C_ELR_OPTYPE(l3celr));
10899347473cSLoc Ho 	/*
10909347473cSLoc Ho 	 * NOTE: Address [41:38] in L3C_ELR_PADDRHIGH(l3celr).
10919347473cSLoc Ho 	 *       Address [37:6] in l3caelr. Lower 6 bits are zero.
10929347473cSLoc Ho 	 */
10939347473cSLoc Ho 	dev_err(edac_dev->dev, "L3C error address 0x%08X.%08X bank %d\n",
10949347473cSLoc Ho 		L3C_ELR_PADDRHIGH(l3celr) << 6 | (l3caelr >> 26),
10959347473cSLoc Ho 		(l3caelr & 0x3FFFFFFF) << 6, L3C_BELR_BANK(l3cbelr));
10969347473cSLoc Ho 	dev_err(edac_dev->dev,
10979347473cSLoc Ho 		"L3C error status register value 0x%X\n", l3cesr);
10989347473cSLoc Ho 
10999347473cSLoc Ho 	/* Clear L3C error interrupt */
11009347473cSLoc Ho 	writel(0, ctx->dev_csr + L3C_ESR);
11019347473cSLoc Ho 
11029347473cSLoc Ho 	if (ctx->version <= 1 &&
11039347473cSLoc Ho 	    xgene_edac_l3_promote_to_uc_err(l3cesr, l3celr)) {
11049347473cSLoc Ho 		edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
11059347473cSLoc Ho 		return;
11069347473cSLoc Ho 	}
11079347473cSLoc Ho 	if (l3cesr & L3C_ESR_CERR_MASK)
11089347473cSLoc Ho 		edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
11099347473cSLoc Ho 	if (l3cesr & L3C_ESR_UCERR_MASK)
11109347473cSLoc Ho 		edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
11119347473cSLoc Ho }
11129347473cSLoc Ho 
xgene_edac_l3_hw_init(struct edac_device_ctl_info * edac_dev,bool enable)11139347473cSLoc Ho static void xgene_edac_l3_hw_init(struct edac_device_ctl_info *edac_dev,
11149347473cSLoc Ho 				  bool enable)
11159347473cSLoc Ho {
11169347473cSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
11179347473cSLoc Ho 	u32 val;
11189347473cSLoc Ho 
11199347473cSLoc Ho 	val = readl(ctx->dev_csr + L3C_ECR);
11209347473cSLoc Ho 	val |= L3C_UCERREN | L3C_CERREN;
11219347473cSLoc Ho 	/* On disable, we just disable interrupt but keep error enabled */
11229347473cSLoc Ho 	if (edac_dev->op_state == OP_RUNNING_INTERRUPT) {
11239347473cSLoc Ho 		if (enable)
11249347473cSLoc Ho 			val |= L3C_ECR_UCINTREN | L3C_ECR_CINTREN;
11259347473cSLoc Ho 		else
11269347473cSLoc Ho 			val &= ~(L3C_ECR_UCINTREN | L3C_ECR_CINTREN);
11279347473cSLoc Ho 	}
11289347473cSLoc Ho 	writel(val, ctx->dev_csr + L3C_ECR);
11299347473cSLoc Ho 
11309347473cSLoc Ho 	if (edac_dev->op_state == OP_RUNNING_INTERRUPT) {
11319347473cSLoc Ho 		/* Enable/disable L3 error top level interrupt */
11329347473cSLoc Ho 		if (enable) {
11339347473cSLoc Ho 			xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
11349347473cSLoc Ho 					       L3C_UNCORR_ERR_MASK);
11359347473cSLoc Ho 			xgene_edac_pcp_clrbits(ctx->edac, PCPLPERRINTMSK,
11369347473cSLoc Ho 					       L3C_CORR_ERR_MASK);
11379347473cSLoc Ho 		} else {
11389347473cSLoc Ho 			xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
11399347473cSLoc Ho 					       L3C_UNCORR_ERR_MASK);
11409347473cSLoc Ho 			xgene_edac_pcp_setbits(ctx->edac, PCPLPERRINTMSK,
11419347473cSLoc Ho 					       L3C_CORR_ERR_MASK);
11429347473cSLoc Ho 		}
11439347473cSLoc Ho 	}
11449347473cSLoc Ho }
11459347473cSLoc Ho 
xgene_edac_l3_inject_ctrl_write(struct file * file,const char __user * data,size_t count,loff_t * ppos)11469347473cSLoc Ho static ssize_t xgene_edac_l3_inject_ctrl_write(struct file *file,
11479347473cSLoc Ho 					       const char __user *data,
11489347473cSLoc Ho 					       size_t count, loff_t *ppos)
11499347473cSLoc Ho {
11509347473cSLoc Ho 	struct edac_device_ctl_info *edac_dev = file->private_data;
11519347473cSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
11529347473cSLoc Ho 
11539347473cSLoc Ho 	/* Generate all errors */
11549347473cSLoc Ho 	writel(0xFFFFFFFF, ctx->dev_csr + L3C_ESR);
11559347473cSLoc Ho 	return count;
11569347473cSLoc Ho }
11579347473cSLoc Ho 
11589347473cSLoc Ho static const struct file_operations xgene_edac_l3_debug_inject_fops = {
11599347473cSLoc Ho 	.open = simple_open,
11609347473cSLoc Ho 	.write = xgene_edac_l3_inject_ctrl_write,
11619347473cSLoc Ho 	.llseek = generic_file_llseek
11629347473cSLoc Ho };
11639347473cSLoc Ho 
11649347473cSLoc Ho static void
xgene_edac_l3_create_debugfs_nodes(struct edac_device_ctl_info * edac_dev)11659347473cSLoc Ho xgene_edac_l3_create_debugfs_nodes(struct edac_device_ctl_info *edac_dev)
11669347473cSLoc Ho {
11679347473cSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
11689347473cSLoc Ho 	struct dentry *dbgfs_dir;
11699347473cSLoc Ho 	char name[10];
11709347473cSLoc Ho 
11719347473cSLoc Ho 	if (!IS_ENABLED(CONFIG_EDAC_DEBUG) || !ctx->edac->dfs)
11729347473cSLoc Ho 		return;
11739347473cSLoc Ho 
11749347473cSLoc Ho 	snprintf(name, sizeof(name), "l3c%d", ctx->edac_idx);
11759347473cSLoc Ho 	dbgfs_dir = edac_debugfs_create_dir_at(name, ctx->edac->dfs);
11769347473cSLoc Ho 	if (!dbgfs_dir)
11779347473cSLoc Ho 		return;
11789347473cSLoc Ho 
11799347473cSLoc Ho 	debugfs_create_file("l3_inject_ctrl", S_IWUSR, dbgfs_dir, edac_dev,
11809347473cSLoc Ho 			    &xgene_edac_l3_debug_inject_fops);
11819347473cSLoc Ho }
11829347473cSLoc Ho 
xgene_edac_l3_add(struct xgene_edac * edac,struct device_node * np,int version)11839347473cSLoc Ho static int xgene_edac_l3_add(struct xgene_edac *edac, struct device_node *np,
11849347473cSLoc Ho 			     int version)
11859347473cSLoc Ho {
11869347473cSLoc Ho 	struct edac_device_ctl_info *edac_dev;
11879347473cSLoc Ho 	struct xgene_edac_dev_ctx *ctx;
11889347473cSLoc Ho 	struct resource res;
11899347473cSLoc Ho 	void __iomem *dev_csr;
11909347473cSLoc Ho 	int edac_idx;
11919347473cSLoc Ho 	int rc = 0;
11929347473cSLoc Ho 
11939347473cSLoc Ho 	if (!devres_open_group(edac->dev, xgene_edac_l3_add, GFP_KERNEL))
11949347473cSLoc Ho 		return -ENOMEM;
11959347473cSLoc Ho 
11969347473cSLoc Ho 	rc = of_address_to_resource(np, 0, &res);
11979347473cSLoc Ho 	if (rc < 0) {
11989347473cSLoc Ho 		dev_err(edac->dev, "no L3 resource address\n");
11999347473cSLoc Ho 		goto err_release_group;
12009347473cSLoc Ho 	}
12019347473cSLoc Ho 	dev_csr = devm_ioremap_resource(edac->dev, &res);
12029347473cSLoc Ho 	if (IS_ERR(dev_csr)) {
12039347473cSLoc Ho 		dev_err(edac->dev,
12049347473cSLoc Ho 			"devm_ioremap_resource failed for L3 resource address\n");
12059347473cSLoc Ho 		rc = PTR_ERR(dev_csr);
12069347473cSLoc Ho 		goto err_release_group;
12079347473cSLoc Ho 	}
12089347473cSLoc Ho 
12099347473cSLoc Ho 	edac_idx = edac_device_alloc_index();
12109347473cSLoc Ho 	edac_dev = edac_device_alloc_ctl_info(sizeof(*ctx),
12119347473cSLoc Ho 					      "l3c", 1, "l3c", 1, 0, NULL, 0,
12129347473cSLoc Ho 					      edac_idx);
12139347473cSLoc Ho 	if (!edac_dev) {
12149347473cSLoc Ho 		rc = -ENOMEM;
12159347473cSLoc Ho 		goto err_release_group;
12169347473cSLoc Ho 	}
12179347473cSLoc Ho 
12189347473cSLoc Ho 	ctx = edac_dev->pvt_info;
12199347473cSLoc Ho 	ctx->dev_csr = dev_csr;
12209347473cSLoc Ho 	ctx->name = "xgene_l3_err";
12219347473cSLoc Ho 	ctx->edac_idx = edac_idx;
12229347473cSLoc Ho 	ctx->edac = edac;
12239347473cSLoc Ho 	ctx->edac_dev = edac_dev;
12249347473cSLoc Ho 	ctx->ddev = *edac->dev;
12259347473cSLoc Ho 	ctx->version = version;
12269347473cSLoc Ho 	edac_dev->dev = &ctx->ddev;
12279347473cSLoc Ho 	edac_dev->ctl_name = ctx->name;
12289347473cSLoc Ho 	edac_dev->dev_name = ctx->name;
12299347473cSLoc Ho 	edac_dev->mod_name = EDAC_MOD_STR;
12309347473cSLoc Ho 
12319347473cSLoc Ho 	if (edac_op_state == EDAC_OPSTATE_POLL)
12329347473cSLoc Ho 		edac_dev->edac_check = xgene_edac_l3_check;
12339347473cSLoc Ho 
12349347473cSLoc Ho 	xgene_edac_l3_create_debugfs_nodes(edac_dev);
12359347473cSLoc Ho 
12369347473cSLoc Ho 	rc = edac_device_add_device(edac_dev);
12379347473cSLoc Ho 	if (rc > 0) {
12389347473cSLoc Ho 		dev_err(edac->dev, "failed edac_device_add_device()\n");
12399347473cSLoc Ho 		rc = -ENOMEM;
12409347473cSLoc Ho 		goto err_ctl_free;
12419347473cSLoc Ho 	}
12429347473cSLoc Ho 
12439347473cSLoc Ho 	if (edac_op_state == EDAC_OPSTATE_INT)
12449347473cSLoc Ho 		edac_dev->op_state = OP_RUNNING_INTERRUPT;
12459347473cSLoc Ho 
12469347473cSLoc Ho 	list_add(&ctx->next, &edac->l3s);
12479347473cSLoc Ho 
12489347473cSLoc Ho 	xgene_edac_l3_hw_init(edac_dev, 1);
12499347473cSLoc Ho 
12509347473cSLoc Ho 	devres_remove_group(edac->dev, xgene_edac_l3_add);
12519347473cSLoc Ho 
12529347473cSLoc Ho 	dev_info(edac->dev, "X-Gene EDAC L3 registered\n");
12539347473cSLoc Ho 	return 0;
12549347473cSLoc Ho 
12559347473cSLoc Ho err_ctl_free:
12569347473cSLoc Ho 	edac_device_free_ctl_info(edac_dev);
12579347473cSLoc Ho err_release_group:
12589347473cSLoc Ho 	devres_release_group(edac->dev, xgene_edac_l3_add);
12599347473cSLoc Ho 	return rc;
12609347473cSLoc Ho }
12619347473cSLoc Ho 
xgene_edac_l3_remove(struct xgene_edac_dev_ctx * l3)12629347473cSLoc Ho static int xgene_edac_l3_remove(struct xgene_edac_dev_ctx *l3)
12639347473cSLoc Ho {
12649347473cSLoc Ho 	struct edac_device_ctl_info *edac_dev = l3->edac_dev;
12659347473cSLoc Ho 
12669347473cSLoc Ho 	xgene_edac_l3_hw_init(edac_dev, 0);
12679347473cSLoc Ho 	edac_device_del_device(l3->edac->dev);
12689347473cSLoc Ho 	edac_device_free_ctl_info(edac_dev);
12699347473cSLoc Ho 	return 0;
12709347473cSLoc Ho }
12719347473cSLoc Ho 
1272f864b79bSLoc Ho /* SoC error device */
1273f864b79bSLoc Ho #define IOBAXIS0TRANSERRINTSTS		0x0000
1274f864b79bSLoc Ho #define  IOBAXIS0_M_ILLEGAL_ACCESS_MASK	BIT(1)
1275f864b79bSLoc Ho #define  IOBAXIS0_ILLEGAL_ACCESS_MASK	BIT(0)
1276f864b79bSLoc Ho #define IOBAXIS0TRANSERRINTMSK		0x0004
1277f864b79bSLoc Ho #define IOBAXIS0TRANSERRREQINFOL	0x0008
1278f864b79bSLoc Ho #define IOBAXIS0TRANSERRREQINFOH	0x000c
1279f864b79bSLoc Ho #define  REQTYPE_RD(src)		(((src) & BIT(0)))
1280f864b79bSLoc Ho #define  ERRADDRH_RD(src)		(((src) & 0xffc00000) >> 22)
1281f864b79bSLoc Ho #define IOBAXIS1TRANSERRINTSTS		0x0010
1282f864b79bSLoc Ho #define IOBAXIS1TRANSERRINTMSK		0x0014
1283f864b79bSLoc Ho #define IOBAXIS1TRANSERRREQINFOL	0x0018
1284f864b79bSLoc Ho #define IOBAXIS1TRANSERRREQINFOH	0x001c
1285f864b79bSLoc Ho #define IOBPATRANSERRINTSTS		0x0020
1286f864b79bSLoc Ho #define  IOBPA_M_REQIDRAM_CORRUPT_MASK	BIT(7)
1287f864b79bSLoc Ho #define  IOBPA_REQIDRAM_CORRUPT_MASK	BIT(6)
1288f864b79bSLoc Ho #define  IOBPA_M_TRANS_CORRUPT_MASK	BIT(5)
1289f864b79bSLoc Ho #define  IOBPA_TRANS_CORRUPT_MASK	BIT(4)
1290f864b79bSLoc Ho #define  IOBPA_M_WDATA_CORRUPT_MASK	BIT(3)
1291f864b79bSLoc Ho #define  IOBPA_WDATA_CORRUPT_MASK	BIT(2)
1292f864b79bSLoc Ho #define  IOBPA_M_RDATA_CORRUPT_MASK	BIT(1)
1293f864b79bSLoc Ho #define  IOBPA_RDATA_CORRUPT_MASK	BIT(0)
1294f864b79bSLoc Ho #define IOBBATRANSERRINTSTS		0x0030
1295f864b79bSLoc Ho #define  M_ILLEGAL_ACCESS_MASK		BIT(15)
1296f864b79bSLoc Ho #define  ILLEGAL_ACCESS_MASK		BIT(14)
1297f864b79bSLoc Ho #define  M_WIDRAM_CORRUPT_MASK		BIT(13)
1298f864b79bSLoc Ho #define  WIDRAM_CORRUPT_MASK		BIT(12)
1299f864b79bSLoc Ho #define  M_RIDRAM_CORRUPT_MASK		BIT(11)
1300f864b79bSLoc Ho #define  RIDRAM_CORRUPT_MASK		BIT(10)
1301f864b79bSLoc Ho #define  M_TRANS_CORRUPT_MASK		BIT(9)
1302f864b79bSLoc Ho #define  TRANS_CORRUPT_MASK		BIT(8)
1303f864b79bSLoc Ho #define  M_WDATA_CORRUPT_MASK		BIT(7)
1304f864b79bSLoc Ho #define  WDATA_CORRUPT_MASK		BIT(6)
1305f864b79bSLoc Ho #define  M_RBM_POISONED_REQ_MASK	BIT(5)
1306f864b79bSLoc Ho #define  RBM_POISONED_REQ_MASK		BIT(4)
1307f864b79bSLoc Ho #define  M_XGIC_POISONED_REQ_MASK	BIT(3)
1308f864b79bSLoc Ho #define  XGIC_POISONED_REQ_MASK		BIT(2)
1309f864b79bSLoc Ho #define  M_WRERR_RESP_MASK		BIT(1)
1310f864b79bSLoc Ho #define  WRERR_RESP_MASK		BIT(0)
1311f864b79bSLoc Ho #define IOBBATRANSERRREQINFOL		0x0038
1312f864b79bSLoc Ho #define IOBBATRANSERRREQINFOH		0x003c
1313f864b79bSLoc Ho #define  REQTYPE_F2_RD(src)		((src) & BIT(0))
1314f864b79bSLoc Ho #define  ERRADDRH_F2_RD(src)		(((src) & 0xffc00000) >> 22)
1315f864b79bSLoc Ho #define IOBBATRANSERRCSWREQID		0x0040
1316f864b79bSLoc Ho #define XGICTRANSERRINTSTS		0x0050
1317f864b79bSLoc Ho #define  M_WR_ACCESS_ERR_MASK		BIT(3)
1318f864b79bSLoc Ho #define  WR_ACCESS_ERR_MASK		BIT(2)
1319f864b79bSLoc Ho #define  M_RD_ACCESS_ERR_MASK		BIT(1)
1320f864b79bSLoc Ho #define  RD_ACCESS_ERR_MASK		BIT(0)
1321f864b79bSLoc Ho #define XGICTRANSERRINTMSK		0x0054
1322f864b79bSLoc Ho #define XGICTRANSERRREQINFO		0x0058
1323f864b79bSLoc Ho #define  REQTYPE_MASK			BIT(26)
1324f864b79bSLoc Ho #define  ERRADDR_RD(src)		((src) & 0x03ffffff)
1325f864b79bSLoc Ho #define GLBL_ERR_STS			0x0800
1326f864b79bSLoc Ho #define  MDED_ERR_MASK			BIT(3)
1327f864b79bSLoc Ho #define  DED_ERR_MASK			BIT(2)
1328f864b79bSLoc Ho #define  MSEC_ERR_MASK			BIT(1)
1329f864b79bSLoc Ho #define  SEC_ERR_MASK			BIT(0)
1330f864b79bSLoc Ho #define GLBL_SEC_ERRL			0x0810
1331f864b79bSLoc Ho #define GLBL_SEC_ERRH			0x0818
1332f864b79bSLoc Ho #define GLBL_MSEC_ERRL			0x0820
1333f864b79bSLoc Ho #define GLBL_MSEC_ERRH			0x0828
1334f864b79bSLoc Ho #define GLBL_DED_ERRL			0x0830
1335f864b79bSLoc Ho #define GLBL_DED_ERRLMASK		0x0834
1336f864b79bSLoc Ho #define GLBL_DED_ERRH			0x0838
1337f864b79bSLoc Ho #define GLBL_DED_ERRHMASK		0x083c
1338f864b79bSLoc Ho #define GLBL_MDED_ERRL			0x0840
1339f864b79bSLoc Ho #define GLBL_MDED_ERRLMASK		0x0844
1340f864b79bSLoc Ho #define GLBL_MDED_ERRH			0x0848
1341f864b79bSLoc Ho #define GLBL_MDED_ERRHMASK		0x084c
1342f864b79bSLoc Ho 
13434d67e3ceSLoc Ho /* IO Bus Registers */
13444d67e3ceSLoc Ho #define RBCSR				0x0000
13454d67e3ceSLoc Ho #define STICKYERR_MASK			BIT(0)
13464d67e3ceSLoc Ho #define RBEIR				0x0008
13474d67e3ceSLoc Ho #define AGENT_OFFLINE_ERR_MASK		BIT(30)
13484d67e3ceSLoc Ho #define UNIMPL_RBPAGE_ERR_MASK		BIT(29)
13494d67e3ceSLoc Ho #define WORD_ALIGNED_ERR_MASK		BIT(28)
13504d67e3ceSLoc Ho #define PAGE_ACCESS_ERR_MASK		BIT(27)
13514d67e3ceSLoc Ho #define WRITE_ACCESS_MASK		BIT(26)
13524d67e3ceSLoc Ho 
1353f864b79bSLoc Ho static const char * const soc_mem_err_v1[] = {
1354f864b79bSLoc Ho 	"10GbE0",
1355f864b79bSLoc Ho 	"10GbE1",
1356f864b79bSLoc Ho 	"Security",
1357f864b79bSLoc Ho 	"SATA45",
1358f864b79bSLoc Ho 	"SATA23/ETH23",
1359f864b79bSLoc Ho 	"SATA01/ETH01",
1360f864b79bSLoc Ho 	"USB1",
1361f864b79bSLoc Ho 	"USB0",
1362f864b79bSLoc Ho 	"QML",
1363f864b79bSLoc Ho 	"QM0",
1364f864b79bSLoc Ho 	"QM1 (XGbE01)",
1365f864b79bSLoc Ho 	"PCIE4",
1366f864b79bSLoc Ho 	"PCIE3",
1367f864b79bSLoc Ho 	"PCIE2",
1368f864b79bSLoc Ho 	"PCIE1",
1369f864b79bSLoc Ho 	"PCIE0",
1370f864b79bSLoc Ho 	"CTX Manager",
1371f864b79bSLoc Ho 	"OCM",
1372f864b79bSLoc Ho 	"1GbE",
1373f864b79bSLoc Ho 	"CLE",
1374f864b79bSLoc Ho 	"AHBC",
1375f864b79bSLoc Ho 	"PktDMA",
1376f864b79bSLoc Ho 	"GFC",
1377f864b79bSLoc Ho 	"MSLIM",
1378f864b79bSLoc Ho 	"10GbE2",
1379f864b79bSLoc Ho 	"10GbE3",
1380f864b79bSLoc Ho 	"QM2 (XGbE23)",
1381f864b79bSLoc Ho 	"IOB",
1382f864b79bSLoc Ho 	"unknown",
1383f864b79bSLoc Ho 	"unknown",
1384f864b79bSLoc Ho 	"unknown",
1385f864b79bSLoc Ho 	"unknown",
1386f864b79bSLoc Ho };
1387f864b79bSLoc Ho 
xgene_edac_iob_gic_report(struct edac_device_ctl_info * edac_dev)1388f864b79bSLoc Ho static void xgene_edac_iob_gic_report(struct edac_device_ctl_info *edac_dev)
1389f864b79bSLoc Ho {
1390f864b79bSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
1391f864b79bSLoc Ho 	u32 err_addr_lo;
1392f864b79bSLoc Ho 	u32 err_addr_hi;
1393f864b79bSLoc Ho 	u32 reg;
1394f864b79bSLoc Ho 	u32 info;
1395f864b79bSLoc Ho 
1396f864b79bSLoc Ho 	/* GIC transaction error interrupt */
1397f864b79bSLoc Ho 	reg = readl(ctx->dev_csr + XGICTRANSERRINTSTS);
1398f864b79bSLoc Ho 	if (!reg)
1399f864b79bSLoc Ho 		goto chk_iob_err;
1400f864b79bSLoc Ho 	dev_err(edac_dev->dev, "XGIC transaction error\n");
1401f864b79bSLoc Ho 	if (reg & RD_ACCESS_ERR_MASK)
1402f864b79bSLoc Ho 		dev_err(edac_dev->dev, "XGIC read size error\n");
1403f864b79bSLoc Ho 	if (reg & M_RD_ACCESS_ERR_MASK)
1404f864b79bSLoc Ho 		dev_err(edac_dev->dev, "Multiple XGIC read size error\n");
1405f864b79bSLoc Ho 	if (reg & WR_ACCESS_ERR_MASK)
1406f864b79bSLoc Ho 		dev_err(edac_dev->dev, "XGIC write size error\n");
1407f864b79bSLoc Ho 	if (reg & M_WR_ACCESS_ERR_MASK)
1408f864b79bSLoc Ho 		dev_err(edac_dev->dev, "Multiple XGIC write size error\n");
1409f864b79bSLoc Ho 	info = readl(ctx->dev_csr + XGICTRANSERRREQINFO);
1410f864b79bSLoc Ho 	dev_err(edac_dev->dev, "XGIC %s access @ 0x%08X (0x%08X)\n",
1411f864b79bSLoc Ho 		info & REQTYPE_MASK ? "read" : "write", ERRADDR_RD(info),
1412f864b79bSLoc Ho 		info);
1413f864b79bSLoc Ho 	writel(reg, ctx->dev_csr + XGICTRANSERRINTSTS);
1414f864b79bSLoc Ho 
1415f864b79bSLoc Ho chk_iob_err:
1416f864b79bSLoc Ho 	/* IOB memory error */
1417f864b79bSLoc Ho 	reg = readl(ctx->dev_csr + GLBL_ERR_STS);
1418f864b79bSLoc Ho 	if (!reg)
1419f864b79bSLoc Ho 		return;
1420f864b79bSLoc Ho 	if (reg & SEC_ERR_MASK) {
1421f864b79bSLoc Ho 		err_addr_lo = readl(ctx->dev_csr + GLBL_SEC_ERRL);
1422f864b79bSLoc Ho 		err_addr_hi = readl(ctx->dev_csr + GLBL_SEC_ERRH);
1423f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1424f864b79bSLoc Ho 			"IOB single-bit correctable memory at 0x%08X.%08X error\n",
1425f864b79bSLoc Ho 			err_addr_lo, err_addr_hi);
1426f864b79bSLoc Ho 		writel(err_addr_lo, ctx->dev_csr + GLBL_SEC_ERRL);
1427f864b79bSLoc Ho 		writel(err_addr_hi, ctx->dev_csr + GLBL_SEC_ERRH);
1428f864b79bSLoc Ho 	}
1429f864b79bSLoc Ho 	if (reg & MSEC_ERR_MASK) {
1430f864b79bSLoc Ho 		err_addr_lo = readl(ctx->dev_csr + GLBL_MSEC_ERRL);
1431f864b79bSLoc Ho 		err_addr_hi = readl(ctx->dev_csr + GLBL_MSEC_ERRH);
1432f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1433f864b79bSLoc Ho 			"IOB multiple single-bit correctable memory at 0x%08X.%08X error\n",
1434f864b79bSLoc Ho 			err_addr_lo, err_addr_hi);
1435f864b79bSLoc Ho 		writel(err_addr_lo, ctx->dev_csr + GLBL_MSEC_ERRL);
1436f864b79bSLoc Ho 		writel(err_addr_hi, ctx->dev_csr + GLBL_MSEC_ERRH);
1437f864b79bSLoc Ho 	}
1438f864b79bSLoc Ho 	if (reg & (SEC_ERR_MASK | MSEC_ERR_MASK))
1439f864b79bSLoc Ho 		edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
1440f864b79bSLoc Ho 
1441f864b79bSLoc Ho 	if (reg & DED_ERR_MASK) {
1442f864b79bSLoc Ho 		err_addr_lo = readl(ctx->dev_csr + GLBL_DED_ERRL);
1443f864b79bSLoc Ho 		err_addr_hi = readl(ctx->dev_csr + GLBL_DED_ERRH);
1444f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1445f864b79bSLoc Ho 			"IOB double-bit uncorrectable memory at 0x%08X.%08X error\n",
1446f864b79bSLoc Ho 			err_addr_lo, err_addr_hi);
1447f864b79bSLoc Ho 		writel(err_addr_lo, ctx->dev_csr + GLBL_DED_ERRL);
1448f864b79bSLoc Ho 		writel(err_addr_hi, ctx->dev_csr + GLBL_DED_ERRH);
1449f864b79bSLoc Ho 	}
1450f864b79bSLoc Ho 	if (reg & MDED_ERR_MASK) {
1451f864b79bSLoc Ho 		err_addr_lo = readl(ctx->dev_csr + GLBL_MDED_ERRL);
1452f864b79bSLoc Ho 		err_addr_hi = readl(ctx->dev_csr + GLBL_MDED_ERRH);
1453f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1454f864b79bSLoc Ho 			"Multiple IOB double-bit uncorrectable memory at 0x%08X.%08X error\n",
1455f864b79bSLoc Ho 			err_addr_lo, err_addr_hi);
1456f864b79bSLoc Ho 		writel(err_addr_lo, ctx->dev_csr + GLBL_MDED_ERRL);
1457f864b79bSLoc Ho 		writel(err_addr_hi, ctx->dev_csr + GLBL_MDED_ERRH);
1458f864b79bSLoc Ho 	}
1459f864b79bSLoc Ho 	if (reg & (DED_ERR_MASK | MDED_ERR_MASK))
1460f864b79bSLoc Ho 		edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
1461f864b79bSLoc Ho }
1462f864b79bSLoc Ho 
xgene_edac_rb_report(struct edac_device_ctl_info * edac_dev)1463f864b79bSLoc Ho static void xgene_edac_rb_report(struct edac_device_ctl_info *edac_dev)
1464f864b79bSLoc Ho {
1465f864b79bSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
1466f864b79bSLoc Ho 	u32 err_addr_lo;
1467f864b79bSLoc Ho 	u32 err_addr_hi;
1468f864b79bSLoc Ho 	u32 reg;
1469f864b79bSLoc Ho 
14704d67e3ceSLoc Ho 	/* If the register bus resource isn't available, just skip it */
14714d67e3ceSLoc Ho 	if (!ctx->edac->rb_map)
14724d67e3ceSLoc Ho 		goto rb_skip;
14734d67e3ceSLoc Ho 
14744d67e3ceSLoc Ho 	/*
14754d67e3ceSLoc Ho 	 * Check RB access errors
14764d67e3ceSLoc Ho 	 * 1. Out of range
14774d67e3ceSLoc Ho 	 * 2. Un-implemented page
14784d67e3ceSLoc Ho 	 * 3. Un-aligned access
14794d67e3ceSLoc Ho 	 * 4. Offline slave IP
14804d67e3ceSLoc Ho 	 */
14814d67e3ceSLoc Ho 	if (regmap_read(ctx->edac->rb_map, RBCSR, &reg))
14824d67e3ceSLoc Ho 		return;
14834d67e3ceSLoc Ho 	if (reg & STICKYERR_MASK) {
14844d67e3ceSLoc Ho 		bool write;
14854d67e3ceSLoc Ho 
14864d67e3ceSLoc Ho 		dev_err(edac_dev->dev, "IOB bus access error(s)\n");
14874d67e3ceSLoc Ho 		if (regmap_read(ctx->edac->rb_map, RBEIR, &reg))
14884d67e3ceSLoc Ho 			return;
14894d67e3ceSLoc Ho 		write = reg & WRITE_ACCESS_MASK ? 1 : 0;
14904d67e3ceSLoc Ho 		if (reg & AGENT_OFFLINE_ERR_MASK)
14914d67e3ceSLoc Ho 			dev_err(edac_dev->dev,
14924d67e3ceSLoc Ho 				"IOB bus %s access to offline agent error\n",
14934d67e3ceSLoc Ho 				write ? "write" : "read");
14944d67e3ceSLoc Ho 		if (reg & UNIMPL_RBPAGE_ERR_MASK)
14954d67e3ceSLoc Ho 			dev_err(edac_dev->dev,
14964d67e3ceSLoc Ho 				"IOB bus %s access to unimplemented page error\n",
14974d67e3ceSLoc Ho 				write ? "write" : "read");
14984d67e3ceSLoc Ho 		if (reg & WORD_ALIGNED_ERR_MASK)
14994d67e3ceSLoc Ho 			dev_err(edac_dev->dev,
15004d67e3ceSLoc Ho 				"IOB bus %s word aligned access error\n",
15014d67e3ceSLoc Ho 				write ? "write" : "read");
15024d67e3ceSLoc Ho 		if (reg & PAGE_ACCESS_ERR_MASK)
15034d67e3ceSLoc Ho 			dev_err(edac_dev->dev,
15044d67e3ceSLoc Ho 				"IOB bus %s to page out of range access error\n",
15054d67e3ceSLoc Ho 				write ? "write" : "read");
15064d67e3ceSLoc Ho 		if (regmap_write(ctx->edac->rb_map, RBEIR, 0))
15074d67e3ceSLoc Ho 			return;
15084d67e3ceSLoc Ho 		if (regmap_write(ctx->edac->rb_map, RBCSR, 0))
15094d67e3ceSLoc Ho 			return;
15104d67e3ceSLoc Ho 	}
15114d67e3ceSLoc Ho rb_skip:
15124d67e3ceSLoc Ho 
1513f864b79bSLoc Ho 	/* IOB Bridge agent transaction error interrupt */
1514f864b79bSLoc Ho 	reg = readl(ctx->dev_csr + IOBBATRANSERRINTSTS);
1515f864b79bSLoc Ho 	if (!reg)
1516f864b79bSLoc Ho 		return;
1517f864b79bSLoc Ho 
1518f864b79bSLoc Ho 	dev_err(edac_dev->dev, "IOB bridge agent (BA) transaction error\n");
1519f864b79bSLoc Ho 	if (reg & WRERR_RESP_MASK)
1520f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB BA write response error\n");
1521f864b79bSLoc Ho 	if (reg & M_WRERR_RESP_MASK)
1522f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1523f864b79bSLoc Ho 			"Multiple IOB BA write response error\n");
1524f864b79bSLoc Ho 	if (reg & XGIC_POISONED_REQ_MASK)
1525f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB BA XGIC poisoned write error\n");
1526f864b79bSLoc Ho 	if (reg & M_XGIC_POISONED_REQ_MASK)
1527f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1528f864b79bSLoc Ho 			"Multiple IOB BA XGIC poisoned write error\n");
1529f864b79bSLoc Ho 	if (reg & RBM_POISONED_REQ_MASK)
1530f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB BA RBM poisoned write error\n");
1531f864b79bSLoc Ho 	if (reg & M_RBM_POISONED_REQ_MASK)
1532f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1533f864b79bSLoc Ho 			"Multiple IOB BA RBM poisoned write error\n");
1534f864b79bSLoc Ho 	if (reg & WDATA_CORRUPT_MASK)
1535f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB BA write error\n");
1536f864b79bSLoc Ho 	if (reg & M_WDATA_CORRUPT_MASK)
1537f864b79bSLoc Ho 		dev_err(edac_dev->dev, "Multiple IOB BA write error\n");
1538f864b79bSLoc Ho 	if (reg & TRANS_CORRUPT_MASK)
1539f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB BA transaction error\n");
1540f864b79bSLoc Ho 	if (reg & M_TRANS_CORRUPT_MASK)
1541f864b79bSLoc Ho 		dev_err(edac_dev->dev, "Multiple IOB BA transaction error\n");
1542f864b79bSLoc Ho 	if (reg & RIDRAM_CORRUPT_MASK)
1543f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1544f864b79bSLoc Ho 			"IOB BA RDIDRAM read transaction ID error\n");
1545f864b79bSLoc Ho 	if (reg & M_RIDRAM_CORRUPT_MASK)
1546f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1547f864b79bSLoc Ho 			"Multiple IOB BA RDIDRAM read transaction ID error\n");
1548f864b79bSLoc Ho 	if (reg & WIDRAM_CORRUPT_MASK)
1549f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1550f864b79bSLoc Ho 			"IOB BA RDIDRAM write transaction ID error\n");
1551f864b79bSLoc Ho 	if (reg & M_WIDRAM_CORRUPT_MASK)
1552f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1553f864b79bSLoc Ho 			"Multiple IOB BA RDIDRAM write transaction ID error\n");
1554f864b79bSLoc Ho 	if (reg & ILLEGAL_ACCESS_MASK)
1555f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1556f864b79bSLoc Ho 			"IOB BA XGIC/RB illegal access error\n");
1557f864b79bSLoc Ho 	if (reg & M_ILLEGAL_ACCESS_MASK)
1558f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1559f864b79bSLoc Ho 			"Multiple IOB BA XGIC/RB illegal access error\n");
1560f864b79bSLoc Ho 
1561f864b79bSLoc Ho 	err_addr_lo = readl(ctx->dev_csr + IOBBATRANSERRREQINFOL);
1562f864b79bSLoc Ho 	err_addr_hi = readl(ctx->dev_csr + IOBBATRANSERRREQINFOH);
1563f864b79bSLoc Ho 	dev_err(edac_dev->dev, "IOB BA %s access at 0x%02X.%08X (0x%08X)\n",
1564f864b79bSLoc Ho 		REQTYPE_F2_RD(err_addr_hi) ? "read" : "write",
1565f864b79bSLoc Ho 		ERRADDRH_F2_RD(err_addr_hi), err_addr_lo, err_addr_hi);
1566f864b79bSLoc Ho 	if (reg & WRERR_RESP_MASK)
1567f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB BA requestor ID 0x%08X\n",
1568f864b79bSLoc Ho 			readl(ctx->dev_csr + IOBBATRANSERRCSWREQID));
1569f864b79bSLoc Ho 	writel(reg, ctx->dev_csr + IOBBATRANSERRINTSTS);
1570f864b79bSLoc Ho }
1571f864b79bSLoc Ho 
xgene_edac_pa_report(struct edac_device_ctl_info * edac_dev)1572f864b79bSLoc Ho static void xgene_edac_pa_report(struct edac_device_ctl_info *edac_dev)
1573f864b79bSLoc Ho {
1574f864b79bSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
1575f864b79bSLoc Ho 	u32 err_addr_lo;
1576f864b79bSLoc Ho 	u32 err_addr_hi;
1577f864b79bSLoc Ho 	u32 reg;
1578f864b79bSLoc Ho 
1579f864b79bSLoc Ho 	/* IOB Processing agent transaction error interrupt */
1580f864b79bSLoc Ho 	reg = readl(ctx->dev_csr + IOBPATRANSERRINTSTS);
1581f864b79bSLoc Ho 	if (!reg)
1582f864b79bSLoc Ho 		goto chk_iob_axi0;
15834bd035eaSColin Ian King 	dev_err(edac_dev->dev, "IOB processing agent (PA) transaction error\n");
1584f864b79bSLoc Ho 	if (reg & IOBPA_RDATA_CORRUPT_MASK)
1585f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB PA read data RAM error\n");
1586f864b79bSLoc Ho 	if (reg & IOBPA_M_RDATA_CORRUPT_MASK)
1587f864b79bSLoc Ho 		dev_err(edac_dev->dev,
15888176170eSColin Ian King 			"Multiple IOB PA read data RAM error\n");
1589f864b79bSLoc Ho 	if (reg & IOBPA_WDATA_CORRUPT_MASK)
1590f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB PA write data RAM error\n");
1591f864b79bSLoc Ho 	if (reg & IOBPA_M_WDATA_CORRUPT_MASK)
1592f864b79bSLoc Ho 		dev_err(edac_dev->dev,
15938176170eSColin Ian King 			"Multiple IOB PA write data RAM error\n");
1594f864b79bSLoc Ho 	if (reg & IOBPA_TRANS_CORRUPT_MASK)
1595f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB PA transaction error\n");
1596f864b79bSLoc Ho 	if (reg & IOBPA_M_TRANS_CORRUPT_MASK)
15978176170eSColin Ian King 		dev_err(edac_dev->dev, "Multiple IOB PA transaction error\n");
1598f864b79bSLoc Ho 	if (reg & IOBPA_REQIDRAM_CORRUPT_MASK)
1599f864b79bSLoc Ho 		dev_err(edac_dev->dev, "IOB PA transaction ID RAM error\n");
1600f864b79bSLoc Ho 	if (reg & IOBPA_M_REQIDRAM_CORRUPT_MASK)
1601f864b79bSLoc Ho 		dev_err(edac_dev->dev,
1602f864b79bSLoc Ho 			"Multiple IOB PA transaction ID RAM error\n");
1603f864b79bSLoc Ho 	writel(reg, ctx->dev_csr + IOBPATRANSERRINTSTS);
1604f864b79bSLoc Ho 
1605f864b79bSLoc Ho chk_iob_axi0:
1606f864b79bSLoc Ho 	/* IOB AXI0 Error */
1607f864b79bSLoc Ho 	reg = readl(ctx->dev_csr + IOBAXIS0TRANSERRINTSTS);
1608f864b79bSLoc Ho 	if (!reg)
1609f864b79bSLoc Ho 		goto chk_iob_axi1;
1610f864b79bSLoc Ho 	err_addr_lo = readl(ctx->dev_csr + IOBAXIS0TRANSERRREQINFOL);
1611f864b79bSLoc Ho 	err_addr_hi = readl(ctx->dev_csr + IOBAXIS0TRANSERRREQINFOH);
1612f864b79bSLoc Ho 	dev_err(edac_dev->dev,
1613f864b79bSLoc Ho 		"%sAXI slave 0 illegal %s access @ 0x%02X.%08X (0x%08X)\n",
1614f864b79bSLoc Ho 		reg & IOBAXIS0_M_ILLEGAL_ACCESS_MASK ? "Multiple " : "",
1615f864b79bSLoc Ho 		REQTYPE_RD(err_addr_hi) ? "read" : "write",
1616f864b79bSLoc Ho 		ERRADDRH_RD(err_addr_hi), err_addr_lo, err_addr_hi);
1617f864b79bSLoc Ho 	writel(reg, ctx->dev_csr + IOBAXIS0TRANSERRINTSTS);
1618f864b79bSLoc Ho 
1619f864b79bSLoc Ho chk_iob_axi1:
1620f864b79bSLoc Ho 	/* IOB AXI1 Error */
1621f864b79bSLoc Ho 	reg = readl(ctx->dev_csr + IOBAXIS1TRANSERRINTSTS);
1622f864b79bSLoc Ho 	if (!reg)
1623f864b79bSLoc Ho 		return;
1624f864b79bSLoc Ho 	err_addr_lo = readl(ctx->dev_csr + IOBAXIS1TRANSERRREQINFOL);
1625f864b79bSLoc Ho 	err_addr_hi = readl(ctx->dev_csr + IOBAXIS1TRANSERRREQINFOH);
1626f864b79bSLoc Ho 	dev_err(edac_dev->dev,
1627f864b79bSLoc Ho 		"%sAXI slave 1 illegal %s access @ 0x%02X.%08X (0x%08X)\n",
1628f864b79bSLoc Ho 		reg & IOBAXIS0_M_ILLEGAL_ACCESS_MASK ? "Multiple " : "",
1629f864b79bSLoc Ho 		REQTYPE_RD(err_addr_hi) ? "read" : "write",
1630f864b79bSLoc Ho 		ERRADDRH_RD(err_addr_hi), err_addr_lo, err_addr_hi);
1631f864b79bSLoc Ho 	writel(reg, ctx->dev_csr + IOBAXIS1TRANSERRINTSTS);
1632f864b79bSLoc Ho }
1633f864b79bSLoc Ho 
xgene_edac_soc_check(struct edac_device_ctl_info * edac_dev)1634f864b79bSLoc Ho static void xgene_edac_soc_check(struct edac_device_ctl_info *edac_dev)
1635f864b79bSLoc Ho {
1636f864b79bSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
1637f864b79bSLoc Ho 	const char * const *soc_mem_err = NULL;
1638f864b79bSLoc Ho 	u32 pcp_hp_stat;
1639f864b79bSLoc Ho 	u32 pcp_lp_stat;
1640f864b79bSLoc Ho 	u32 reg;
1641f864b79bSLoc Ho 	int i;
1642f864b79bSLoc Ho 
1643f864b79bSLoc Ho 	xgene_edac_pcp_rd(ctx->edac, PCPHPERRINTSTS, &pcp_hp_stat);
1644f864b79bSLoc Ho 	xgene_edac_pcp_rd(ctx->edac, PCPLPERRINTSTS, &pcp_lp_stat);
1645f864b79bSLoc Ho 	xgene_edac_pcp_rd(ctx->edac, MEMERRINTSTS, &reg);
1646f864b79bSLoc Ho 	if (!((pcp_hp_stat & (IOB_PA_ERR_MASK | IOB_BA_ERR_MASK |
1647f864b79bSLoc Ho 			      IOB_XGIC_ERR_MASK | IOB_RB_ERR_MASK)) ||
1648f864b79bSLoc Ho 	      (pcp_lp_stat & CSW_SWITCH_TRACE_ERR_MASK) || reg))
1649f864b79bSLoc Ho 		return;
1650f864b79bSLoc Ho 
1651f864b79bSLoc Ho 	if (pcp_hp_stat & IOB_XGIC_ERR_MASK)
1652f864b79bSLoc Ho 		xgene_edac_iob_gic_report(edac_dev);
1653f864b79bSLoc Ho 
1654f864b79bSLoc Ho 	if (pcp_hp_stat & (IOB_RB_ERR_MASK | IOB_BA_ERR_MASK))
1655f864b79bSLoc Ho 		xgene_edac_rb_report(edac_dev);
1656f864b79bSLoc Ho 
1657f864b79bSLoc Ho 	if (pcp_hp_stat & IOB_PA_ERR_MASK)
1658f864b79bSLoc Ho 		xgene_edac_pa_report(edac_dev);
1659f864b79bSLoc Ho 
1660f864b79bSLoc Ho 	if (pcp_lp_stat & CSW_SWITCH_TRACE_ERR_MASK) {
1661f864b79bSLoc Ho 		dev_info(edac_dev->dev,
1662f864b79bSLoc Ho 			 "CSW switch trace correctable memory parity error\n");
1663f864b79bSLoc Ho 		edac_device_handle_ce(edac_dev, 0, 0, edac_dev->ctl_name);
1664f864b79bSLoc Ho 	}
1665f864b79bSLoc Ho 
1666f864b79bSLoc Ho 	if (!reg)
1667f864b79bSLoc Ho 		return;
1668f864b79bSLoc Ho 	if (ctx->version == 1)
1669f864b79bSLoc Ho 		soc_mem_err = soc_mem_err_v1;
1670f864b79bSLoc Ho 	if (!soc_mem_err) {
1671f864b79bSLoc Ho 		dev_err(edac_dev->dev, "SoC memory parity error 0x%08X\n",
1672f864b79bSLoc Ho 			reg);
1673f864b79bSLoc Ho 		edac_device_handle_ue(edac_dev, 0, 0, edac_dev->ctl_name);
1674f864b79bSLoc Ho 		return;
1675f864b79bSLoc Ho 	}
1676f864b79bSLoc Ho 	for (i = 0; i < 31; i++) {
1677f864b79bSLoc Ho 		if (reg & (1 << i)) {
1678f864b79bSLoc Ho 			dev_err(edac_dev->dev, "%s memory parity error\n",
1679f864b79bSLoc Ho 				soc_mem_err[i]);
1680f864b79bSLoc Ho 			edac_device_handle_ue(edac_dev, 0, 0,
1681f864b79bSLoc Ho 					      edac_dev->ctl_name);
1682f864b79bSLoc Ho 		}
1683f864b79bSLoc Ho 	}
1684f864b79bSLoc Ho }
1685f864b79bSLoc Ho 
xgene_edac_soc_hw_init(struct edac_device_ctl_info * edac_dev,bool enable)1686f864b79bSLoc Ho static void xgene_edac_soc_hw_init(struct edac_device_ctl_info *edac_dev,
1687f864b79bSLoc Ho 				   bool enable)
1688f864b79bSLoc Ho {
1689f864b79bSLoc Ho 	struct xgene_edac_dev_ctx *ctx = edac_dev->pvt_info;
1690f864b79bSLoc Ho 
1691f864b79bSLoc Ho 	/* Enable SoC IP error interrupt */
1692f864b79bSLoc Ho 	if (edac_dev->op_state == OP_RUNNING_INTERRUPT) {
1693f864b79bSLoc Ho 		if (enable) {
1694f864b79bSLoc Ho 			xgene_edac_pcp_clrbits(ctx->edac, PCPHPERRINTMSK,
1695f864b79bSLoc Ho 					       IOB_PA_ERR_MASK |
1696f864b79bSLoc Ho 					       IOB_BA_ERR_MASK |
1697f864b79bSLoc Ho 					       IOB_XGIC_ERR_MASK |
1698f864b79bSLoc Ho 					       IOB_RB_ERR_MASK);
1699f864b79bSLoc Ho 			xgene_edac_pcp_clrbits(ctx->edac, PCPLPERRINTMSK,
1700f864b79bSLoc Ho 					       CSW_SWITCH_TRACE_ERR_MASK);
1701f864b79bSLoc Ho 		} else {
1702f864b79bSLoc Ho 			xgene_edac_pcp_setbits(ctx->edac, PCPHPERRINTMSK,
1703f864b79bSLoc Ho 					       IOB_PA_ERR_MASK |
1704f864b79bSLoc Ho 					       IOB_BA_ERR_MASK |
1705f864b79bSLoc Ho 					       IOB_XGIC_ERR_MASK |
1706f864b79bSLoc Ho 					       IOB_RB_ERR_MASK);
1707f864b79bSLoc Ho 			xgene_edac_pcp_setbits(ctx->edac, PCPLPERRINTMSK,
1708f864b79bSLoc Ho 					       CSW_SWITCH_TRACE_ERR_MASK);
1709f864b79bSLoc Ho 		}
1710f864b79bSLoc Ho 
1711f864b79bSLoc Ho 		writel(enable ? 0x0 : 0xFFFFFFFF,
1712f864b79bSLoc Ho 		       ctx->dev_csr + IOBAXIS0TRANSERRINTMSK);
1713f864b79bSLoc Ho 		writel(enable ? 0x0 : 0xFFFFFFFF,
1714f864b79bSLoc Ho 		       ctx->dev_csr + IOBAXIS1TRANSERRINTMSK);
1715f864b79bSLoc Ho 		writel(enable ? 0x0 : 0xFFFFFFFF,
1716f864b79bSLoc Ho 		       ctx->dev_csr + XGICTRANSERRINTMSK);
1717f864b79bSLoc Ho 
1718f864b79bSLoc Ho 		xgene_edac_pcp_setbits(ctx->edac, MEMERRINTMSK,
1719f864b79bSLoc Ho 				       enable ? 0x0 : 0xFFFFFFFF);
1720f864b79bSLoc Ho 	}
1721f864b79bSLoc Ho }
1722f864b79bSLoc Ho 
xgene_edac_soc_add(struct xgene_edac * edac,struct device_node * np,int version)1723f864b79bSLoc Ho static int xgene_edac_soc_add(struct xgene_edac *edac, struct device_node *np,
1724f864b79bSLoc Ho 			      int version)
1725f864b79bSLoc Ho {
1726f864b79bSLoc Ho 	struct edac_device_ctl_info *edac_dev;
1727f864b79bSLoc Ho 	struct xgene_edac_dev_ctx *ctx;
1728f864b79bSLoc Ho 	void __iomem *dev_csr;
1729f864b79bSLoc Ho 	struct resource res;
1730f864b79bSLoc Ho 	int edac_idx;
1731f864b79bSLoc Ho 	int rc;
1732f864b79bSLoc Ho 
1733f864b79bSLoc Ho 	if (!devres_open_group(edac->dev, xgene_edac_soc_add, GFP_KERNEL))
1734f864b79bSLoc Ho 		return -ENOMEM;
1735f864b79bSLoc Ho 
1736f864b79bSLoc Ho 	rc = of_address_to_resource(np, 0, &res);
1737f864b79bSLoc Ho 	if (rc < 0) {
1738f864b79bSLoc Ho 		dev_err(edac->dev, "no SoC resource address\n");
1739f864b79bSLoc Ho 		goto err_release_group;
1740f864b79bSLoc Ho 	}
1741f864b79bSLoc Ho 	dev_csr = devm_ioremap_resource(edac->dev, &res);
1742f864b79bSLoc Ho 	if (IS_ERR(dev_csr)) {
1743f864b79bSLoc Ho 		dev_err(edac->dev,
1744f864b79bSLoc Ho 			"devm_ioremap_resource failed for soc resource address\n");
1745f864b79bSLoc Ho 		rc = PTR_ERR(dev_csr);
1746f864b79bSLoc Ho 		goto err_release_group;
1747f864b79bSLoc Ho 	}
1748f864b79bSLoc Ho 
1749f864b79bSLoc Ho 	edac_idx = edac_device_alloc_index();
1750f864b79bSLoc Ho 	edac_dev = edac_device_alloc_ctl_info(sizeof(*ctx),
1751f864b79bSLoc Ho 					      "SOC", 1, "SOC", 1, 2, NULL, 0,
1752f864b79bSLoc Ho 					      edac_idx);
1753f864b79bSLoc Ho 	if (!edac_dev) {
1754f864b79bSLoc Ho 		rc = -ENOMEM;
1755f864b79bSLoc Ho 		goto err_release_group;
1756f864b79bSLoc Ho 	}
1757f864b79bSLoc Ho 
1758f864b79bSLoc Ho 	ctx = edac_dev->pvt_info;
1759f864b79bSLoc Ho 	ctx->dev_csr = dev_csr;
1760f864b79bSLoc Ho 	ctx->name = "xgene_soc_err";
1761f864b79bSLoc Ho 	ctx->edac_idx = edac_idx;
1762f864b79bSLoc Ho 	ctx->edac = edac;
1763f864b79bSLoc Ho 	ctx->edac_dev = edac_dev;
1764f864b79bSLoc Ho 	ctx->ddev = *edac->dev;
1765f864b79bSLoc Ho 	ctx->version = version;
1766f864b79bSLoc Ho 	edac_dev->dev = &ctx->ddev;
1767f864b79bSLoc Ho 	edac_dev->ctl_name = ctx->name;
1768f864b79bSLoc Ho 	edac_dev->dev_name = ctx->name;
1769f864b79bSLoc Ho 	edac_dev->mod_name = EDAC_MOD_STR;
1770f864b79bSLoc Ho 
1771f864b79bSLoc Ho 	if (edac_op_state == EDAC_OPSTATE_POLL)
1772f864b79bSLoc Ho 		edac_dev->edac_check = xgene_edac_soc_check;
1773f864b79bSLoc Ho 
1774f864b79bSLoc Ho 	rc = edac_device_add_device(edac_dev);
1775f864b79bSLoc Ho 	if (rc > 0) {
1776f864b79bSLoc Ho 		dev_err(edac->dev, "failed edac_device_add_device()\n");
1777f864b79bSLoc Ho 		rc = -ENOMEM;
1778f864b79bSLoc Ho 		goto err_ctl_free;
1779f864b79bSLoc Ho 	}
1780f864b79bSLoc Ho 
1781f864b79bSLoc Ho 	if (edac_op_state == EDAC_OPSTATE_INT)
1782f864b79bSLoc Ho 		edac_dev->op_state = OP_RUNNING_INTERRUPT;
1783f864b79bSLoc Ho 
1784f864b79bSLoc Ho 	list_add(&ctx->next, &edac->socs);
1785f864b79bSLoc Ho 
1786f864b79bSLoc Ho 	xgene_edac_soc_hw_init(edac_dev, 1);
1787f864b79bSLoc Ho 
1788f864b79bSLoc Ho 	devres_remove_group(edac->dev, xgene_edac_soc_add);
1789f864b79bSLoc Ho 
1790f864b79bSLoc Ho 	dev_info(edac->dev, "X-Gene EDAC SoC registered\n");
1791f864b79bSLoc Ho 
1792f864b79bSLoc Ho 	return 0;
1793f864b79bSLoc Ho 
1794f864b79bSLoc Ho err_ctl_free:
1795f864b79bSLoc Ho 	edac_device_free_ctl_info(edac_dev);
1796f864b79bSLoc Ho err_release_group:
1797f864b79bSLoc Ho 	devres_release_group(edac->dev, xgene_edac_soc_add);
1798f864b79bSLoc Ho 	return rc;
1799f864b79bSLoc Ho }
1800f864b79bSLoc Ho 
xgene_edac_soc_remove(struct xgene_edac_dev_ctx * soc)1801f864b79bSLoc Ho static int xgene_edac_soc_remove(struct xgene_edac_dev_ctx *soc)
1802f864b79bSLoc Ho {
1803f864b79bSLoc Ho 	struct edac_device_ctl_info *edac_dev = soc->edac_dev;
1804f864b79bSLoc Ho 
1805f864b79bSLoc Ho 	xgene_edac_soc_hw_init(edac_dev, 0);
1806f864b79bSLoc Ho 	edac_device_del_device(soc->edac->dev);
1807f864b79bSLoc Ho 	edac_device_free_ctl_info(edac_dev);
1808f864b79bSLoc Ho 	return 0;
1809f864b79bSLoc Ho }
1810f864b79bSLoc Ho 
xgene_edac_isr(int irq,void * dev_id)18110d442930SLoc Ho static irqreturn_t xgene_edac_isr(int irq, void *dev_id)
18120d442930SLoc Ho {
18130d442930SLoc Ho 	struct xgene_edac *ctx = dev_id;
18140d442930SLoc Ho 	struct xgene_edac_pmd_ctx *pmd;
18159347473cSLoc Ho 	struct xgene_edac_dev_ctx *node;
18160d442930SLoc Ho 	unsigned int pcp_hp_stat;
18170d442930SLoc Ho 	unsigned int pcp_lp_stat;
18180d442930SLoc Ho 
18190d442930SLoc Ho 	xgene_edac_pcp_rd(ctx, PCPHPERRINTSTS, &pcp_hp_stat);
18200d442930SLoc Ho 	xgene_edac_pcp_rd(ctx, PCPLPERRINTSTS, &pcp_lp_stat);
18210d442930SLoc Ho 	if ((MCU_UNCORR_ERR_MASK & pcp_hp_stat) ||
18220d442930SLoc Ho 	    (MCU_CTL_ERR_MASK & pcp_hp_stat) ||
18230d442930SLoc Ho 	    (MCU_CORR_ERR_MASK & pcp_lp_stat)) {
18240d442930SLoc Ho 		struct xgene_edac_mc_ctx *mcu;
18250d442930SLoc Ho 
18269347473cSLoc Ho 		list_for_each_entry(mcu, &ctx->mcus, next)
18270d442930SLoc Ho 			xgene_edac_mc_check(mcu->mci);
18280d442930SLoc Ho 	}
18290d442930SLoc Ho 
18300d442930SLoc Ho 	list_for_each_entry(pmd, &ctx->pmds, next) {
18310d442930SLoc Ho 		if ((PMD0_MERR_MASK << pmd->pmd) & pcp_hp_stat)
18320d442930SLoc Ho 			xgene_edac_pmd_check(pmd->edac_dev);
18330d442930SLoc Ho 	}
18340d442930SLoc Ho 
18359347473cSLoc Ho 	list_for_each_entry(node, &ctx->l3s, next)
18369347473cSLoc Ho 		xgene_edac_l3_check(node->edac_dev);
18379347473cSLoc Ho 
1838f864b79bSLoc Ho 	list_for_each_entry(node, &ctx->socs, next)
1839f864b79bSLoc Ho 		xgene_edac_soc_check(node->edac_dev);
1840f864b79bSLoc Ho 
18410d442930SLoc Ho 	return IRQ_HANDLED;
18420d442930SLoc Ho }
18430d442930SLoc Ho 
xgene_edac_probe(struct platform_device * pdev)18440d442930SLoc Ho static int xgene_edac_probe(struct platform_device *pdev)
18450d442930SLoc Ho {
18460d442930SLoc Ho 	struct xgene_edac *edac;
18470d442930SLoc Ho 	struct device_node *child;
18480d442930SLoc Ho 	struct resource *res;
18490d442930SLoc Ho 	int rc;
18500d442930SLoc Ho 
18510d442930SLoc Ho 	edac = devm_kzalloc(&pdev->dev, sizeof(*edac), GFP_KERNEL);
18520d442930SLoc Ho 	if (!edac)
18530d442930SLoc Ho 		return -ENOMEM;
18540d442930SLoc Ho 
18550d442930SLoc Ho 	edac->dev = &pdev->dev;
18560d442930SLoc Ho 	platform_set_drvdata(pdev, edac);
18570d442930SLoc Ho 	INIT_LIST_HEAD(&edac->mcus);
18580d442930SLoc Ho 	INIT_LIST_HEAD(&edac->pmds);
18599347473cSLoc Ho 	INIT_LIST_HEAD(&edac->l3s);
1860f864b79bSLoc Ho 	INIT_LIST_HEAD(&edac->socs);
18610d442930SLoc Ho 	spin_lock_init(&edac->lock);
18620d442930SLoc Ho 	mutex_init(&edac->mc_lock);
18630d442930SLoc Ho 
18640d442930SLoc Ho 	edac->csw_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
18650d442930SLoc Ho 							"regmap-csw");
18660d442930SLoc Ho 	if (IS_ERR(edac->csw_map)) {
18670d442930SLoc Ho 		dev_err(edac->dev, "unable to get syscon regmap csw\n");
18680d442930SLoc Ho 		rc = PTR_ERR(edac->csw_map);
18690d442930SLoc Ho 		goto out_err;
18700d442930SLoc Ho 	}
18710d442930SLoc Ho 
18720d442930SLoc Ho 	edac->mcba_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
18730d442930SLoc Ho 							 "regmap-mcba");
18740d442930SLoc Ho 	if (IS_ERR(edac->mcba_map)) {
18750d442930SLoc Ho 		dev_err(edac->dev, "unable to get syscon regmap mcba\n");
18760d442930SLoc Ho 		rc = PTR_ERR(edac->mcba_map);
18770d442930SLoc Ho 		goto out_err;
18780d442930SLoc Ho 	}
18790d442930SLoc Ho 
18800d442930SLoc Ho 	edac->mcbb_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
18810d442930SLoc Ho 							 "regmap-mcbb");
18820d442930SLoc Ho 	if (IS_ERR(edac->mcbb_map)) {
18830d442930SLoc Ho 		dev_err(edac->dev, "unable to get syscon regmap mcbb\n");
18840d442930SLoc Ho 		rc = PTR_ERR(edac->mcbb_map);
18850d442930SLoc Ho 		goto out_err;
18860d442930SLoc Ho 	}
18870d442930SLoc Ho 	edac->efuse_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
18880d442930SLoc Ho 							  "regmap-efuse");
18890d442930SLoc Ho 	if (IS_ERR(edac->efuse_map)) {
18900d442930SLoc Ho 		dev_err(edac->dev, "unable to get syscon regmap efuse\n");
18910d442930SLoc Ho 		rc = PTR_ERR(edac->efuse_map);
18920d442930SLoc Ho 		goto out_err;
18930d442930SLoc Ho 	}
18940d442930SLoc Ho 
18954d67e3ceSLoc Ho 	/*
18964d67e3ceSLoc Ho 	 * NOTE: The register bus resource is optional for compatibility
18974d67e3ceSLoc Ho 	 * reason.
18984d67e3ceSLoc Ho 	 */
18994d67e3ceSLoc Ho 	edac->rb_map = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
19004d67e3ceSLoc Ho 						       "regmap-rb");
19014d67e3ceSLoc Ho 	if (IS_ERR(edac->rb_map)) {
19024d67e3ceSLoc Ho 		dev_warn(edac->dev, "missing syscon regmap rb\n");
19034d67e3ceSLoc Ho 		edac->rb_map = NULL;
19044d67e3ceSLoc Ho 	}
19054d67e3ceSLoc Ho 
19060d442930SLoc Ho 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
19070d442930SLoc Ho 	edac->pcp_csr = devm_ioremap_resource(&pdev->dev, res);
19080d442930SLoc Ho 	if (IS_ERR(edac->pcp_csr)) {
19090d442930SLoc Ho 		dev_err(&pdev->dev, "no PCP resource address\n");
19100d442930SLoc Ho 		rc = PTR_ERR(edac->pcp_csr);
19110d442930SLoc Ho 		goto out_err;
19120d442930SLoc Ho 	}
19130d442930SLoc Ho 
19140d442930SLoc Ho 	if (edac_op_state == EDAC_OPSTATE_INT) {
19150d442930SLoc Ho 		int irq;
19160d442930SLoc Ho 		int i;
19170d442930SLoc Ho 
19180d442930SLoc Ho 		for (i = 0; i < 3; i++) {
1919e26124cdSMenglong Dong 			irq = platform_get_irq_optional(pdev, i);
19200d442930SLoc Ho 			if (irq < 0) {
19210d442930SLoc Ho 				dev_err(&pdev->dev, "No IRQ resource\n");
1922dfd0dfb9SSergey Shtylyov 				rc = irq;
19230d442930SLoc Ho 				goto out_err;
19240d442930SLoc Ho 			}
19250d442930SLoc Ho 			rc = devm_request_irq(&pdev->dev, irq,
19260d442930SLoc Ho 					      xgene_edac_isr, IRQF_SHARED,
19270d442930SLoc Ho 					      dev_name(&pdev->dev), edac);
19280d442930SLoc Ho 			if (rc) {
19290d442930SLoc Ho 				dev_err(&pdev->dev,
19300d442930SLoc Ho 					"Could not request IRQ %d\n", irq);
19310d442930SLoc Ho 				goto out_err;
19320d442930SLoc Ho 			}
19330d442930SLoc Ho 		}
19340d442930SLoc Ho 	}
19350d442930SLoc Ho 
19369347473cSLoc Ho 	edac->dfs = edac_debugfs_create_dir(pdev->dev.kobj.name);
19379347473cSLoc Ho 
19380d442930SLoc Ho 	for_each_child_of_node(pdev->dev.of_node, child) {
19390d442930SLoc Ho 		if (!of_device_is_available(child))
19400d442930SLoc Ho 			continue;
19410d442930SLoc Ho 		if (of_device_is_compatible(child, "apm,xgene-edac-mc"))
19420d442930SLoc Ho 			xgene_edac_mc_add(edac, child);
19430d442930SLoc Ho 		if (of_device_is_compatible(child, "apm,xgene-edac-pmd"))
1944451bb7fbSArnd Bergmann 			xgene_edac_pmd_add(edac, child, 1);
1945451bb7fbSArnd Bergmann 		if (of_device_is_compatible(child, "apm,xgene-edac-pmd-v2"))
1946451bb7fbSArnd Bergmann 			xgene_edac_pmd_add(edac, child, 2);
19479347473cSLoc Ho 		if (of_device_is_compatible(child, "apm,xgene-edac-l3"))
19489347473cSLoc Ho 			xgene_edac_l3_add(edac, child, 1);
19499347473cSLoc Ho 		if (of_device_is_compatible(child, "apm,xgene-edac-l3-v2"))
19509347473cSLoc Ho 			xgene_edac_l3_add(edac, child, 2);
1951f864b79bSLoc Ho 		if (of_device_is_compatible(child, "apm,xgene-edac-soc"))
1952f864b79bSLoc Ho 			xgene_edac_soc_add(edac, child, 0);
1953f864b79bSLoc Ho 		if (of_device_is_compatible(child, "apm,xgene-edac-soc-v1"))
1954f864b79bSLoc Ho 			xgene_edac_soc_add(edac, child, 1);
19550d442930SLoc Ho 	}
19560d442930SLoc Ho 
19570d442930SLoc Ho 	return 0;
19580d442930SLoc Ho 
19590d442930SLoc Ho out_err:
19600d442930SLoc Ho 	return rc;
19610d442930SLoc Ho }
19620d442930SLoc Ho 
xgene_edac_remove(struct platform_device * pdev)19630d442930SLoc Ho static int xgene_edac_remove(struct platform_device *pdev)
19640d442930SLoc Ho {
19650d442930SLoc Ho 	struct xgene_edac *edac = dev_get_drvdata(&pdev->dev);
19660d442930SLoc Ho 	struct xgene_edac_mc_ctx *mcu;
19670d442930SLoc Ho 	struct xgene_edac_mc_ctx *temp_mcu;
19680d442930SLoc Ho 	struct xgene_edac_pmd_ctx *pmd;
19690d442930SLoc Ho 	struct xgene_edac_pmd_ctx *temp_pmd;
19709347473cSLoc Ho 	struct xgene_edac_dev_ctx *node;
19719347473cSLoc Ho 	struct xgene_edac_dev_ctx *temp_node;
19720d442930SLoc Ho 
19739347473cSLoc Ho 	list_for_each_entry_safe(mcu, temp_mcu, &edac->mcus, next)
19740d442930SLoc Ho 		xgene_edac_mc_remove(mcu);
19750d442930SLoc Ho 
19769347473cSLoc Ho 	list_for_each_entry_safe(pmd, temp_pmd, &edac->pmds, next)
19770d442930SLoc Ho 		xgene_edac_pmd_remove(pmd);
19789347473cSLoc Ho 
19799347473cSLoc Ho 	list_for_each_entry_safe(node, temp_node, &edac->l3s, next)
19809347473cSLoc Ho 		xgene_edac_l3_remove(node);
19819347473cSLoc Ho 
1982f864b79bSLoc Ho 	list_for_each_entry_safe(node, temp_node, &edac->socs, next)
1983f864b79bSLoc Ho 		xgene_edac_soc_remove(node);
1984f864b79bSLoc Ho 
19850d442930SLoc Ho 	return 0;
19860d442930SLoc Ho }
19870d442930SLoc Ho 
19880d442930SLoc Ho static const struct of_device_id xgene_edac_of_match[] = {
19890d442930SLoc Ho 	{ .compatible = "apm,xgene-edac" },
19900d442930SLoc Ho 	{},
19910d442930SLoc Ho };
19920d442930SLoc Ho MODULE_DEVICE_TABLE(of, xgene_edac_of_match);
19930d442930SLoc Ho 
19940d442930SLoc Ho static struct platform_driver xgene_edac_driver = {
19950d442930SLoc Ho 	.probe = xgene_edac_probe,
19960d442930SLoc Ho 	.remove = xgene_edac_remove,
19970d442930SLoc Ho 	.driver = {
19980d442930SLoc Ho 		.name = "xgene-edac",
19990d442930SLoc Ho 		.of_match_table = xgene_edac_of_match,
20000d442930SLoc Ho 	},
20010d442930SLoc Ho };
20020d442930SLoc Ho 
xgene_edac_init(void)20030d442930SLoc Ho static int __init xgene_edac_init(void)
20040d442930SLoc Ho {
20050d442930SLoc Ho 	int rc;
20060d442930SLoc Ho 
2007*315bada6SJia He 	if (ghes_get_devices())
2008*315bada6SJia He 		return -EBUSY;
2009*315bada6SJia He 
20100d442930SLoc Ho 	/* Make sure error reporting method is sane */
20110d442930SLoc Ho 	switch (edac_op_state) {
20120d442930SLoc Ho 	case EDAC_OPSTATE_POLL:
20130d442930SLoc Ho 	case EDAC_OPSTATE_INT:
20140d442930SLoc Ho 		break;
20150d442930SLoc Ho 	default:
20160d442930SLoc Ho 		edac_op_state = EDAC_OPSTATE_INT;
20170d442930SLoc Ho 		break;
20180d442930SLoc Ho 	}
20190d442930SLoc Ho 
20200d442930SLoc Ho 	rc = platform_driver_register(&xgene_edac_driver);
20210d442930SLoc Ho 	if (rc) {
20220d442930SLoc Ho 		edac_printk(KERN_ERR, EDAC_MOD_STR,
20230d442930SLoc Ho 			    "EDAC fails to register\n");
20240d442930SLoc Ho 		goto reg_failed;
20250d442930SLoc Ho 	}
20260d442930SLoc Ho 
20270d442930SLoc Ho 	return 0;
20280d442930SLoc Ho 
20290d442930SLoc Ho reg_failed:
20300d442930SLoc Ho 	return rc;
20310d442930SLoc Ho }
20320d442930SLoc Ho module_init(xgene_edac_init);
20330d442930SLoc Ho 
xgene_edac_exit(void)20340d442930SLoc Ho static void __exit xgene_edac_exit(void)
20350d442930SLoc Ho {
20360d442930SLoc Ho 	platform_driver_unregister(&xgene_edac_driver);
20370d442930SLoc Ho }
20380d442930SLoc Ho module_exit(xgene_edac_exit);
20390d442930SLoc Ho 
20400d442930SLoc Ho MODULE_LICENSE("GPL");
20410d442930SLoc Ho MODULE_AUTHOR("Feng Kan <fkan@apm.com>");
20420d442930SLoc Ho MODULE_DESCRIPTION("APM X-Gene EDAC driver");
20430d442930SLoc Ho module_param(edac_op_state, int, 0444);
20440d442930SLoc Ho MODULE_PARM_DESC(edac_op_state,
20450d442930SLoc Ho 		 "EDAC error reporting state: 0=Poll, 2=Interrupt");
2046