diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/Makefile | 2 | ||||
-rw-r--r-- | drivers/edac/altera_edac.c | 20 | ||||
-rw-r--r-- | drivers/edac/altera_edac.h | 5 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.c | 35 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.h | 58 | ||||
-rw-r--r-- | drivers/edac/debugfs.c | 163 | ||||
-rw-r--r-- | drivers/edac/edac_core.h | 2 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 2 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 150 | ||||
-rw-r--r-- | drivers/edac/edac_module.h | 34 | ||||
-rw-r--r-- | drivers/edac/ghes_edac.c | 24 | ||||
-rw-r--r-- | drivers/edac/i5100_edac.c | 37 | ||||
-rw-r--r-- | drivers/edac/ppc4xx_edac.c | 1 | ||||
-rw-r--r-- | drivers/edac/sb_edac.c | 8 | ||||
-rw-r--r-- | drivers/edac/xgene_edac.c | 1193 |
15 files changed, 1273 insertions, 461 deletions
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index ae3c5f3ce405..dbf53e08bdd1 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile @@ -12,6 +12,8 @@ obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_core-y += edac_module.o edac_device_sysfs.o +edac_core-$(CONFIG_EDAC_DEBUG) += debugfs.o + ifdef CONFIG_PCI edac_core-y += edac_pci.o edac_pci_sysfs.o endif diff --git a/drivers/edac/altera_edac.c b/drivers/edac/altera_edac.c index 23ef0917483c..929640981d8a 100644 --- a/drivers/edac/altera_edac.c +++ b/drivers/edac/altera_edac.c @@ -51,11 +51,9 @@ static const struct altr_sdram_prv_data c5_data = { .ecc_irq_clr_mask = (CV_DRAMINTR_INTRCLR | CV_DRAMINTR_INTREN), .ecc_cnt_rst_offset = CV_DRAMINTR_OFST, .ecc_cnt_rst_mask = CV_DRAMINTR_INTRCLR, -#ifdef CONFIG_EDAC_DEBUG .ce_ue_trgr_offset = CV_CTLCFG_OFST, .ce_set_mask = CV_CTLCFG_GEN_SB_ERR, .ue_set_mask = CV_CTLCFG_GEN_DB_ERR, -#endif }; static const struct altr_sdram_prv_data a10_data = { @@ -72,11 +70,9 @@ static const struct altr_sdram_prv_data a10_data = { .ecc_irq_clr_mask = (A10_INTSTAT_SBEERR | A10_INTSTAT_DBEERR), .ecc_cnt_rst_offset = A10_ECCCTRL1_OFST, .ecc_cnt_rst_mask = A10_ECC_CNT_RESET_MASK, -#ifdef CONFIG_EDAC_DEBUG .ce_ue_trgr_offset = A10_DIAGINTTEST_OFST, .ce_set_mask = A10_DIAGINT_TSERRA_MASK, .ue_set_mask = A10_DIAGINT_TDERRA_MASK, -#endif }; static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id) @@ -116,7 +112,6 @@ static irqreturn_t altr_sdram_mc_err_handler(int irq, void *dev_id) return IRQ_NONE; } -#ifdef CONFIG_EDAC_DEBUG static ssize_t altr_sdr_mc_err_inject_write(struct file *file, const char __user *data, size_t count, loff_t *ppos) @@ -191,14 +186,15 @@ static const struct file_operations altr_sdr_mc_debug_inject_fops = { static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci) { - if (mci->debugfs) - debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, - &altr_sdr_mc_debug_inject_fops); + if (!IS_ENABLED(CONFIG_EDAC_DEBUG)) + return; + + if (!mci->debugfs) + return; + + edac_debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, + &altr_sdr_mc_debug_inject_fops); } -#else -static void altr_sdr_mc_create_debugfs_nodes(struct mem_ctl_info *mci) -{} -#endif /* Get total memory size from Open Firmware DTB */ static unsigned long get_total_mem(void) diff --git a/drivers/edac/altera_edac.h b/drivers/edac/altera_edac.h index 7b64dc7c4eb7..953077d3e4f3 100644 --- a/drivers/edac/altera_edac.h +++ b/drivers/edac/altera_edac.h @@ -30,8 +30,7 @@ #define CV_CTLCFG_GEN_SB_ERR 0x2000 #define CV_CTLCFG_GEN_DB_ERR 0x4000 -#define CV_CTLCFG_ECC_AUTO_EN (CV_CTLCFG_ECC_EN | \ - CV_CTLCFG_ECC_CORR_EN) +#define CV_CTLCFG_ECC_AUTO_EN (CV_CTLCFG_ECC_EN) /* SDRAM Controller Address Width Register */ #define CV_DRAMADDRW_OFST 0x2C @@ -181,13 +180,11 @@ struct altr_sdram_prv_data { int ecc_irq_clr_mask; int ecc_cnt_rst_offset; int ecc_cnt_rst_mask; -#ifdef CONFIG_EDAC_DEBUG struct edac_dev_sysfs_attribute *eccmgr_sysfs_attr; int ecc_enable_mask; int ce_set_mask; int ue_set_mask; int ce_ue_trgr_offset; -#endif }; /* Altera SDRAM Memory Controller data */ diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index d5fcdbfd99b8..9eee13ef83a5 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c @@ -173,7 +173,7 @@ static inline int amd64_read_dct_pci_cfg(struct amd64_pvt *pvt, u8 dct, * scan the scrub rate mapping table for a close or matching bandwidth value to * issue. If requested is too big, then use last maximum value found. */ -static int __set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate) +static int __set_scrub_rate(struct amd64_pvt *pvt, u32 new_bw, u32 min_rate) { u32 scrubval; int i; @@ -201,7 +201,14 @@ static int __set_scrub_rate(struct pci_dev *ctl, u32 new_bw, u32 min_rate) scrubval = scrubrates[i].scrubval; - pci_write_bits32(ctl, SCRCTRL, scrubval, 0x001F); + if (pvt->fam == 0x15 && pvt->model == 0x60) { + f15h_select_dct(pvt, 0); + pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F); + f15h_select_dct(pvt, 1); + pci_write_bits32(pvt->F2, F15H_M60H_SCRCTRL, scrubval, 0x001F); + } else { + pci_write_bits32(pvt->F3, SCRCTRL, scrubval, 0x001F); + } if (scrubval) return scrubrates[i].bandwidth; @@ -217,11 +224,15 @@ static int set_scrub_rate(struct mem_ctl_info *mci, u32 bw) if (pvt->fam == 0xf) min_scrubrate = 0x0; - /* Erratum #505 */ - if (pvt->fam == 0x15 && pvt->model < 0x10) - f15h_select_dct(pvt, 0); + if (pvt->fam == 0x15) { + /* Erratum #505 */ + if (pvt->model < 0x10) + f15h_select_dct(pvt, 0); - return __set_scrub_rate(pvt->F3, bw, min_scrubrate); + if (pvt->model == 0x60) + min_scrubrate = 0x6; + } + return __set_scrub_rate(pvt, bw, min_scrubrate); } static int get_scrub_rate(struct mem_ctl_info *mci) @@ -230,11 +241,15 @@ static int get_scrub_rate(struct mem_ctl_info *mci) u32 scrubval = 0; int i, retval = -EINVAL; - /* Erratum #505 */ - if (pvt->fam == 0x15 && pvt->model < 0x10) - f15h_select_dct(pvt, 0); + if (pvt->fam == 0x15) { + /* Erratum #505 */ + if (pvt->model < 0x10) + f15h_select_dct(pvt, 0); - amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); + if (pvt->model == 0x60) + amd64_read_pci_cfg(pvt->F2, F15H_M60H_SCRCTRL, &scrubval); + } else + amd64_read_pci_cfg(pvt->F3, SCRCTRL, &scrubval); scrubval = scrubval & 0x001F; diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 4bdec752d330..c0f248f3aaf9 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h @@ -2,64 +2,10 @@ * AMD64 class Memory Controller kernel module * * Copyright (c) 2009 SoftwareBitMaker. - * Copyright (c) 2009 Advanced Micro Devices, Inc. + * Copyright (c) 2009-15 Advanced Micro Devices, Inc. * * This file may be distributed under the terms of the * GNU General Public License. - * - * Originally Written by Thayne Harbaugh - * - * Changes by Douglas "norsk" Thompson <dougthompson@xmission.com>: - * - K8 CPU Revision D and greater support - * - * Changes by Dave Peterson <dsp@llnl.gov> <dave_peterson@pobox.com>: - * - Module largely rewritten, with new (and hopefully correct) - * code for dealing with node and chip select interleaving, - * various code cleanup, and bug fixes - * - Added support for memory hoisting using DRAM hole address - * register - * - * Changes by Douglas "norsk" Thompson <dougthompson@xmission.com>: - * -K8 Rev (1207) revision support added, required Revision - * specific mini-driver code to support Rev F as well as - * prior revisions - * - * Changes by Douglas "norsk" Thompson <dougthompson@xmission.com>: - * -Family 10h revision support added. New PCI Device IDs, - * indicating new changes. Actual registers modified - * were slight, less than the Rev E to Rev F transition - * but changing the PCI Device ID was the proper thing to - * do, as it provides for almost automactic family - * detection. The mods to Rev F required more family - * information detection. - * - * Changes/Fixes by Borislav Petkov <bp@alien8.de>: - * - misc fixes and code cleanups - * - * This module is based on the following documents - * (available from http://www.amd.com/): - * - * Title: BIOS and Kernel Developer's Guide for AMD Athlon 64 and AMD - * Opteron Processors - * AMD publication #: 26094 - *` Revision: 3.26 - * - * Title: BIOS and Kernel Developer's Guide for AMD NPT Family 0Fh - * Processors - * AMD publication #: 32559 - * Revision: 3.00 - * Issue Date: May 2006 - * - * Title: BIOS and Kernel Developer's Guide (BKDG) For AMD Family 10h - * Processors - * AMD publication #: 31116 - * Revision: 3.00 - * Issue Date: September 07, 2007 - * - * Sections in the first 2 documents are no longer in sync with each other. - * The Family 10h BKDG was totally re-written from scratch with a new - * presentation model. - * Therefore, comments that refer to a Document section might be off. */ #include <linux/module.h> @@ -255,6 +201,8 @@ #define DCT_SEL_HI 0x114 +#define F15H_M60H_SCRCTRL 0x1C8 + /* * Function 3 - Misc Control */ diff --git a/drivers/edac/debugfs.c b/drivers/edac/debugfs.c new file mode 100644 index 000000000000..54d2f668cb0a --- /dev/null +++ b/drivers/edac/debugfs.c @@ -0,0 +1,163 @@ +#include "edac_module.h" + +static struct dentry *edac_debugfs; + +static ssize_t edac_fake_inject_write(struct file *file, + const char __user *data, + size_t count, loff_t *ppos) +{ + struct device *dev = file->private_data; + struct mem_ctl_info *mci = to_mci(dev); + static enum hw_event_mc_err_type type; + u16 errcount = mci->fake_inject_count; + + if (!errcount) + errcount = 1; + + type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED + : HW_EVENT_ERR_CORRECTED; + + printk(KERN_DEBUG + "Generating %d %s fake error%s to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n", + errcount, + (type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE", + errcount > 1 ? "s" : "", + mci->fake_inject_layer[0], + mci->fake_inject_layer[1], + mci->fake_inject_layer[2] + ); + edac_mc_handle_error(type, mci, errcount, 0, 0, 0, + mci->fake_inject_layer[0], + mci->fake_inject_layer[1], + mci->fake_inject_layer[2], + "FAKE ERROR", "for EDAC testing only"); + + return count; +} + +static const struct file_operations debug_fake_inject_fops = { + .open = simple_open, + .write = edac_fake_inject_write, + .llseek = generic_file_llseek, +}; + +int __init edac_debugfs_init(void) +{ + edac_debugfs = debugfs_create_dir("edac", NULL); + if (IS_ERR(edac_debugfs)) { + edac_debugfs = NULL; + return -ENOMEM; + } + return 0; +} + +void edac_debugfs_exit(void) +{ + debugfs_remove(edac_debugfs); +} + +int edac_create_debugfs_nodes(struct mem_ctl_info *mci) +{ + struct dentry *d, *parent; + char name[80]; + int i; + + if (!edac_debugfs) + return -ENODEV; + + d = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs); + if (!d) + return -ENOMEM; + parent = d; + + for (i = 0; i < mci->n_layers; i++) { + sprintf(name, "fake_inject_%s", + edac_layer_name[mci->layers[i].type]); + d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent, + &mci->fake_inject_layer[i]); + if (!d) + goto nomem; + } + + d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent, + &mci->fake_inject_ue); + if (!d) + goto nomem; + + d = debugfs_create_u16("fake_inject_count", S_IRUGO | S_IWUSR, parent, + &mci->fake_inject_count); + if (!d) + goto nomem; + + d = debugfs_create_file("fake_inject", S_IWUSR, parent, + &mci->dev, + &debug_fake_inject_fops); + if (!d) + goto nomem; + + mci->debugfs = parent; + return 0; +nomem: + edac_debugfs_remove_recursive(mci->debugfs); + return -ENOMEM; +} + +/* Create a toplevel dir under EDAC's debugfs hierarchy */ +struct dentry *edac_debugfs_create_dir(const char *dirname) +{ + if (!edac_debugfs) + return NULL; + + return debugfs_create_dir(dirname, edac_debugfs); +} +EXPORT_SYMBOL_GPL(edac_debugfs_create_dir); + +/* Create a toplevel dir under EDAC's debugfs hierarchy with parent @parent */ +struct dentry * +edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent) +{ + return debugfs_create_dir(dirname, parent); +} +EXPORT_SYMBOL_GPL(edac_debugfs_create_dir_at); + +/* + * Create a file under EDAC's hierarchy or a sub-hierarchy: + * + * @name: file name + * @mode: file permissions + * @parent: parent dentry. If NULL, it becomes the toplevel EDAC dir + * @data: private data of caller + * @fops: file operations of this file + */ +struct dentry * +edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, + void *data, const struct file_operations *fops) +{ + if (!parent) + parent = edac_debugfs; + + return debugfs_create_file(name, mode, parent, data, fops); +} +EXPORT_SYMBOL_GPL(edac_debugfs_create_file); + +/* Wrapper for debugfs_create_x8() */ +struct dentry *edac_debugfs_create_x8(const char *name, umode_t mode, + struct dentry *parent, u8 *value) +{ + if (!parent) + parent = edac_debugfs; + + return debugfs_create_x8(name, mode, parent, value); +} +EXPORT_SYMBOL_GPL(edac_debugfs_create_x8); + +/* Wrapper for debugfs_create_x16() */ +struct dentry *edac_debugfs_create_x16(const char *name, umode_t mode, + struct dentry *parent, u16 *value) +{ + if (!parent) + parent = edac_debugfs; + + return debugfs_create_x16(name, mode, parent, value); +} +EXPORT_SYMBOL_GPL(edac_debugfs_create_x16); diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index ad42587c3f4d..4861542163d7 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -94,6 +94,8 @@ do { \ #define edac_dev_name(dev) (dev)->dev_name +#define to_mci(k) container_of(k, struct mem_ctl_info, dev) + /* * The following are the structures to provide for a generic * or abstract 'edac_device'. This set of structures and the diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 943ed8cf71b9..77ecd6a4179a 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -1302,7 +1302,7 @@ void edac_mc_handle_error(const enum hw_event_mc_err_type type, grain_bits = fls_long(e->grain) + 1; trace_mc_event(type, e->msg, e->label, e->error_count, mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer, - PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page, + (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page, grain_bits, e->syndrome, e->other_detail); edac_raw_mc_handle_error(type, mci, e); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 33df7d93c857..a75acea0f674 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -229,7 +229,7 @@ static ssize_t channel_dimm_label_show(struct device *dev, if (!rank->dimm->label[0]) return 0; - return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", + return snprintf(data, sizeof(rank->dimm->label) + 1, "%s\n", rank->dimm->label); } @@ -240,14 +240,21 @@ static ssize_t channel_dimm_label_store(struct device *dev, struct csrow_info *csrow = to_csrow(dev); unsigned chan = to_channel(mattr); struct rank_info *rank = csrow->channels[chan]; + size_t copy_count = count; - ssize_t max_size = 0; + if (count == 0) + return -EINVAL; + + if (data[count - 1] == '\0' || data[count - 1] == '\n') + copy_count -= 1; + + if (copy_count == 0 || copy_count >= sizeof(rank->dimm->label)) + return -EINVAL; - max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1); - strncpy(rank->dimm->label, data, max_size); - rank->dimm->label[max_size] = '\0'; + strncpy(rank->dimm->label, data, copy_count); + rank->dimm->label[copy_count] = '\0'; - return max_size; + return count; } /* show function for dynamic chX_ce_count attribute */ @@ -485,7 +492,7 @@ static ssize_t dimmdev_label_show(struct device *dev, if (!dimm->label[0]) return 0; - return snprintf(data, EDAC_MC_LABEL_LEN, "%s\n", dimm->label); + return snprintf(data, sizeof(dimm->label) + 1, "%s\n", dimm->label); } static ssize_t dimmdev_label_store(struct device *dev, @@ -494,14 +501,21 @@ static ssize_t dimmdev_label_store(struct device *dev, size_t count) { struct dimm_info *dimm = to_dimm(dev); + size_t copy_count = count; - ssize_t max_size = 0; + if (count == 0) + return -EINVAL; - max_size = min((ssize_t) count, (ssize_t) EDAC_MC_LABEL_LEN - 1); - strncpy(dimm->label, data, max_size); - dimm->label[max_size] = '\0'; + if (data[count - 1] == '\0' || data[count - 1] == '\n') + copy_count -= 1; - return max_size; + if (copy_count == 0 || copy_count >= sizeof(dimm->label)) + return -EINVAL; + + strncpy(dimm->label, data, copy_count); + dimm->label[copy_count] = '\0'; + + return count; } static ssize_t dimmdev_size_show(struct device *dev, @@ -785,47 +799,6 @@ static ssize_t mci_max_location_show(struct device *dev, return p - data; } -#ifdef CONFIG_EDAC_DEBUG -static ssize_t edac_fake_inject_write(struct file *file, - const char __user *data, - size_t count, loff_t *ppos) -{ - struct device *dev = file->private_data; - struct mem_ctl_info *mci = to_mci(dev); - static enum hw_event_mc_err_type type; - u16 errcount = mci->fake_inject_count; - - if (!errcount) - errcount = 1; - - type = mci->fake_inject_ue ? HW_EVENT_ERR_UNCORRECTED - : HW_EVENT_ERR_CORRECTED; - - printk(KERN_DEBUG - "Generating %d %s fake error%s to %d.%d.%d to test core handling. NOTE: this won't test the driver-specific decoding logic.\n", - errcount, - (type == HW_EVENT_ERR_UNCORRECTED) ? "UE" : "CE", - errcount > 1 ? "s" : "", - mci->fake_inject_layer[0], - mci->fake_inject_layer[1], - mci->fake_inject_layer[2] - ); - edac_mc_handle_error(type, mci, errcount, 0, 0, 0, - mci->fake_inject_layer[0], - mci->fake_inject_layer[1], - mci->fake_inject_layer[2], - "FAKE ERROR", "for EDAC testing only"); - - return count; -} - -static const struct file_operations debug_fake_inject_fops = { - .open = simple_open, - .write = edac_fake_inject_write, - .llseek = generic_file_llseek, -}; -#endif - /* default Control file */ static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store); @@ -896,71 +869,6 @@ static struct device_type mci_attr_type = { .release = mci_attr_release, }; -#ifdef CONFIG_EDAC_DEBUG -static struct dentry *edac_debugfs; - -int __init edac_debugfs_init(void) -{ - edac_debugfs = debugfs_create_dir("edac", NULL); - if (IS_ERR(edac_debugfs)) { - edac_debugfs = NULL; - return -ENOMEM; - } - return 0; -} - -void edac_debugfs_exit(void) -{ - debugfs_remove(edac_debugfs); -} - -static int edac_create_debug_nodes(struct mem_ctl_info *mci) -{ - struct dentry *d, *parent; - char name[80]; - int i; - - if (!edac_debugfs) - return -ENODEV; - - d = debugfs_create_dir(mci->dev.kobj.name, edac_debugfs); - if (!d) - return -ENOMEM; - parent = d; - - for (i = 0; i < mci->n_layers; i++) { - sprintf(name, "fake_inject_%s", - edac_layer_name[mci->layers[i].type]); - d = debugfs_create_u8(name, S_IRUGO | S_IWUSR, parent, - &mci->fake_inject_layer[i]); - if (!d) - goto nomem; - } - - d = debugfs_create_bool("fake_inject_ue", S_IRUGO | S_IWUSR, parent, - &mci->fake_inject_ue); - if (!d) - goto nomem; - - d = debugfs_create_u16("fake_inject_count", S_IRUGO | S_IWUSR, parent, - &mci->fake_inject_count); - if (!d) - goto nomem; - - d = debugfs_create_file("fake_inject", S_IWUSR, parent, - &mci->dev, - &debug_fake_inject_fops); - if (!d) - goto nomem; - - mci->debugfs = parent; - return 0; -nomem: - debugfs_remove(mci->debugfs); - return -ENOMEM; -} -#endif - /* * Create a new Memory Controller kobject instance, * mc<id> under the 'mc' directory @@ -1039,9 +947,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, goto fail_unregister_dimm; #endif -#ifdef CONFIG_EDAC_DEBUG - edac_create_debug_nodes(mci); -#endif + edac_create_debugfs_nodes(mci); return 0; fail_unregister_dimm: @@ -1070,7 +976,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) edac_dbg(0, "\n"); #ifdef CONFIG_EDAC_DEBUG - debugfs_remove(mci->debugfs); + edac_debugfs_remove_recursive(mci->debugfs); #endif #ifdef CONFIG_EDAC_LEGACY_SYSFS edac_delete_csrow_objects(mci); diff --git a/drivers/edac/edac_module.h b/drivers/edac/edac_module.h index 26ecc52e073d..b95a48fc723d 100644 --- a/drivers/edac/edac_module.h +++ b/drivers/edac/edac_module.h @@ -60,15 +60,39 @@ extern void *edac_align_ptr(void **p, unsigned size, int n_elems); /* * EDAC debugfs functions */ + +#define edac_debugfs_remove_recursive debugfs_remove_recursive +#define edac_debugfs_remove debugfs_remove #ifdef CONFIG_EDAC_DEBUG int edac_debugfs_init(void); void edac_debugfs_exit(void); +int edac_create_debugfs_nodes(struct mem_ctl_info *mci); +struct dentry *edac_debugfs_create_dir(const char *dirname); +struct dentry * +edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent); +struct dentry * +edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, + void *data, const struct file_operations *fops); +struct dentry * +edac_debugfs_create_x8(const char *name, umode_t mode, struct dentry *parent, u8 *value); +struct dentry * +edac_debugfs_create_x16(const char *name, umode_t mode, struct dentry *parent, u16 *value); #else -static inline int edac_debugfs_init(void) -{ - return -ENODEV; -} -static inline void edac_debugfs_exit(void) {} +static inline int edac_debugfs_init(void) { return -ENODEV; } +static inline void edac_debugfs_exit(void) { } +static inline int edac_create_debugfs_nodes(struct mem_ctl_info *mci) { return 0; } +static inline struct dentry *edac_debugfs_create_dir(const char *dirname) { return NULL; } +static inline struct dentry * +edac_debugfs_create_dir_at(const char *dirname, struct dentry *parent) { return NULL; } +static inline struct dentry * +edac_debugfs_create_file(const char *name, umode_t mode, struct dentry *parent, + void *data, const struct file_operations *fops) { return NULL; } +static inline struct dentry * +edac_debugfs_create_x8(const char *name, umode_t mode, + struct dentry *parent, u8 *value) { return NULL; } +static inline struct dentry * +edac_debugfs_create_x16(const char *name, umode_t mode, + struct dentry *parent, u16 *value) { return NULL; } #endif /* diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index b24681998740..e3fa4390f846 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c @@ -66,26 +66,6 @@ struct ghes_edac_dimm_fill { unsigned count; }; -char *memory_type[] = { - [MEM_EMPTY] = "EMPTY", - [MEM_RESERVED] = "RESERVED", - [MEM_UNKNOWN] = "UNKNOWN", - [MEM_FPM] = "FPM", - [MEM_EDO] = "EDO", - [MEM_BEDO] = "BEDO", - [MEM_SDR] = "SDR", - [MEM_RDR] = "RDR", - [MEM_DDR] = "DDR", - [MEM_RDDR] = "RDDR", - [MEM_RMBS] = "RMBS", - [MEM_DDR2] = "DDR2", - [MEM_FB_DDR2] = "FB_DDR2", - [MEM_RDDR2] = "RDDR2", - [MEM_XDR] = "XDR", - [MEM_DDR3] = "DDR3", - [MEM_RDDR3] = "RDDR3", -}; - static void ghes_edac_count_dimms(const struct dmi_header *dh, void *arg) { int *num_dimm = arg; @@ -173,7 +153,7 @@ static void ghes_edac_dmidecode(const struct dmi_header *dh, void *arg) if (dimm->nr_pages) { edac_dbg(1, "DIMM%i: %s size = %d MB%s\n", - dimm_fill->count, memory_type[dimm->mtype], + dimm_fill->count, edac_mem_types[dimm->mtype], PAGES_TO_MiB(dimm->nr_pages), (dimm->edac_mode != EDAC_NONE) ? "(ECC)" : ""); edac_dbg(2, "\ttype %d, detail 0x%02x, width %d(total %d)\n", @@ -417,7 +397,7 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, "APEI location: %s %s", e->location, e->other_detail); trace_mc_event(type, e->msg, e->label, e->error_count, mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer, - PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page, + (e->page_frame_number << PAGE_SHIFT) | e->offset_in_page, grain_bits, e->syndrome, pvt->detail_location); /* Report the error via EDAC API */ diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c index e9f8a393915a..40917775dca1 100644 --- a/drivers/edac/i5100_edac.c +++ b/drivers/edac/i5100_edac.c @@ -30,6 +30,7 @@ #include <linux/debugfs.h> #include "edac_core.h" +#include "edac_module.h" /* register addresses */ @@ -966,25 +967,25 @@ static int i5100_setup_debugfs(struct mem_ctl_info *mci) if (!i5100_debugfs) return -ENODEV; - priv->debugfs = debugfs_create_dir(mci->bus->name, i5100_debugfs); + priv->debugfs = edac_debugfs_create_dir_at(mci->bus->name, i5100_debugfs); if (!priv->debugfs) return -ENOMEM; - debugfs_create_x8("inject_channel", S_IRUGO | S_IWUSR, priv->debugfs, - &priv->inject_channel); - debugfs_create_x8("inject_hlinesel", S_IRUGO | S_IWUSR, priv->debugfs, - &priv->inject_hlinesel); - debugfs_create_x8("inject_deviceptr1", S_IRUGO | S_IWUSR, priv->debugfs, - &priv->inject_deviceptr1); - debugfs_create_x8("inject_deviceptr2", S_IRUGO | S_IWUSR, priv->debugfs, - &priv->inject_deviceptr2); - debugfs_create_x16("inject_eccmask1", S_IRUGO | S_IWUSR, priv->debugfs, - &priv->inject_eccmask1); - debugfs_create_x16("inject_eccmask2", S_IRUGO | S_IWUSR, priv->debugfs, - &priv->inject_eccmask2); - debugfs_create_file("inject_enable", S_IWUSR, priv->debugfs, - &mci->dev, &i5100_inject_enable_fops); + edac_debugfs_create_x8("inject_channel", S_IRUGO | S_IWUSR, priv->debugfs, + &priv->inject_channel); + edac_debugfs_create_x8("inject_hlinesel", S_IRUGO | S_IWUSR, priv->debugfs, + &priv->inject_hlinesel); + edac_debugfs_create_x8("inject_deviceptr1", S_IRUGO | S_IWUSR, priv->debugfs, + &priv->inject_deviceptr1); + edac_debugfs_create_x8("inject_deviceptr2", S_IRUGO | S_IWUSR, priv->debugfs, + &priv->inject_deviceptr2); + edac_debugfs_create_x16("inject_eccmask1", S_IRUGO | S_IWUSR, priv->debugfs, + &priv->inject_eccmask1); + edac_debugfs_create_x16("inject_eccmask2", S_IRUGO | S_IWUSR, priv->debugfs, + &priv->inject_eccmask2); + edac_debugfs_create_file("inject_enable", S_IWUSR, priv->debugfs, + &mci->dev, &i5100_inject_enable_fops); return 0; @@ -1189,7 +1190,7 @@ static void i5100_remove_one(struct pci_dev *pdev) priv = mci->pvt_info; - debugfs_remove_recursive(priv->debugfs); + edac_debugfs_remove_recursive(priv->debugfs); priv->scrub_enable = 0; cancel_delayed_work_sync(&(priv->i5100_scrubbing)); @@ -1223,7 +1224,7 @@ static int __init i5100_init(void) { int pci_rc; - i5100_debugfs = debugfs_create_dir("i5100_edac", NULL); + i5100_debugfs = edac_debugfs_create_dir_at("i5100_edac", NULL); pci_rc = pci_register_driver(&i5100_driver); return (pci_rc < 0) ? pci_rc : 0; @@ -1231,7 +1232,7 @@ static int __init i5100_init(void) static void __exit i5100_exit(void) { - debugfs_remove(i5100_debugfs); + edac_debugfs_remove(i5100_debugfs); pci_unregister_driver(&i5100_driver); } diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 711d8ad74f11..d3a64ba61fa3 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c @@ -199,6 +199,7 @@ static const struct of_device_id ppc4xx_edac_match[] = { }, { } }; +MODULE_DEVICE_TABLE(of, ppc4xx_edac_match); static struct platform_driver ppc4xx_edac_driver = { .probe = ppc4xx_edac_probe, diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index cf1268ddef0c..429309c62699 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c @@ -1688,6 +1688,7 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, { struct sbridge_pvt *pvt = mci->pvt_info; struct pci_dev *pdev; + u8 saw_chan_mask = 0; int i; for (i = 0; i < sbridge_dev->n_devs; i++) { @@ -1721,6 +1722,7 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, { int id = pdev->device - PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TAD0; pvt->pci_tad[id] = pdev; + saw_chan_mask |= 1 << id; } break; case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_DDRIO: @@ -1741,10 +1743,8 @@ static int sbridge_mci_bind_devs(struct mem_ctl_info *mci, !pvt-> pci_tad || !pvt->pci_ras || !pvt->pci_ta) goto enodev; - for (i = 0; i < NUM_CHANNELS; i++) { - if (!pvt->pci_tad[i]) - goto enodev; - } + if (saw_chan_mask != 0x0f) + goto enodev; return 0; enodev: diff --git a/drivers/edac/xgene_edac.c b/drivers/edac/xgene_edac.c index ba06904af2e1..41f876414a18 100644 --- a/drivers/edac/xgene_edac.c +++ b/drivers/edac/xgene_edac.c @@ -29,6 +29,7 @@ #include <linux/regmap.h> #include "edac_core.h" +#include "edac_module.h" #define EDAC_MOD_STR "xgene_edac" @@ -62,10 +63,12 @@ struct xgene_edac { struct regmap *efuse_map; void __iomem *pcp_csr; spinlock_t lock; - struct dentry *dfs; + struct dentry *dfs; struct list_head mcus; struct list_head pmds; + struct list_head l3s; + struct list_head socs; struct mutex mc_lock; int mc_active_mask; @@ -172,12 +175,12 @@ static void xgene_edac_mc_create_debugfs_node(struct mem_ctl_info *mci) { if (!IS_ENABLED(CONFIG_EDAC_DEBUG)) return; -#ifdef CONFIG_EDAC_DEBUG + if (!mci->debugfs) return; - debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, - &xgene_edac_mc_debug_inject_fops); -#endif + + edac_debugfs_create_file("inject_ctrl", S_IWUSR, mci->debugfs, mci, + &xgene_edac_mc_debug_inject_fops); } static void xgene_edac_mc_check(struct mem_ctl_info *mci) @@ -536,140 +539,134 @@ static void xgene_edac_pmd_l1_check(struct edac_device_ctl_info *edac_dev, pg_f = ctx->pmd_csr + cpu_idx * CPU_CSR_STRIDE + CPU_MEMERR_CPU_PAGE; val = readl(pg_f + MEMERR_CPU_ICFESR_PAGE_OFFSET); - if (val) { - dev_err(edac_dev->dev, - "CPU%d L1 memory error ICF 0x%08X Way 0x%02X Index 0x%02X Info 0x%02X\n", - ctx->pmd * MAX_CPU_PER_PMD + cpu_idx, val, - MEMERR_CPU_ICFESR_ERRWAY_RD(val), - MEMERR_CPU_ICFESR_ERRINDEX_RD(val), - MEMERR_CPU_ICFESR_ERRINFO_RD(val)); - if (val & MEMERR_CPU_ICFESR_CERR_MASK) - dev_err(edac_dev->dev, - "One or more correctable error\n"); - if (val & MEMERR_CPU_ICFESR_MULTCERR_MASK) - dev_err(edac_dev->dev, "Multiple correctable error\n"); - switch (MEMERR_CPU_ICFESR_ERRTYPE_RD(val)) { - case 1: - dev_err(edac_dev->dev, "L1 TLB multiple hit\n"); - break; - case 2: - dev_err(edac_dev->dev, "Way select multiple hit\n"); - break; - case 3: - dev_err(edac_dev->dev, "Physi |