EDAC/synopsys: Clear the ECC counters on init
Clear the ECC error and counter registers during initialization/probe to avoid
reporting stale errors that may have occurred before EDAC registration.
For that, unify the Zynq and ZynqMP ECC state reading paths and simplify the
code.
[ bp: Massage commit message.
Fix an -Wsometimes-uninitialized warning as reported by
Reported-by: kernel test robot <lkp@intel.com>
Closes: https://lore.kernel.org/oe-kbuild-all/202507141048.obUv3ZUm-lkp@intel.com ]
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/20250713050753.7042-1-shubhrajyoti.datta@amd.com
pull/1309/head
parent
05a61c6cb6
commit
b1dc7f097b
|
|
@ -332,20 +332,26 @@ struct synps_edac_priv {
|
|||
#endif
|
||||
};
|
||||
|
||||
enum synps_platform_type {
|
||||
ZYNQ,
|
||||
ZYNQMP,
|
||||
SYNPS,
|
||||
};
|
||||
|
||||
/**
|
||||
* struct synps_platform_data - synps platform data structure.
|
||||
* @platform: Identifies the target hardware platform
|
||||
* @get_error_info: Get EDAC error info.
|
||||
* @get_mtype: Get mtype.
|
||||
* @get_dtype: Get dtype.
|
||||
* @get_ecc_state: Get ECC state.
|
||||
* @get_mem_info: Get EDAC memory info
|
||||
* @quirks: To differentiate IPs.
|
||||
*/
|
||||
struct synps_platform_data {
|
||||
enum synps_platform_type platform;
|
||||
int (*get_error_info)(struct synps_edac_priv *priv);
|
||||
enum mem_type (*get_mtype)(const void __iomem *base);
|
||||
enum dev_type (*get_dtype)(const void __iomem *base);
|
||||
bool (*get_ecc_state)(void __iomem *base);
|
||||
#ifdef CONFIG_EDAC_DEBUG
|
||||
u64 (*get_mem_info)(struct synps_edac_priv *priv);
|
||||
#endif
|
||||
|
|
@ -720,51 +726,38 @@ static enum dev_type zynqmp_get_dtype(const void __iomem *base)
|
|||
return dt;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynq_get_ecc_state - Return the controller ECC enable/disable status.
|
||||
* @base: DDR memory controller base address.
|
||||
*
|
||||
* Get the ECC enable/disable status of the controller.
|
||||
*
|
||||
* Return: true if enabled, otherwise false.
|
||||
*/
|
||||
static bool zynq_get_ecc_state(void __iomem *base)
|
||||
static bool get_ecc_state(struct synps_edac_priv *priv)
|
||||
{
|
||||
u32 ecctype, clearval;
|
||||
enum dev_type dt;
|
||||
u32 ecctype;
|
||||
|
||||
dt = zynq_get_dtype(base);
|
||||
if (dt == DEV_UNKNOWN)
|
||||
return false;
|
||||
if (priv->p_data->platform == ZYNQ) {
|
||||
dt = zynq_get_dtype(priv->baseaddr);
|
||||
if (dt == DEV_UNKNOWN)
|
||||
return false;
|
||||
|
||||
ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK;
|
||||
if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2))
|
||||
return true;
|
||||
ecctype = readl(priv->baseaddr + SCRUB_OFST) & SCRUB_MODE_MASK;
|
||||
if (ecctype == SCRUB_MODE_SECDED && dt == DEV_X2) {
|
||||
clearval = ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_UE_ERR;
|
||||
writel(clearval, priv->baseaddr + ECC_CTRL_OFST);
|
||||
writel(0x0, priv->baseaddr + ECC_CTRL_OFST);
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
dt = zynqmp_get_dtype(priv->baseaddr);
|
||||
if (dt == DEV_UNKNOWN)
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* zynqmp_get_ecc_state - Return the controller ECC enable/disable status.
|
||||
* @base: DDR memory controller base address.
|
||||
*
|
||||
* Get the ECC enable/disable status for the controller.
|
||||
*
|
||||
* Return: a ECC status boolean i.e true/false - enabled/disabled.
|
||||
*/
|
||||
static bool zynqmp_get_ecc_state(void __iomem *base)
|
||||
{
|
||||
enum dev_type dt;
|
||||
u32 ecctype;
|
||||
|
||||
dt = zynqmp_get_dtype(base);
|
||||
if (dt == DEV_UNKNOWN)
|
||||
return false;
|
||||
|
||||
ecctype = readl(base + ECC_CFG0_OFST) & SCRUB_MODE_MASK;
|
||||
if ((ecctype == SCRUB_MODE_SECDED) &&
|
||||
((dt == DEV_X2) || (dt == DEV_X4) || (dt == DEV_X8)))
|
||||
return true;
|
||||
ecctype = readl(priv->baseaddr + ECC_CFG0_OFST) & SCRUB_MODE_MASK;
|
||||
if (ecctype == SCRUB_MODE_SECDED &&
|
||||
(dt == DEV_X2 || dt == DEV_X4 || dt == DEV_X8)) {
|
||||
clearval = readl(priv->baseaddr + ECC_CLR_OFST) |
|
||||
ECC_CTRL_CLR_CE_ERR | ECC_CTRL_CLR_CE_ERRCNT |
|
||||
ECC_CTRL_CLR_UE_ERR | ECC_CTRL_CLR_UE_ERRCNT;
|
||||
writel(clearval, priv->baseaddr + ECC_CLR_OFST);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
@ -934,18 +927,18 @@ static int setup_irq(struct mem_ctl_info *mci,
|
|||
}
|
||||
|
||||
static const struct synps_platform_data zynq_edac_def = {
|
||||
.platform = ZYNQ,
|
||||
.get_error_info = zynq_get_error_info,
|
||||
.get_mtype = zynq_get_mtype,
|
||||
.get_dtype = zynq_get_dtype,
|
||||
.get_ecc_state = zynq_get_ecc_state,
|
||||
.quirks = 0,
|
||||
};
|
||||
|
||||
static const struct synps_platform_data zynqmp_edac_def = {
|
||||
.platform = ZYNQMP,
|
||||
.get_error_info = zynqmp_get_error_info,
|
||||
.get_mtype = zynqmp_get_mtype,
|
||||
.get_dtype = zynqmp_get_dtype,
|
||||
.get_ecc_state = zynqmp_get_ecc_state,
|
||||
#ifdef CONFIG_EDAC_DEBUG
|
||||
.get_mem_info = zynqmp_get_mem_info,
|
||||
#endif
|
||||
|
|
@ -957,10 +950,10 @@ static const struct synps_platform_data zynqmp_edac_def = {
|
|||
};
|
||||
|
||||
static const struct synps_platform_data synopsys_edac_def = {
|
||||
.platform = SYNPS,
|
||||
.get_error_info = zynqmp_get_error_info,
|
||||
.get_mtype = zynqmp_get_mtype,
|
||||
.get_dtype = zynqmp_get_dtype,
|
||||
.get_ecc_state = zynqmp_get_ecc_state,
|
||||
.quirks = (DDR_ECC_INTR_SUPPORT | DDR_ECC_INTR_SELF_CLEAR
|
||||
#ifdef CONFIG_EDAC_DEBUG
|
||||
| DDR_ECC_DATA_POISON_SUPPORT
|
||||
|
|
@ -1390,10 +1383,6 @@ static int mc_probe(struct platform_device *pdev)
|
|||
if (!p_data)
|
||||
return -ENODEV;
|
||||
|
||||
if (!p_data->get_ecc_state(baseaddr)) {
|
||||
edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
|
||||
layers[0].size = SYNPS_EDAC_NR_CSROWS;
|
||||
|
|
@ -1413,6 +1402,12 @@ static int mc_probe(struct platform_device *pdev)
|
|||
priv = mci->pvt_info;
|
||||
priv->baseaddr = baseaddr;
|
||||
priv->p_data = p_data;
|
||||
if (!get_ecc_state(priv)) {
|
||||
edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
|
||||
rc = -ENODEV;
|
||||
goto free_edac_mc;
|
||||
}
|
||||
|
||||
spin_lock_init(&priv->reglock);
|
||||
|
||||
mc_init(mci, pdev);
|
||||
|
|
|
|||
Loading…
Reference in New Issue