]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
EDAC/synopsys: Fix error injection on Zynq UltraScale+
authorShubhrajyoti Datta <shubhrajyoti.datta@amd.com>
Thu, 11 Jul 2024 10:06:56 +0000 (15:36 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Oct 2024 13:10:42 +0000 (15:10 +0200)
[ 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: 1a81361f75d8 ("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>
drivers/edac/synopsys_edac.c

index feb203efcffffc566e3488457bdc0458e3a62b01..e8ddb029f10d898d101d7faf14b78bc34f750f20 100644 (file)
@@ -23,6 +23,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>
 #include <linux/of_device.h>
@@ -351,6 +352,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 {
@@ -358,6 +360,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;
 };
 
@@ -416,6 +421,25 @@ out:
        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.
@@ -936,6 +960,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
@@ -989,10 +1016,16 @@ 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;
 
-       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++) {
                if (priv->row_shift[index])