diff options
author | Qiuxu Zhuo <qiuxu.zhuo@intel.com> | 2020-11-05 15:49:34 +0800 |
---|---|---|
committer | Tony Luck <tony.luck@intel.com> | 2020-11-19 12:52:47 -0800 |
commit | 2223d8c781a0c1a8cf26b1d8f13aff84557ecbfc (patch) | |
tree | 1f56140d993959cd1a85512a6a4d6d1f950a450a /drivers/edac | |
parent | 10590a9d4f23e0a519730d79d39331df60ad2079 (diff) | |
download | linux-2223d8c781a0c1a8cf26b1d8f13aff84557ecbfc.tar.bz2 |
EDAC/igen6: Add debugfs interface for Intel client SoC EDAC driver
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>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/igen6_edac.c | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/drivers/edac/igen6_edac.c b/drivers/edac/igen6_edac.c index 318b9b67080f..6c0039e1171f 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); |