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

EDAC/synopsys: Fix error injection on Zynq UltraScale+



The Zynq UltraScale+ MPSoC DDR has a disjoint memory from 2GB to 32GB.
The DDR host interface has a contiguous memory so while injecting
errors, the driver should remove the hole else the injection fails as
the address translation is incorrect.

Introduce a get_mem_info() function pointer and set it for Zynq
UltraScale+ platform to return host address.

Fixes: 1a81361f ("EDAC, synopsys: Add Error Injection support for ZynqMP DDR controller")
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/r/20240711100656.31376-1-shubhrajyoti.datta@amd.com
parent 8400291e
Loading
Loading
Loading
Loading
+34 −1
Original line number Diff line number Diff line
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
#include <linux/sizes.h>
#include <linux/interrupt.h>
#include <linux/of.h>

@@ -337,6 +338,7 @@ struct synps_edac_priv {
 * @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 {
@@ -344,6 +346,9 @@ struct synps_platform_data {
	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
	int quirks;
};

@@ -402,6 +407,25 @@ static int zynq_get_error_info(struct synps_edac_priv *priv)
	return 0;
}

#ifdef CONFIG_EDAC_DEBUG
/**
 * zynqmp_get_mem_info - Get the current memory info.
 * @priv:	DDR memory controller private instance data.
 *
 * Return: host interface address.
 */
static u64 zynqmp_get_mem_info(struct synps_edac_priv *priv)
{
	u64 hif_addr = 0, linear_addr;

	linear_addr = priv->poison_addr;
	if (linear_addr >= SZ_32G)
		linear_addr = linear_addr - SZ_32G + SZ_2G;
	hif_addr = linear_addr >> 3;
	return hif_addr;
}
#endif

/**
 * zynqmp_get_error_info - Get the current ECC error info.
 * @priv:	DDR memory controller private instance data.
@@ -922,6 +946,9 @@ static const struct synps_platform_data zynqmp_edac_def = {
	.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
	.quirks         = (DDR_ECC_INTR_SUPPORT
#ifdef CONFIG_EDAC_DEBUG
			  | DDR_ECC_DATA_POISON_SUPPORT
@@ -975,9 +1002,15 @@ MODULE_DEVICE_TABLE(of, synps_edac_match);
static void ddr_poison_setup(struct synps_edac_priv *priv)
{
	int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval;
	const struct synps_platform_data *p_data;
	int index;
	ulong hif_addr = 0;

	p_data = priv->p_data;

	if (p_data->get_mem_info)
		hif_addr = p_data->get_mem_info(priv);
	else
		hif_addr = priv->poison_addr >> 3;

	for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) {