Commit b1dc7f09 authored by Shubhrajyoti Datta's avatar Shubhrajyoti Datta Committed by Borislav Petkov (AMD)
Browse files

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: default avatarkernel test robot <lkp@intel.com>
    Closes: https://lore.kernel.org/oe-kbuild-all/202507141048.obUv3ZUm-lkp@intel.com

 ]

Signed-off-by: default avatarShubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Signed-off-by: default avatarBorislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/20250713050753.7042-1-shubhrajyoti.datta@amd.com
parent 05a61c6c
Loading
Loading
Loading
Loading
+46 −51
Original line number Diff line number Diff line
@@ -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 (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))
		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;

	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);
	} else {
		dt = zynqmp_get_dtype(priv->baseaddr);
		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)))
		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);