EDAC/synopsys: Fix error injection on Zynq UltraScale+
[ Upstream commit 35e6dbfe1846caeafabb49b7575adb36b0aa2269 ]
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: 1a81361f75
("EDAC, synopsys: Add Error Injection support for ZynqMP DDR controller")
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20240711100656.31376-1-shubhrajyoti.datta@amd.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
a8d9917193
commit
7d77159149
@ -10,6 +10,7 @@
|
|||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/sizes.h>
|
||||||
#include <linux/interrupt.h>
|
#include <linux/interrupt.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/of_device.h>
|
#include <linux/of_device.h>
|
||||||
@ -338,6 +339,7 @@ struct synps_edac_priv {
|
|||||||
* @get_mtype: Get mtype.
|
* @get_mtype: Get mtype.
|
||||||
* @get_dtype: Get dtype.
|
* @get_dtype: Get dtype.
|
||||||
* @get_ecc_state: Get ECC state.
|
* @get_ecc_state: Get ECC state.
|
||||||
|
* @get_mem_info: Get EDAC memory info
|
||||||
* @quirks: To differentiate IPs.
|
* @quirks: To differentiate IPs.
|
||||||
*/
|
*/
|
||||||
struct synps_platform_data {
|
struct synps_platform_data {
|
||||||
@ -345,6 +347,9 @@ struct synps_platform_data {
|
|||||||
enum mem_type (*get_mtype)(const void __iomem *base);
|
enum mem_type (*get_mtype)(const void __iomem *base);
|
||||||
enum dev_type (*get_dtype)(const void __iomem *base);
|
enum dev_type (*get_dtype)(const void __iomem *base);
|
||||||
bool (*get_ecc_state)(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;
|
int quirks;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -403,6 +408,25 @@ out:
|
|||||||
return 0;
|
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.
|
* zynqmp_get_error_info - Get the current ECC error info.
|
||||||
* @priv: DDR memory controller private instance data.
|
* @priv: DDR memory controller private instance data.
|
||||||
@ -923,6 +947,9 @@ static const struct synps_platform_data zynqmp_edac_def = {
|
|||||||
.get_mtype = zynqmp_get_mtype,
|
.get_mtype = zynqmp_get_mtype,
|
||||||
.get_dtype = zynqmp_get_dtype,
|
.get_dtype = zynqmp_get_dtype,
|
||||||
.get_ecc_state = zynqmp_get_ecc_state,
|
.get_ecc_state = zynqmp_get_ecc_state,
|
||||||
|
#ifdef CONFIG_EDAC_DEBUG
|
||||||
|
.get_mem_info = zynqmp_get_mem_info,
|
||||||
|
#endif
|
||||||
.quirks = (DDR_ECC_INTR_SUPPORT
|
.quirks = (DDR_ECC_INTR_SUPPORT
|
||||||
#ifdef CONFIG_EDAC_DEBUG
|
#ifdef CONFIG_EDAC_DEBUG
|
||||||
| DDR_ECC_DATA_POISON_SUPPORT
|
| DDR_ECC_DATA_POISON_SUPPORT
|
||||||
@ -976,10 +1003,16 @@ MODULE_DEVICE_TABLE(of, synps_edac_match);
|
|||||||
static void ddr_poison_setup(struct synps_edac_priv *priv)
|
static void ddr_poison_setup(struct synps_edac_priv *priv)
|
||||||
{
|
{
|
||||||
int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval;
|
int col = 0, row = 0, bank = 0, bankgrp = 0, rank = 0, regval;
|
||||||
|
const struct synps_platform_data *p_data;
|
||||||
int index;
|
int index;
|
||||||
ulong hif_addr = 0;
|
ulong hif_addr = 0;
|
||||||
|
|
||||||
hif_addr = priv->poison_addr >> 3;
|
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++) {
|
for (index = 0; index < DDR_MAX_ROW_SHIFT; index++) {
|
||||||
if (priv->row_shift[index])
|
if (priv->row_shift[index])
|
||||||
|
Loading…
Reference in New Issue
Block a user