Commit b271b212 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'edac_for_4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp

Pull EDAC updates from Borislav Petkov:

 - Support for ZynqMP DDR controller support to synopsys_edac along with
   a driver cleanup and generalization for the addition of support for
   the new IP. (Manish Narani)

 - Removal of the /sys/bus/edac devices hierarchy. This enabled us to
   get rid of the silly memory controllers maximum number notion. (Tony
   Luck and Borislav Petkov)

 - skx_edac improvements and fixes. (Qiuxu Zhuo and Tony Luck)

 - The usual garden variety of small cleanups and fixes.

* tag 'edac_for_4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp: (25 commits)
  EDAC, fsl_ddr: Add LS1021A to the list of supported hardware
  EDAC, i5000: Remove set but not used local variables
  MAINTAINERS, EDAC: Drop bouncing email
  EDAC, i82975x: Fix spelling mistake "reserverd" -> "reserved"
  EDAC, fsl: Move error injection under CONFIG_EDAC_DEBUG
  EDAC, skx: Let EDAC core show the decoded result for debugfs
  EDAC, skx: Move debugfs node under EDAC's hierarchy
  EDAC, skx: Prepend hex formatting with '0x'
  EDAC, skx: Fix function calling order in skx_exit()
  EDAC: Drop per-memory controller buses
  EDAC: Don't add devices under /sys/bus/edac
  EDAC: Fix indentation issues in several EDAC drivers
  EDAC, skx: Fix randconfig builds in a better way
  EDAC, i82975x: Remove set but not used variable dtype
  EDAC, qcom_edac: Remove irq_handled local variable
  EDAC, synopsys: Add Error Injection support for ZynqMP DDR controller
  EDAC, synopsys: Add ECC support for ZynqMP DDR controller
  EDAC, synopsys: Add macro defines for ZynqMP DDRC
  dt: bindings: Document ZynqMP DDRC in Synopsys documentation
  EDAC, synopsys: Add error handling for the of_device_get_match_data() result
  ...
parents 8e61e7b5 75dfa870
Binding for Synopsys IntelliDDR Multi Protocol Memory Controller Binding for Synopsys IntelliDDR Multi Protocol Memory Controller
This controller has an optional ECC support in half-bus width (16-bit) The ZynqMP DDR ECC controller has an optional ECC support in 64-bit and 32-bit
configuration. The ECC controller corrects one bit error and detects bus width configurations.
two bit errors.
The Zynq DDR ECC controller has an optional ECC support in half-bus width
(16-bit) configuration.
These both ECC controllers correct single bit ECC errors and detect double bit
ECC errors.
Required properties: Required properties:
- compatible: Should be 'xlnx,zynq-ddrc-a05' - compatible: One of:
- reg: Base address and size of the controllers memory area - 'xlnx,zynq-ddrc-a05' : Zynq DDR ECC controller
- 'xlnx,zynqmp-ddrc-2.40a' : ZynqMP DDR ECC controller
- reg: Should contain DDR controller registers location and length.
Required properties for "xlnx,zynqmp-ddrc-2.40a":
- interrupts: Property with a value describing the interrupt number.
Example: Example:
memory-controller@f8006000 { memory-controller@f8006000 {
compatible = "xlnx,zynq-ddrc-a05"; compatible = "xlnx,zynq-ddrc-a05";
reg = <0xf8006000 0x1000>; reg = <0xf8006000 0x1000>;
}; };
mc: memory-controller@fd070000 {
compatible = "xlnx,zynqmp-ddrc-2.40a";
reg = <0x0 0xfd070000 0x0 0x30000>;
interrupt-parent = <&gic>;
interrupts = <0 112 4>;
};
...@@ -5445,7 +5445,6 @@ S: Maintained ...@@ -5445,7 +5445,6 @@ S: Maintained
F: drivers/edac/i82443bxgx_edac.c F: drivers/edac/i82443bxgx_edac.c
EDAC-I82975X EDAC-I82975X
M: Ranganathan Desikan <ravi@jetztechnologies.com>
M: "Arvind R." <arvino55@gmail.com> M: "Arvind R." <arvino55@gmail.com>
L: linux-edac@vger.kernel.org L: linux-edac@vger.kernel.org
S: Maintained S: Maintained
......
...@@ -231,10 +231,10 @@ config EDAC_SBRIDGE ...@@ -231,10 +231,10 @@ config EDAC_SBRIDGE
config EDAC_SKX config EDAC_SKX
tristate "Intel Skylake server Integrated MC" tristate "Intel Skylake server Integrated MC"
depends on PCI && X86_64 && X86_MCE_INTEL && PCI_MMCONFIG depends on PCI && X86_64 && X86_MCE_INTEL && PCI_MMCONFIG && ACPI
depends on ACPI_NFIT || !ACPI_NFIT # if ACPI_NFIT=m, EDAC_SKX can't be y depends on ACPI_NFIT || !ACPI_NFIT # if ACPI_NFIT=m, EDAC_SKX can't be y
select DMI select DMI
select ACPI_ADXL if ACPI select ACPI_ADXL
help help
Support for error detection and correction the Intel Support for error detection and correction the Intel
Skylake server Integrated Memory Controllers. If your Skylake server Integrated Memory Controllers. If your
...@@ -442,7 +442,7 @@ config EDAC_ALTERA_SDMMC ...@@ -442,7 +442,7 @@ config EDAC_ALTERA_SDMMC
config EDAC_SYNOPSYS config EDAC_SYNOPSYS
tristate "Synopsys DDR Memory Controller" tristate "Synopsys DDR Memory Controller"
depends on ARCH_ZYNQ depends on ARCH_ZYNQ || ARCH_ZYNQMP
help help
Support for error detection and correction on the Synopsys DDR Support for error detection and correction on the Synopsys DDR
memory controller. memory controller.
......
...@@ -1446,8 +1446,8 @@ static int __init e752x_init(void) ...@@ -1446,8 +1446,8 @@ static int __init e752x_init(void)
edac_dbg(3, "\n"); edac_dbg(3, "\n");
/* Ensure that the OPSTATE is set correctly for POLL or NMI */ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
opstate_init(); opstate_init();
pci_rc = pci_register_driver(&e752x_driver); pci_rc = pci_register_driver(&e752x_driver);
return (pci_rc < 0) ? pci_rc : 0; return (pci_rc < 0) ? pci_rc : 0;
......
...@@ -55,8 +55,6 @@ static LIST_HEAD(mc_devices); ...@@ -55,8 +55,6 @@ static LIST_HEAD(mc_devices);
*/ */
static const char *edac_mc_owner; static const char *edac_mc_owner;
static struct bus_type mc_bus[EDAC_MAX_MCS];
int edac_get_report_status(void) int edac_get_report_status(void)
{ {
return edac_report; return edac_report;
...@@ -716,11 +714,6 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, ...@@ -716,11 +714,6 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
int ret = -EINVAL; int ret = -EINVAL;
edac_dbg(0, "\n"); edac_dbg(0, "\n");
if (mci->mc_idx >= EDAC_MAX_MCS) {
pr_warn_once("Too many memory controllers: %d\n", mci->mc_idx);
return -ENODEV;
}
#ifdef CONFIG_EDAC_DEBUG #ifdef CONFIG_EDAC_DEBUG
if (edac_debug_level >= 3) if (edac_debug_level >= 3)
edac_mc_dump_mci(mci); edac_mc_dump_mci(mci);
...@@ -760,7 +753,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci, ...@@ -760,7 +753,7 @@ int edac_mc_add_mc_with_groups(struct mem_ctl_info *mci,
/* set load time so that error rate can be tracked */ /* set load time so that error rate can be tracked */
mci->start_time = jiffies; mci->start_time = jiffies;
mci->bus = &mc_bus[mci->mc_idx]; mci->bus = edac_get_sysfs_subsys();
if (edac_create_sysfs_mci_device(mci, groups)) { if (edac_create_sysfs_mci_device(mci, groups)) {
edac_mc_printk(mci, KERN_WARNING, edac_mc_printk(mci, KERN_WARNING,
......
...@@ -405,7 +405,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci, ...@@ -405,7 +405,6 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
struct csrow_info *csrow, int index) struct csrow_info *csrow, int index)
{ {
csrow->dev.type = &csrow_attr_type; csrow->dev.type = &csrow_attr_type;
csrow->dev.bus = mci->bus;
csrow->dev.groups = csrow_dev_groups; csrow->dev.groups = csrow_dev_groups;
device_initialize(&csrow->dev); device_initialize(&csrow->dev);
csrow->dev.parent = &mci->dev; csrow->dev.parent = &mci->dev;
...@@ -636,7 +635,6 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci, ...@@ -636,7 +635,6 @@ static int edac_create_dimm_object(struct mem_ctl_info *mci,
dimm->mci = mci; dimm->mci = mci;
dimm->dev.type = &dimm_attr_type; dimm->dev.type = &dimm_attr_type;
dimm->dev.bus = mci->bus;
device_initialize(&dimm->dev); device_initialize(&dimm->dev);
dimm->dev.parent = &mci->dev; dimm->dev.parent = &mci->dev;
...@@ -914,33 +912,13 @@ static const struct device_type mci_attr_type = { ...@@ -914,33 +912,13 @@ static const struct device_type mci_attr_type = {
int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
const struct attribute_group **groups) const struct attribute_group **groups)
{ {
char *name;
int i, err; int i, err;
/*
* The memory controller needs its own bus, in order to avoid
* namespace conflicts at /sys/bus/edac.
*/
name = kasprintf(GFP_KERNEL, "mc%d", mci->mc_idx);
if (!name)
return -ENOMEM;
mci->bus->name = name;
edac_dbg(0, "creating bus %s\n", mci->bus->name);
err = bus_register(mci->bus);
if (err < 0) {
kfree(name);
return err;
}
/* get the /sys/devices/system/edac subsys reference */ /* get the /sys/devices/system/edac subsys reference */
mci->dev.type = &mci_attr_type; mci->dev.type = &mci_attr_type;
device_initialize(&mci->dev); device_initialize(&mci->dev);
mci->dev.parent = mci_pdev; mci->dev.parent = mci_pdev;
mci->dev.bus = mci->bus;
mci->dev.groups = groups; mci->dev.groups = groups;
dev_set_name(&mci->dev, "mc%d", mci->mc_idx); dev_set_name(&mci->dev, "mc%d", mci->mc_idx);
dev_set_drvdata(&mci->dev, mci); dev_set_drvdata(&mci->dev, mci);
...@@ -950,7 +928,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, ...@@ -950,7 +928,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
err = device_add(&mci->dev); err = device_add(&mci->dev);
if (err < 0) { if (err < 0) {
edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev)); edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
goto fail_unregister_bus; goto out;
} }
/* /*
...@@ -998,10 +976,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci, ...@@ -998,10 +976,8 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci,
device_unregister(&dimm->dev); device_unregister(&dimm->dev);
} }
device_unregister(&mci->dev); device_unregister(&mci->dev);
fail_unregister_bus:
bus_unregister(mci->bus);
kfree(name);
out:
return err; return err;
} }
...@@ -1032,13 +1008,8 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) ...@@ -1032,13 +1008,8 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci)
void edac_unregister_sysfs(struct mem_ctl_info *mci) void edac_unregister_sysfs(struct mem_ctl_info *mci)
{ {
struct bus_type *bus = mci->bus;
const char *name = mci->bus->name;
edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev)); edac_dbg(1, "Unregistering device %s\n", dev_name(&mci->dev));
device_unregister(&mci->dev); device_unregister(&mci->dev);
bus_unregister(bus);
kfree(name);
} }
static void mc_attr_release(struct device *dev) static void mc_attr_release(struct device *dev)
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* Freescale Memory Controller kernel module * Freescale Memory Controller kernel module
* *
* Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and
* ARM-based Layerscape SoCs including LS2xxx. Originally split * ARM-based Layerscape SoCs including LS2xxx and LS1021A. Originally
* out from mpc85xx_edac EDAC driver. * split out from mpc85xx_edac EDAC driver.
* *
* Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc. * Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.
* *
...@@ -51,6 +51,7 @@ static inline void ddr_out32(void __iomem *addr, u32 value) ...@@ -51,6 +51,7 @@ static inline void ddr_out32(void __iomem *addr, u32 value)
iowrite32be(value, addr); iowrite32be(value, addr);
} }
#ifdef CONFIG_EDAC_DEBUG
/************************ MC SYSFS parts ***********************************/ /************************ MC SYSFS parts ***********************************/
#define to_mci(k) container_of(k, struct mem_ctl_info, dev) #define to_mci(k) container_of(k, struct mem_ctl_info, dev)
...@@ -151,11 +152,14 @@ static DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR, ...@@ -151,11 +152,14 @@ static DEVICE_ATTR(inject_data_lo, S_IRUGO | S_IWUSR,
fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store); fsl_mc_inject_data_lo_show, fsl_mc_inject_data_lo_store);
static DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR, static DEVICE_ATTR(inject_ctrl, S_IRUGO | S_IWUSR,
fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store); fsl_mc_inject_ctrl_show, fsl_mc_inject_ctrl_store);
#endif /* CONFIG_EDAC_DEBUG */
static struct attribute *fsl_ddr_dev_attrs[] = { static struct attribute *fsl_ddr_dev_attrs[] = {
#ifdef CONFIG_EDAC_DEBUG
&dev_attr_inject_data_hi.attr, &dev_attr_inject_data_hi.attr,
&dev_attr_inject_data_lo.attr, &dev_attr_inject_data_lo.attr,
&dev_attr_inject_ctrl.attr, &dev_attr_inject_ctrl.attr,
#endif
NULL NULL
}; };
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
* Freescale Memory Controller kernel module * Freescale Memory Controller kernel module
* *
* Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and * Support Power-based SoCs including MPC85xx, MPC86xx, MPC83xx and
* ARM-based Layerscape SoCs including LS2xxx. Originally split * ARM-based Layerscape SoCs including LS2xxx and LS1021A. Originally
* out from mpc85xx_edac EDAC driver. * split out from mpc85xx_edac EDAC driver.
* *
* Author: Dave Jiang <djiang@mvista.com> * Author: Dave Jiang <djiang@mvista.com>
* *
......
...@@ -508,8 +508,8 @@ static int __init i3000_init(void) ...@@ -508,8 +508,8 @@ static int __init i3000_init(void)
edac_dbg(3, "MC:\n"); edac_dbg(3, "MC:\n");
/* Ensure that the OPSTATE is set correctly for POLL or NMI */ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
opstate_init(); opstate_init();
pci_rc = pci_register_driver(&i3000_driver); pci_rc = pci_register_driver(&i3000_driver);
if (pci_rc < 0) if (pci_rc < 0)
......
...@@ -1134,8 +1134,6 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci) ...@@ -1134,8 +1134,6 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
u32 actual_tolm; u32 actual_tolm;
u16 limit; u16 limit;
int slot_row; int slot_row;
int maxch;
int maxdimmperch;
int way0, way1; int way0, way1;
pvt = mci->pvt_info; pvt = mci->pvt_info;
...@@ -1145,9 +1143,6 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci) ...@@ -1145,9 +1143,6 @@ static void i5000_get_mc_regs(struct mem_ctl_info *mci)
pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32), pci_read_config_dword(pvt->system_address, AMBASE + sizeof(u32),
&pvt->u.ambase_top); &pvt->u.ambase_top);
maxdimmperch = pvt->maxdimmperch;
maxch = pvt->maxch;
edac_dbg(2, "AMBASE= 0x%lx MAXCH= %d MAX-DIMM-Per-CH= %d\n", edac_dbg(2, "AMBASE= 0x%lx MAXCH= %d MAX-DIMM-Per-CH= %d\n",
(long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch); (long unsigned int)pvt->ambase, pvt->maxch, pvt->maxdimmperch);
...@@ -1253,7 +1248,7 @@ static int i5000_init_csrows(struct mem_ctl_info *mci) ...@@ -1253,7 +1248,7 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
{ {
struct i5000_pvt *pvt; struct i5000_pvt *pvt;
struct dimm_info *dimm; struct dimm_info *dimm;
int empty, channel_count; int empty;
int max_csrows; int max_csrows;
int mtr; int mtr;
int csrow_megs; int csrow_megs;
...@@ -1261,8 +1256,6 @@ static int i5000_init_csrows(struct mem_ctl_info *mci) ...@@ -1261,8 +1256,6 @@ static int i5000_init_csrows(struct mem_ctl_info *mci)
int slot; int slot;
pvt = mci->pvt_info; pvt = mci->pvt_info;
channel_count = pvt->maxch;
max_csrows = pvt->maxdimmperch * 2; max_csrows = pvt->maxdimmperch * 2;
empty = 1; /* Assume NO memory */ empty = 1; /* Assume NO memory */
...@@ -1559,8 +1552,8 @@ static int __init i5000_init(void) ...@@ -1559,8 +1552,8 @@ static int __init i5000_init(void)
edac_dbg(2, "MC:\n"); edac_dbg(2, "MC:\n");
/* Ensure that the OPSTATE is set correctly for POLL or NMI */ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
opstate_init(); opstate_init();
pci_rc = pci_register_driver(&i5000_driver); pci_rc = pci_register_driver(&i5000_driver);
......
...@@ -724,7 +724,7 @@ static ssize_t i7core_inject_type_store(struct device *dev, ...@@ -724,7 +724,7 @@ static ssize_t i7core_inject_type_store(struct device *dev,
const char *data, size_t count) const char *data, size_t count)
{ {
struct mem_ctl_info *mci = to_mci(dev); struct mem_ctl_info *mci = to_mci(dev);
struct i7core_pvt *pvt = mci->pvt_info; struct i7core_pvt *pvt = mci->pvt_info;
unsigned long value; unsigned long value;
int rc; int rc;
......
...@@ -104,7 +104,7 @@ NOTE: Only ONE of the three must be enabled ...@@ -104,7 +104,7 @@ NOTE: Only ONE of the three must be enabled
* *
* 31:14 Base Addr of 16K memory-mapped * 31:14 Base Addr of 16K memory-mapped
* configuration space * configuration space
* 13:1 reserverd * 13:1 reserved
* 0 mem-mapped config space enable * 0 mem-mapped config space enable
*/ */
...@@ -358,14 +358,6 @@ static int dual_channel_active(void __iomem *mch_window) ...@@ -358,14 +358,6 @@ static int dual_channel_active(void __iomem *mch_window)
return dualch; return dualch;
} }
static enum dev_type i82975x_dram_type(void __iomem *mch_window, int rank)
{
/*
* ECC is possible on i92975x ONLY with DEV_X8
*/
return DEV_X8;
}
static void i82975x_init_csrows(struct mem_ctl_info *mci, static void i82975x_init_csrows(struct mem_ctl_info *mci,
struct pci_dev *pdev, void __iomem *mch_window) struct pci_dev *pdev, void __iomem *mch_window)
{ {
...@@ -375,7 +367,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, ...@@ -375,7 +367,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
u32 cumul_size, nr_pages; u32 cumul_size, nr_pages;
int index, chan; int index, chan;
struct dimm_info *dimm; struct dimm_info *dimm;
enum dev_type dtype;
last_cumul_size = 0; last_cumul_size = 0;
...@@ -413,7 +404,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, ...@@ -413,7 +404,6 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
* [0-7] for single-channel; i.e. csrow->nr_channels = 1 * [0-7] for single-channel; i.e. csrow->nr_channels = 1
* [0-3] for dual-channel; i.e. csrow->nr_channels = 2 * [0-3] for dual-channel; i.e. csrow->nr_channels = 2
*/ */
dtype = i82975x_dram_type(mch_window, index);
for (chan = 0; chan < csrow->nr_channels; chan++) { for (chan = 0; chan < csrow->nr_channels; chan++) {
dimm = mci->csrows[index]->channels[chan]->dimm; dimm = mci->csrows[index]->channels[chan]->dimm;
...@@ -423,7 +413,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci, ...@@ -423,7 +413,10 @@ static void i82975x_init_csrows(struct mem_ctl_info *mci,
(chan == 0) ? 'A' : 'B', (chan == 0) ? 'A' : 'B',
index); index);
dimm->grain = 1 << 7; /* 128Byte cache-line resolution */ dimm->grain = 1 << 7; /* 128Byte cache-line resolution */
dimm->dtype = i82975x_dram_type(mch_window, index);
/* ECC is possible on i92975x ONLY with DEV_X8. */
dimm->dtype = DEV_X8;
dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */ dimm->mtype = MEM_DDR2; /* I82975x supports only DDR2 */
dimm->edac_mode = EDAC_SECDED; /* only supported */ dimm->edac_mode = EDAC_SECDED; /* only supported */
} }
...@@ -655,8 +648,8 @@ static int __init i82975x_init(void) ...@@ -655,8 +648,8 @@ static int __init i82975x_init(void)
edac_dbg(3, "\n"); edac_dbg(3, "\n");
/* Ensure that the OPSTATE is set correctly for POLL or NMI */ /* Ensure that the OPSTATE is set correctly for POLL or NMI */
opstate_init(); opstate_init();
pci_rc = pci_register_driver(&i82975x_driver); pci_rc = pci_register_driver(&i82975x_driver);
if (pci_rc < 0) if (pci_rc < 0)
......
...@@ -292,7 +292,6 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ...@@ -292,7 +292,6 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
struct llcc_drv_data *drv = edac_dev_ctl->pvt_info; struct llcc_drv_data *drv = edac_dev_ctl->pvt_info;
irqreturn_t irq_rc = IRQ_NONE; irqreturn_t irq_rc = IRQ_NONE;
u32 drp_error, trp_error, i; u32 drp_error, trp_error, i;
bool irq_handled;
int ret; int ret;
/* Iterate over the banks and look for Tag RAM or Data RAM errors */ /* Iterate over the banks and look for Tag RAM or Data RAM errors */
...@@ -311,7 +310,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ...@@ -311,7 +310,7 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i); ret = dump_syn_reg(edev_ctl, LLCC_DRAM_UE, i);
} }
if (!ret) if (!ret)
irq_handled = true; irq_rc = IRQ_HANDLED;
ret = regmap_read(drv->regmap, ret = regmap_read(drv->regmap,
drv->offsets[i] + TRP_INTERRUPT_0_STATUS, drv->offsets[i] + TRP_INTERRUPT_0_STATUS,
...@@ -327,12 +326,9 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl) ...@@ -327,12 +326,9 @@ llcc_ecc_irq_handler(int irq, void *edev_ctl)
ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i); ret = dump_syn_reg(edev_ctl, LLCC_TRAM_UE, i);
} }
if (!ret) if (!ret)
irq_handled = true; irq_rc = IRQ_HANDLED;
} }
if (irq_handled)
irq_rc = IRQ_HANDLED;
return irq_rc; return irq_rc;
} }
......
...@@ -209,7 +209,7 @@ static int get_all_bus_mappings(void) ...@@ -209,7 +209,7 @@ static int get_all_bus_mappings(void)
d->bus[1] = GET_BITFIELD(reg, 8, 15); d->bus[1] = GET_BITFIELD(reg, 8, 15);
d->bus[2] = GET_BITFIELD(reg, 16, 23); d->bus[2] = GET_BITFIELD(reg, 16, 23);
d->bus[3] = GET_BITFIELD(reg, 24, 31); d->bus[3] = GET_BITFIELD(reg, 24, 31);
edac_dbg(2, "busses: %x, %x, %x, %x\n", edac_dbg(2, "busses: 0x%x, 0x%x, 0x%x, 0x%x\n",
d->bus[0], d->bus[1], d->bus[2], d->bus[3]); d->bus[0], d->bus[1], d->bus[2], d->bus[3]);
list_add_tail(&d->list, &skx_edac_list); list_add_tail(&d->list, &skx_edac_list);
skx_num_sockets++; skx_num_sockets++;
...@@ -245,8 +245,8 @@ static int get_all_munits(const struct munit *m) ...@@ -245,8 +245,8 @@ static int get_all_munits(const struct munit *m)
/* Be sure that the device is enabled */ /* Be sure that the device is enabled */
if (unlikely(pci_enable_device(pdev) < 0)) { if (unlikely(pci_enable_device(pdev) < 0)) {
skx_printk(KERN_ERR, skx_printk(KERN_ERR, "Couldn't enable device %04x:%04x\n",
"Couldn't enable %04x:%04x\n", PCI_VENDOR_ID_INTEL, m->did); PCI_VENDOR_ID_INTEL, m->did);
goto fail; goto fail;
} }
...@@ -323,7 +323,7 @@ static int get_dimm_attr(u32 reg, int lobit, int hibit, int add, int minval, ...@@ -323,7 +323,7 @@ static int get_dimm_attr(u32 reg, int lobit, int hibit, int add, int minval,
u32 val = GET_BITFIELD(reg, lobit, hibit); u32 val = GET_BITFIELD(reg, lobit, hibit);
if (val < minval || val > maxval) { if (val < minval || val > maxval) {
edac_dbg(2, "bad %s = %d (raw=%x)\n", name, val, reg); edac_dbg(2, "bad %s = %d (raw=0x%x)\n", name, val, reg);
return -EINVAL; return -EINVAL;
} }
return val + add; return val + add;
...@@ -368,7 +368,7 @@ static int skx_get_hi_lo(void) ...@@ -368,7 +368,7 @@ static int skx_get_hi_lo(void)
skx_tohm |= (u64)reg << 32; skx_tohm |= (u64)reg << 32;
pci_dev_put(pdev); pci_dev_put(pdev);
edac_dbg(2, "tolm=%llx tohm=%llx\n", skx_tolm, skx_tohm); edac_dbg(2, "tolm=0x%llx tohm=0x%llx\n", skx_tolm, skx_tohm);
return 0; return 0;
} }
...@@ -389,7 +389,7 @@ static int get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm, ...@@ -389,7 +389,7 @@ static int get_dimm_info(u32 mtr, u32 amap, struct dimm_info *dimm,
size = ((1ull << (rows + cols + ranks)) * banks) >> (20 - 3); size = ((1ull << (rows + cols + ranks)) * banks) >> (20 - 3);
npages = MiB_TO_PAGES(size); npages = MiB_TO_PAGES(size);
edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: %#x, col: %#x\n", edac_dbg(0, "mc#%d: channel %d, dimm %d, %lld MiB (%d pages) bank: %d, rank: %d, row: 0x%#x, col: 0x%#x\n",
imc->mc, chan, dimmno, size, npages, imc->mc, chan, dimmno, size, npages,
banks, 1 << ranks, rows, cols); banks, 1 << ranks, rows, cols);
...@@ -430,18 +430,18 @@ static int get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc, ...@@ -430,18 +430,18 @@ static int get_nvdimm_info(struct dimm_info *dimm, struct skx_imc *imc,
} }
if (smbios_handle < 0) { if (smbios_handle < 0) {
skx_printk(KERN_ERR, "Can't find handle for NVDIMM ADR=%x\n", dev_handle); skx_printk(KERN_ERR, "Can't find handle for NVDIMM ADR=0x%x\n", dev_handle);
goto unknown_size; goto unknown_size;
} }
if (flags & ACPI_NFIT_MEM_MAP_FAILED) { if (flags & ACPI_NFIT_MEM_MAP_FAILED) {
skx_printk(KERN_ERR, "NVDIMM ADR=%x is not mapped\n", dev_handle); skx_printk(KERN_ERR, "NVDIMM ADR=0x%x is not mapped\n", dev_handle);
goto unknown_size; goto unknown_size;
} }
size = dmi_memdev_size(smbios_handle); size = dmi_memdev_size(smbios_handle);
if (size == ~0ull) if (size == ~0ull)
skx_printk(KERN_ERR, "Can't find size for NVDIMM ADR=%x/SMBIOS=%x\n", skx_printk(KERN_ERR, "Can't find size for NVDIMM ADR=0x%x/SMBIOS=0x%x\n",
dev_handle, smbios_handle); dev_handle, smbios_handle);
unknown_size: unknown_size:
...@@ -616,7 +616,7 @@ static bool skx_sad_decode(struct decoded_addr *res) ...@@ -616,7 +616,7 @@ static bool skx_sad_decode(struct decoded_addr *res)
/* Simple sanity check for I/O space or out of range */ /* Simple sanity check for I/O space or out of range */
if (addr >= skx_tohm || (addr >= skx_tolm && addr < BIT_ULL(32))) { if (addr >= skx_tohm || (addr >= skx_tolm && addr < BIT_ULL(32))) {
edac_dbg(0, "Address %llx out of range\n", addr); edac_dbg(0, "Address 0x%llx out of range\n", addr);
return false; return false;
} }
...@@ -631,7 +631,7 @@ static bool skx_sad_decode(struct decoded_addr *res) ...@@ -631,7 +631,7 @@ static bool skx_sad_decode(struct decoded_addr *res)
} }
prev_limit = limit + 1; prev_limit = limit + 1;
} }
edac_dbg(0, "No SAD entry for %llx\n", addr); edac_dbg(0, "No SAD entry for 0x%llx\n", addr);
return false; return false;
sad_found: sad_found:
...@@ -709,7 +709,7 @@ static bool skx_sad_decode(struct decoded_addr *res) ...@@ -709,7 +709,7 @@ static bool skx_sad_decode(struct decoded_addr *res)
res->imc = GET_BITFIELD(d->mcroute, lchan * 3, lchan * 3 + 2); res->imc = GET_BITFIELD(d->mcroute, lchan * 3, lchan * 3 + 2);
res->channel = GET_BITFIELD(d->mcroute, lchan * 2 + 18, lchan * 2 + 19); res->channel = GET_BITFIELD(d->mcroute, lchan * 2 + 18, lchan * 2 + 19);
edac_dbg(2, "%llx: socket=%d imc=%d channel=%d\n", edac_dbg(2, "0x%llx: socket=%d imc=%d channel=%d\n",
res->addr, res->socket, res->imc, res->channel); res->addr, res->socket, res->imc, res->channel);
return true; return true;
} }
...@@ -756,7 +756,7 @@ static bool skx_tad_decode(struct decoded_addr *res) ...@@ -756,7 +756,7 @@ static bool skx_tad_decode(struct decoded_addr *res)
if (SKX_TAD_BASE(base) <= res->addr && res->addr <= SKX_TAD_LIMIT(wayness)) if (SKX_TAD_BASE(base) <= res->addr && res->addr <= SKX_TAD_LIMIT(wayness))
goto tad_found; goto tad_found;
} }
edac_dbg(0, "No TAD entry for %llx\n", res->addr); edac_dbg(0, "No TAD entry for 0x%llx\n", res->addr);
return false; return false;
tad_found: tad_found:
...@@ -784,7 +784,7 @@ static bool skx_tad_decode(struct decoded_addr *res) ...@@ -784,7 +784,7 @@ static bool skx_tad_decode(struct decoded_addr *res)
res->chan_addr = channel_addr; res->chan_addr = channel_addr;
edac_dbg(2, "%llx: chan_addr=%llx sktways=%d chanways=%d\n", edac_dbg(2, "0x%llx: chan_addr=0x%llx sktways=%d chanways=%d\n",
res->addr, res->chan_addr, res->sktways, res->chanways); res->addr, res->chan_addr, res->sktways, res->chanways);
return true; return true;
} }
...@@ -826,7 +826,7 @@ static bool skx_rir_decode(struct decoded_addr *res) ...@@ -826,7 +826,7 @@ static bool skx_rir_decode(struct decoded_addr *res)
} }
prev_limit = limit; prev_limit = limit;
} }
edac_dbg(0, "No RIR entry for %llx\n", res->addr); edac_dbg(0, "No RIR entry for 0x%llx\n", res->addr);
return false; return false;
rir_found: rir_found:
...@@ -845,7 +845,7 @@ static bool skx_rir_decode(struct decoded_addr *res) ...@@ -845,7 +845,7 @@ static bool skx_rir_decode(struct decoded_addr *res)
res->dimm = chan_rank / 4; res->dimm = chan_rank / 4;
res->rank = chan_rank % 4; res->rank = chan_rank % 4;
edac_dbg(2, "%llx: dimm=%d rank=%d chan_rank=%d rank_addr=%llx\n", edac_dbg(2, "0x%llx: dimm=%d rank=%d chan_rank=%d rank_addr=0x%llx\n",
res->addr, res->dimm, res->rank, res->addr, res->dimm, res->rank,
res->channel_rank, res->rank_address); res->channel_rank, res->rank_address);
return true; return true;
...@@ -908,7 +908,7 @@ static bool skx_mad_decode(struct decoded_addr *r) ...@@ -908,7 +908,7 @@ static bool skx_mad_decode(struct decoded_addr *r)
} }
r->row &= (1u << dimm->rowbits) - 1; r->row &= (1u << dimm->rowbits) - 1;
edac_dbg(2, "%llx: row=%x col=%x bank_addr=%d bank_group=%d\n", edac_dbg(2, "0x%llx: row=0x%x col=0x%x bank_addr=%d bank_group=%d\n",
r->addr, r->row, r->column, r->bank_address, r->addr, r->row, r->column, r->bank_address,
r->bank_group); r->bank_group);
return true; return true;
...@@ -921,53 +921,6 @@ static bool skx_decode(struct decoded_addr *res) ...@@ -921,53 +921,6 @@ static bool skx_decode(struct decoded_addr *res)
skx_rir_decode(res) && skx_mad_decode(res); skx_rir_decode(res) && skx_mad_decode(res);
} }
#ifdef CONFIG_EDAC_DEBUG
/*
* Debug feature. Make /sys/kernel/debug/skx_edac_test/addr.
* Write an address to this file to exercise the address decode
* logic in this driver.
*/
static struct dentry *skx_test;
static u64 skx_fake_addr;
static int debugfs_u64_set(void *data, u64 val)
{
struct decoded_addr res;
res.addr = val;
skx_decode(&res);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
static struct dentry *mydebugfs_create(const char *name, umode_t mode,
struct dentry *parent, u64 *value)
{
return debugfs_create_file(name, mode, parent, value, &fops_u64_wo);
}
static void setup_skx_debug(void)
{
skx_test = debugfs_create_dir("skx_edac_test", NULL);
mydebugfs_create("addr", S_IWUSR, skx_test, &skx_fake_addr);
}
static void teardown_skx_debug(void)
{
debugfs_remove_recursive(skx_test);
}
#else
static void setup_skx_debug(void)
{
}
static void teardown_skx_debug(void)
{
}
#endif /*CONFIG_EDAC_DEBUG*/
static bool skx_adxl_decode(struct decoded_addr *res) static bool skx_adxl_decode(struct decoded_addr *res)
{ {
...@@ -1069,13 +1022,13 @@ static void skx_mce_output_error(struct mem_ctl_info *mci, ...@@ -1069,13 +1022,13 @@ static void skx_mce_output_error(struct mem_ctl_info *mci,
} }
} }
if (adxl_component_count) { if (adxl_component_count) {
snprintf(skx_msg, MSG_SIZE, "%s%s err_code:%04x:%04x %s", snprintf(skx_msg, MSG_SIZE, "%s%s err_code:0x%04x:0x%04x %s",
overflow ? " OVERFLOW" : "", overflow ? " OVERFLOW" : "",
(uncorrected_error && recoverable) ? " recoverable" : "", (uncorrected_error && recoverable) ? " recoverable" : "",
mscod, errcode, adxl_msg); mscod, errcode, adxl_msg);
} else { } else {
snprintf(skx_msg, MSG_SIZE, snprintf(skx_msg, MSG_SIZE,
"%s%s err_code:%04x:%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:%x col:%x", "%s%s err_code:0x%04x:0x%04x socket:%d imc:%d rank:%d bg:%d ba:%d row:0x%x col:0x%x",
overflow ? " OVERFLOW" : "", overflow ? " OVERFLOW" : "",
(uncorrected_error && recoverable) ? " recoverable" : "", (uncorrected_error && recoverable) ? " recoverable" : "",
mscod, errcode, mscod, errcode,
...@@ -1151,15 +1104,15 @@ static int skx_mce_check_error(struct notifier_block *nb, unsigned long val, ...@@ -1151,15 +1104,15 @@ static int skx_mce_check_error(struct notifier_block *nb, unsigned long val,
skx_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n"); skx_mc_printk(mci, KERN_DEBUG, "HANDLING MCE MEMORY ERROR\n");
skx_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: %Lx " skx_mc_printk(mci, KERN_DEBUG, "CPU %d: Machine Check %s: 0x%llx "
"Bank %d: %016Lx\n", mce->extcpu, type, "Bank %d: %016Lx\n", mce->extcpu, type,
mce->mcgstatus, mce->bank, mce->status); mce->mcgstatus, mce->bank, mce->status);
skx_mc_printk(mci, KERN_DEBUG, "TSC %llx ", mce->tsc); skx_mc_printk(mci, KERN_DEBUG, "TSC 0x%llx ", mce->tsc);
skx_mc_printk(mci, KERN_DEBUG, "ADDR %llx ", mce->addr); skx_mc_printk(mci, KERN_DEBUG, "ADDR 0x%llx ", mce->addr);
skx_mc_printk(mci, KERN_DEBUG, "MISC %llx ", mce->misc); skx_mc_printk(mci, KERN_DEBUG, "MISC 0x%llx ", mce->misc);
skx_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:%x TIME %llu SOCKET " skx_mc_printk(mci, KERN_DEBUG, "PROCESSOR %u:0x%x TIME %llu SOCKET "
"%u APIC %x\n", mce->cpuvendor, mce->cpuid, "%u APIC 0x%x\n", mce->cpuvendor, mce->cpuid,
mce->time, mce->socketid, mce->apicid); mce->time, mce->socketid, mce->apicid);
skx_mce_output_error(mci, mce, &res); skx_mce_output_error(mci, mce, &res);
...@@ -1172,6 +1125,54 @@ static struct notifier_block skx_mce_dec = { ...@@ -1172,6 +1125,54 @@ static struct notifier_block skx_mce_dec = {
.priority = MCE_PRIO_EDAC, .priority = MCE_PRIO_EDAC,
}; };
#ifdef CONFIG_EDAC_DEBUG
/*
* Debug feature.
* Exercise the address decode logic by writing an address to
* /sys/kernel/debug/edac/skx_test/addr.
*/
static struct dentry *skx_test;
static int debugfs_u64_set(void *data, u64 val)
{
struct mce m;
pr_warn_once("Fake error to 0x%llx injected via debugfs\n", val);
memset(&m, 0, sizeof(m));
/* ADDRV + MemRd + Unknown channel */
m.status = MCI_STATUS_ADDRV + 0x90;
/* One corrected error */
m.status |= BIT_ULL(MCI_STATUS_CEC_SHIFT);
m.addr = val;
skx_mce_check_error(NULL, 0, &m);
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(fops_u64_wo, NULL, debugfs_u64_set, "%llu\n");
static void setup_skx_debug(void)
{
skx_test = edac_debugfs_create_dir("skx_test");
if (!skx_test)
return;
if (!edac_debugfs_create_file("addr", 0200, skx_test,
NULL, &fops_u64_wo)) {
debugfs_remove(skx_test);
skx_test = NULL;
}
}
static void teardown_skx_debug(void)
{
debugfs_remove_recursive(skx_test);
}
#else
static void setup_skx_debug(void) {}
static void teardown_skx_debug(void) {}
#endif /*CONFIG_EDAC_DEBUG*/
static void skx_remove(void) static void skx_remove(void)
{ {
int i, j; int i, j;
...@@ -1291,7 +1292,7 @@ static int __init skx_init(void) ...@@ -1291,7 +1292,7 @@ static int __init skx_init(void)
if (rc < 0) if (rc < 0)
goto fail; goto fail;
if (rc != m->per_socket * skx_num_sockets) { if (rc != m->per_socket * skx_num_sockets) {
edac_dbg(2, "Expected %d, got %d of %x\n", edac_dbg(2, "Expected %d, got %d of 0x%x\n",
m->per_socket * skx_num_sockets, rc, m->did); m->per_socket * skx_num_sockets, rc, m->did);
rc = -ENODEV; rc = -ENODEV;
goto fail; goto fail;
...@@ -1339,11 +1340,11 @@ static void __exit skx_exit(void) ...@@ -1339,11 +1340,11 @@ static void __exit skx_exit(void)
{ {
edac_dbg(2, "\n"); edac_dbg(2, "\n");
mce_unregister_decode_chain(&skx_mce_dec); mce_unregister_decode_chain(&skx_mce_dec);
skx_remove(); teardown_skx_debug();
if (nvdimm_count) if (nvdimm_count)
skx_adxl_put(); skx_adxl_put();
kfree(skx_msg); kfree(skx_msg);
teardown_skx_debug(); skx_remove();
} }
module_init(skx_init); module_init(skx_init);
......
This diff is collapsed.
...@@ -7,12 +7,7 @@ ...@@ -7,12 +7,7 @@
#ifndef _LINUX_ADXL_H #ifndef _LINUX_ADXL_H
#define _LINUX_ADXL_H #define _LINUX_ADXL_H
#ifdef CONFIG_ACPI_ADXL
const char * const *adxl_get_component_names(void); const char * const *adxl_get_component_names(void);
int adxl_decode(u64 addr, u64 component_values[]); int adxl_decode(u64 addr, u64 component_values[]);
#else
static inline const char * const *adxl_get_component_names(void) { return NULL; }
static inline int adxl_decode(u64 addr, u64 component_values[]) { return -EOPNOTSUPP; }
#endif
#endif /* _LINUX_ADXL_H */ #endif /* _LINUX_ADXL_H */
...@@ -669,10 +669,4 @@ struct mem_ctl_info { ...@@ -669,10 +669,4 @@ struct mem_ctl_info {
bool fake_inject_ue; bool fake_inject_ue;
u16 fake_inject_count; u16 fake_inject_count;
}; };
/*
* Maximum number of memory controllers in the coherent fabric.
*/
#define EDAC_MAX_MCS 2 * MAX_NUMNODES
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment