diff mbox series

[v1,3/3] EDAC/igen6: Add debugfs interface for Intel client SoC EDAC driver

Message ID 20201105074934.3915-1-qiuxu.zhuo@intel.com (mailing list archive)
State New, archived
Headers show
Series Add EDAC driver for Intel client SoCs using In-Band ECC | expand

Commit Message

Zhuo, Qiuxu Nov. 5, 2020, 7:49 a.m. UTC
Add debugfs support to fake memory correctable errors to test the
error reporting path and the error address decoding logic in the
igen6_edac driver.

Please note that the fake errors are also reported to EDAC core and
then the CE counter in EDAC sysfs is also increased.

Signed-off-by: Qiuxu Zhuo <qiuxu.zhuo@intel.com>
---
 drivers/edac/igen6_edac.c | 59 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 59 insertions(+)
diff mbox series

Patch

diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c
index b8a6d692c1e4..5a5e7e9ffcb7 100644
--- a/drivers/edac/igen6_edac.c
+++ b/drivers/edac/igen6_edac.c
@@ -612,6 +612,10 @@  static int igen6_get_dimm_config(struct mem_ctl_info *mci)
 }
 
 #ifdef CONFIG_EDAC_DEBUG
+/* Top of upper usable DRAM */
+static u64 igen6_touud;
+#define TOUUD_OFFSET	0xa8
+
 static void igen6_reg_dump(struct igen6_imc *imc)
 {
 	int i;
@@ -632,10 +636,54 @@  static void igen6_reg_dump(struct igen6_imc *imc)
 			 readl(imc->window + MAD_DIMM_CH0_OFFSET + i * 4));
 	}
 	edac_dbg(2, "TOLUD            : 0x%x", igen6_tolud);
+	edac_dbg(2, "TOUUD            : 0x%llx", igen6_touud);
 	edac_dbg(2, "TOM              : 0x%llx", igen6_tom);
 }
+
+static struct dentry *igen6_test;
+
+static int debugfs_u64_set(void *data, u64 val)
+{
+	u64 ecclog;
+
+	if ((val >= igen6_tolud && val < _4GB) || val >= igen6_touud) {
+		edac_dbg(0, "Address 0x%llx out of range\n", val);
+		return 0;
+	}
+
+	pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val);
+
+	val  >>= ECC_ERROR_LOG_ADDR_SHIFT;
+	ecclog = (val << ECC_ERROR_LOG_ADDR_SHIFT) | ECC_ERROR_LOG_CE;
+
+	if (!ecclog_gen_pool_add(0, ecclog))
+		irq_work_queue(&ecclog_irq_work);
+
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
+
+static void igen6_debug_setup(void)
+{
+	igen6_test = edac_debugfs_create_dir("igen6_test");
+	if (!igen6_test)
+		return;
+
+	if (!edac_debugfs_create_file("addr", 0200, igen6_test,
+				      NULL, &fops_u64_wo)) {
+		debugfs_remove(igen6_test);
+		igen6_test = NULL;
+	}
+}
+
+static void igen6_debug_teardown(void)
+{
+	debugfs_remove_recursive(igen6_test);
+}
 #else
 static void igen6_reg_dump(struct igen6_imc *imc) {}
+static void igen6_debug_setup(void) {}
+static void igen6_debug_teardown(void) {}
 #endif
 
 static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar)
@@ -691,6 +739,15 @@  static int igen6_pci_setup(struct pci_dev *pdev, u64 *mchbar)
 
 	*mchbar = MCHBAR_BASE(u.v);
 
+#ifdef CONFIG_EDAC_DEBUG
+	if (pci_read_config_dword(pdev, TOUUD_OFFSET, &u.v_lo))
+		edac_dbg(2, "Failed to read lower TOUUD\n");
+	else if (pci_read_config_dword(pdev, TOUUD_OFFSET + 4, &u.v_hi))
+		edac_dbg(2, "Failed to read upper TOUUD\n");
+	else
+		igen6_touud = u.v & GENMASK_ULL(38, 20);
+#endif
+
 	return 0;
 fail:
 	return -ENODEV;
@@ -849,6 +906,7 @@  static int igen6_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		goto fail4;
 	}
 
+	igen6_debug_setup();
 	return 0;
 fail4:
 	unregister_nmi_handler(NMI_SERR, IGEN6_NMI_NAME);
@@ -865,6 +923,7 @@  static void igen6_remove(struct pci_dev *pdev)
 {
 	edac_dbg(2, "\n");
 
+	igen6_debug_teardown();
 	errcmd_enable_error_reporting(false);
 	unregister_nmi_handler(NMI_SERR, IGEN6_NMI_NAME);
 	irq_work_sync(&ecclog_irq_work);