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
Shubhrajyoti Datta 2025-07-13 10:37:53 +05:30 committed by Borislav Petkov (AMD)
parent 05a61c6cb6
commit b1dc7f097b
1 changed files with 44 additions and 49 deletions

View File

@ -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);