Commit 0160928e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'edac_for_3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp

Pull EDAC updates from Borislav Petkov:
 "EDAC updates all over the place:

   - Enablement for AMD F15h models 0x60 CPUs.  Most notably DDR4 RAM
     support.  Out of tree stuff is adding the required PCI IDs.  From
     Aravind Gopalakrishnan.

   - Enable amd64_edac for 32-bit due to popular demand.  From Tomasz
     Pala.

   - Convert the AMD MCE injection module to debugfs, where it belongs.

   - Misc EDAC cleanups"

* tag 'edac_for_3.19' of git://git.kernel.org/pub/scm/linux/kernel/git/bp/bp:
  EDAC, MCE, AMD: Correct formatting of decoded text
  EDAC, mce_amd_inj: Add an injector function
  EDAC, mce_amd_inj: Add hw-injection attributes
  EDAC, mce_amd_inj: Enable direct writes to MCE MSRs
  EDAC, mce_amd_inj: Convert mce_amd_inj module to debugfs
  EDAC: Delete unnecessary check before calling pci_dev_put()
  EDAC, pci_sysfs: remove unneccessary ifdef around entire file
  ghes_edac: Use snprintf() to silence a static checker warning
  amd64_edac: Build module on x86-32
  EDAC, MCE, AMD: Add decoding table for MC6 xec
  amd64_edac: Add F15h M60h support
  {mv64x60,ppc4xx}_edac,: Remove deprecated IRQF_DISABLED
  EDAC: Sync memory types and names
  EDAC: Add DDR3 LRDIMM entries to edac_mem_types
  x86, amd_nb: Add device IDs to NB tables for F15h M60h
  pci_ids: Add PCI device IDs for F15h M60h
parents 3a7dbed7 50872ccd
...@@ -21,6 +21,7 @@ const struct pci_device_id amd_nb_misc_ids[] = { ...@@ -21,6 +21,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{} {}
...@@ -30,6 +31,7 @@ EXPORT_SYMBOL(amd_nb_misc_ids); ...@@ -30,6 +31,7 @@ EXPORT_SYMBOL(amd_nb_misc_ids);
static const struct pci_device_id amd_nb_link_ids[] = { static const struct pci_device_id amd_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) }, { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
{} {}
......
...@@ -61,14 +61,14 @@ config EDAC_DECODE_MCE ...@@ -61,14 +61,14 @@ config EDAC_DECODE_MCE
has been initialized. has been initialized.
config EDAC_MCE_INJ config EDAC_MCE_INJ
tristate "Simple MCE injection interface over /sysfs" tristate "Simple MCE injection interface"
depends on EDAC_DECODE_MCE depends on EDAC_DECODE_MCE && DEBUG_FS
default n default n
help help
This is a simple interface to inject MCEs over /sysfs and test This is a simple debugfs interface to inject MCEs and test different
the MCE decoding code in EDAC. aspects of the MCE handling code.
This is currently AMD-only. WARNING: Do not even assume this interface is staying stable!
config EDAC_MM_EDAC config EDAC_MM_EDAC
tristate "Main Memory EDAC (Error Detection And Correction) reporting" tristate "Main Memory EDAC (Error Detection And Correction) reporting"
...@@ -105,11 +105,11 @@ config EDAC_GHES ...@@ -105,11 +105,11 @@ config EDAC_GHES
In doubt, say 'Y'. In doubt, say 'Y'.
config EDAC_AMD64 config EDAC_AMD64
tristate "AMD64 (Opteron, Athlon64) K8, F10h" tristate "AMD64 (Opteron, Athlon64)"
depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE depends on EDAC_MM_EDAC && AMD_NB && EDAC_DECODE_MCE
help help
Support for error detection and correction of DRAM ECC errors on Support for error detection and correction of DRAM ECC errors on
the AMD64 families of memory controllers (K8 and F10h) the AMD64 families (>= K8) of memory controllers.
config EDAC_AMD64_ERROR_INJECTION config EDAC_AMD64_ERROR_INJECTION
bool "Sysfs HW Error injection facilities" bool "Sysfs HW Error injection facilities"
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
obj-$(CONFIG_EDAC) := edac_stub.o obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.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-y += edac_module.o edac_device_sysfs.o
ifdef CONFIG_PCI ifdef CONFIG_PCI
......
This diff is collapsed.
...@@ -162,10 +162,12 @@ ...@@ -162,10 +162,12 @@
/* /*
* PCI-defined configuration space registers * PCI-defined configuration space registers
*/ */
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c
#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 #define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 #define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c
#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F1 0x1571
#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F2 0x1572
#define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531 #define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531
#define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532 #define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532
#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581 #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581
...@@ -221,6 +223,8 @@ ...@@ -221,6 +223,8 @@
#define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE) #define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE)
#define DRAM_CONTROL 0x78
#define DBAM0 0x80 #define DBAM0 0x80
#define DBAM1 0x180 #define DBAM1 0x180
...@@ -301,6 +305,7 @@ enum amd_families { ...@@ -301,6 +305,7 @@ enum amd_families {
F10_CPUS, F10_CPUS,
F15_CPUS, F15_CPUS,
F15_M30H_CPUS, F15_M30H_CPUS,
F15_M60H_CPUS,
F16_CPUS, F16_CPUS,
F16_M30H_CPUS, F16_M30H_CPUS,
NUM_FAMILIES, NUM_FAMILIES,
...@@ -379,6 +384,9 @@ struct amd64_pvt { ...@@ -379,6 +384,9 @@ struct amd64_pvt {
/* place to store error injection parameters prior to issue */ /* place to store error injection parameters prior to issue */
struct error_injection injection; struct error_injection injection;
/* cache the dram_type */
enum mem_type dram_type;
}; };
enum err_codes { enum err_codes {
...@@ -480,7 +488,8 @@ struct low_ops { ...@@ -480,7 +488,8 @@ struct low_ops {
int (*early_channel_count) (struct amd64_pvt *pvt); int (*early_channel_count) (struct amd64_pvt *pvt);
void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr,
struct err_info *); struct err_info *);
int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode); int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct,
unsigned cs_mode, int cs_mask_nr);
}; };
struct amd64_family_type { struct amd64_family_type {
......
...@@ -125,27 +125,27 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci) ...@@ -125,27 +125,27 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci)
#endif /* CONFIG_EDAC_DEBUG */ #endif /* CONFIG_EDAC_DEBUG */
/*
* keep those in sync with the enum mem_type
*/
const char * const edac_mem_types[] = { const char * const edac_mem_types[] = {
"Empty csrow", [MEM_EMPTY] = "Empty csrow",
"Reserved csrow type", [MEM_RESERVED] = "Reserved csrow type",
"Unknown csrow type", [MEM_UNKNOWN] = "Unknown csrow type",
"Fast page mode RAM", [MEM_FPM] = "Fast page mode RAM",
"Extended data out RAM", [MEM_EDO] = "Extended data out RAM",
"Burst Extended data out RAM", [MEM_BEDO] = "Burst Extended data out RAM",
"Single data rate SDRAM", [MEM_SDR] = "Single data rate SDRAM",
"Registered single data rate SDRAM", [MEM_RDR] = "Registered single data rate SDRAM",
"Double data rate SDRAM", [MEM_DDR] = "Double data rate SDRAM",
"Registered Double data rate SDRAM", [MEM_RDDR] = "Registered Double data rate SDRAM",
"Rambus DRAM", [MEM_RMBS] = "Rambus DRAM",
"Unbuffered DDR2 RAM", [MEM_DDR2] = "Unbuffered DDR2 RAM",
"Fully buffered DDR2", [MEM_FB_DDR2] = "Fully buffered DDR2",
"Registered DDR2 RAM", [MEM_RDDR2] = "Registered DDR2 RAM",
"Rambus XDR", [MEM_XDR] = "Rambus XDR",
"Unbuffered DDR3 RAM", [MEM_DDR3] = "Unbuffered DDR3 RAM",
"Registered DDR3 RAM", [MEM_RDDR3] = "Registered DDR3 RAM",
[MEM_LRDDR3] = "Load-Reduced DDR3 RAM",
[MEM_DDR4] = "Unbuffered DDR4 RAM",
[MEM_RDDR4] = "Registered DDR4 RAM",
}; };
EXPORT_SYMBOL_GPL(edac_mem_types); EXPORT_SYMBOL_GPL(edac_mem_types);
......
...@@ -14,9 +14,6 @@ ...@@ -14,9 +14,6 @@
#include "edac_core.h" #include "edac_core.h"
#include "edac_module.h" #include "edac_module.h"
/* Turn off this whole feature if PCI is not configured */
#ifdef CONFIG_PCI
#define EDAC_PCI_SYMLINK "device" #define EDAC_PCI_SYMLINK "device"
/* data variables exported via sysfs */ /* data variables exported via sysfs */
...@@ -761,5 +758,3 @@ MODULE_PARM_DESC(check_pci_errors, ...@@ -761,5 +758,3 @@ MODULE_PARM_DESC(check_pci_errors,
module_param(edac_pci_panic_on_pe, int, 0644); module_param(edac_pci_panic_on_pe, int, 0644);
MODULE_PARM_DESC(edac_pci_panic_on_pe, MODULE_PARM_DESC(edac_pci_panic_on_pe,
"Panic on PCI Bus Parity error: 0=off 1=on"); "Panic on PCI Bus Parity error: 0=off 1=on");
#endif /* CONFIG_PCI */
...@@ -413,8 +413,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, ...@@ -413,8 +413,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
/* Generate the trace event */ /* Generate the trace event */
grain_bits = fls_long(e->grain); grain_bits = fls_long(e->grain);
sprintf(pvt->detail_location, "APEI location: %s %s", snprintf(pvt->detail_location, sizeof(pvt->detail_location),
e->location, e->other_detail); "APEI location: %s %s", e->location, e->other_detail);
trace_mc_event(type, e->msg, e->label, e->error_count, trace_mc_event(type, e->msg, e->label, e->error_count,
mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer, mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer,
PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page, PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page,
......
...@@ -542,8 +542,7 @@ static int __init i3000_init(void) ...@@ -542,8 +542,7 @@ static int __init i3000_init(void)
pci_unregister_driver(&i3000_driver); pci_unregister_driver(&i3000_driver);
fail0: fail0:
if (mci_pdev) pci_dev_put(mci_pdev);
pci_dev_put(mci_pdev);
return pci_rc; return pci_rc;
} }
......
...@@ -523,8 +523,7 @@ static int __init i3200_init(void) ...@@ -523,8 +523,7 @@ static int __init i3200_init(void)
pci_unregister_driver(&i3200_driver); pci_unregister_driver(&i3200_driver);
fail0: fail0:
if (mci_pdev) pci_dev_put(mci_pdev);
pci_dev_put(mci_pdev);
return pci_rc; return pci_rc;
} }
......
...@@ -458,8 +458,7 @@ static void __exit i82443bxgx_edacmc_exit(void) ...@@ -458,8 +458,7 @@ static void __exit i82443bxgx_edacmc_exit(void)
if (!i82443bxgx_registered) if (!i82443bxgx_registered)
i82443bxgx_edacmc_remove_one(mci_pdev); i82443bxgx_edacmc_remove_one(mci_pdev);
if (mci_pdev) pci_dev_put(mci_pdev);
pci_dev_put(mci_pdev);
} }
module_init(i82443bxgx_edacmc_init); module_init(i82443bxgx_edacmc_init);
......
...@@ -138,6 +138,15 @@ static const char * const mc5_mce_desc[] = { ...@@ -138,6 +138,15 @@ static const char * const mc5_mce_desc[] = {
"Retire status queue" "Retire status queue"
}; };
static const char * const mc6_mce_desc[] = {
"Hardware Assertion",
"Free List",
"Physical Register File",
"Retire Queue",
"Scheduler table",
"Status Register File",
};
static bool f12h_mc0_mce(u16 ec, u8 xec) static bool f12h_mc0_mce(u16 ec, u8 xec)
{ {
bool ret = false; bool ret = false;
...@@ -432,8 +441,8 @@ static bool k8_mc2_mce(u16 ec, u8 xec) ...@@ -432,8 +441,8 @@ static bool k8_mc2_mce(u16 ec, u8 xec)
pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec)); pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec));
else if (xec == 0x0) { else if (xec == 0x0) {
if (TLB_ERROR(ec)) if (TLB_ERROR(ec))
pr_cont(": %s error in a Page Descriptor Cache or " pr_cont("%s error in a Page Descriptor Cache or Guest TLB.\n",
"Guest TLB.\n", TT_MSG(ec)); TT_MSG(ec));
else if (BUS_ERROR(ec)) else if (BUS_ERROR(ec))
pr_cont(": %s/ECC error in data read from NB: %s.\n", pr_cont(": %s/ECC error in data read from NB: %s.\n",
R4_MSG(ec), PP_MSG(ec)); R4_MSG(ec), PP_MSG(ec));
...@@ -672,38 +681,10 @@ static void decode_mc6_mce(struct mce *m) ...@@ -672,38 +681,10 @@ static void decode_mc6_mce(struct mce *m)
pr_emerg(HW_ERR "MC6 Error: "); pr_emerg(HW_ERR "MC6 Error: ");
switch (xec) { if (xec > 0x5)
case 0x0:
pr_cont("Hardware Assertion");
break;
case 0x1:
pr_cont("Free List");
break;
case 0x2:
pr_cont("Physical Register File");
break;
case 0x3:
pr_cont("Retire Queue");
break;
case 0x4:
pr_cont("Scheduler table");
break;
case 0x5:
pr_cont("Status Register File");
break;
default:
goto wrong_mc6_mce; goto wrong_mc6_mce;
break;
}
pr_cont(" parity error.\n");
pr_cont("%s parity error.\n", mc6_mce_desc[xec]);
return; return;
wrong_mc6_mce: wrong_mc6_mce:
...@@ -800,7 +781,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) ...@@ -800,7 +781,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
pr_cont("]: 0x%016llx\n", m->status); pr_cont("]: 0x%016llx\n", m->status);
if (m->status & MCI_STATUS_ADDRV) if (m->status & MCI_STATUS_ADDRV)
pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr); pr_emerg(HW_ERR "MC%d Error Address: 0x%016llx\n", m->bank, m->addr);
if (!fam_ops) if (!fam_ops)
goto err_code; goto err_code;
......
/* /*
* A simple MCE injection facility for testing the MCE decoding code. This * A simple MCE injection facility for testing different aspects of the RAS
* driver should be built as module so that it can be loaded on production * code. This driver should be built as module so that it can be loaded
* kernels for testing purposes. * on production kernels for testing purposes.
* *
* This file may be distributed under the terms of the GNU General Public * This file may be distributed under the terms of the GNU General Public
* License version 2. * License version 2.
* *
* Copyright (c) 2010: Borislav Petkov <bp@alien8.de> * Copyright (c) 2010-14: Borislav Petkov <bp@alien8.de>
* Advanced Micro Devices Inc. * Advanced Micro Devices Inc.
*/ */
#include <linux/kobject.h> #include <linux/kobject.h>
#include <linux/debugfs.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/edac.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/cpu.h>
#include <asm/mce.h> #include <asm/mce.h>
#include "mce_amd.h" #include "mce_amd.h"
struct edac_mce_attr {
struct attribute attr;
ssize_t (*show) (struct kobject *kobj, struct edac_mce_attr *attr, char *buf);
ssize_t (*store)(struct kobject *kobj, struct edac_mce_attr *attr,
const char *buf, size_t count);
};
#define EDAC_MCE_ATTR(_name, _mode, _show, _store) \
static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _store)
static struct kobject *mce_kobj;
/* /*
* Collect all the MCi_XXX settings * Collect all the MCi_XXX settings
*/ */
static struct mce i_mce; static struct mce i_mce;
static struct dentry *dfs_inj;
#define MCE_INJECT_STORE(reg) \ #define MCE_INJECT_SET(reg) \
static ssize_t edac_inject_##reg##_store(struct kobject *kobj, \ static int inj_##reg##_set(void *data, u64 val) \
struct edac_mce_attr *attr, \
const char *data, size_t count)\
{ \ { \
int ret = 0; \ struct mce *m = (struct mce *)data; \
unsigned long value; \
\
ret = kstrtoul(data, 16, &value); \
if (ret < 0) \
printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \
\ \
i_mce.reg = value; \ m->reg = val; \
\ return 0; \
return count; \
} }
MCE_INJECT_STORE(status); MCE_INJECT_SET(status);
MCE_INJECT_STORE(misc); MCE_INJECT_SET(misc);
MCE_INJECT_STORE(addr); MCE_INJECT_SET(addr);
#define MCE_INJECT_SHOW(reg) \ #define MCE_INJECT_GET(reg) \
static ssize_t edac_inject_##reg##_show(struct kobject *kobj, \ static int inj_##reg##_get(void *data, u64 *val) \
struct edac_mce_attr *attr, \
char *buf) \
{ \ { \
return sprintf(buf, "0x%016llx\n", i_mce.reg); \ struct mce *m = (struct mce *)data; \
\
*val = m->reg; \
return 0; \
} }
MCE_INJECT_SHOW(status); MCE_INJECT_GET(status);
MCE_INJECT_SHOW(misc); MCE_INJECT_GET(misc);
MCE_INJECT_SHOW(addr); MCE_INJECT_GET(addr);
EDAC_MCE_ATTR(status, 0644, edac_inject_status_show, edac_inject_status_store); DEFINE_SIMPLE_ATTRIBUTE(status_fops, inj_status_get, inj_status_set, "%llx\n");
EDAC_MCE_ATTR(misc, 0644, edac_inject_misc_show, edac_inject_misc_store); DEFINE_SIMPLE_ATTRIBUTE(misc_fops, inj_misc_get, inj_misc_set, "%llx\n");
EDAC_MCE_ATTR(addr, 0644, edac_inject_addr_show, edac_inject_addr_store); DEFINE_SIMPLE_ATTRIBUTE(addr_fops, inj_addr_get, inj_addr_set, "%llx\n");
/* /*
* This denotes into which bank we're injecting and triggers * Caller needs to be make sure this cpu doesn't disappear
* the injection, at the same time. * from under us, i.e.: get_cpu/put_cpu.
*/ */
static ssize_t edac_inject_bank_store(struct kobject *kobj, static int toggle_hw_mce_inject(unsigned int cpu, bool enable)
struct edac_mce_attr *attr,
const char *data, size_t count)
{ {
int ret = 0; u32 l, h;
unsigned long value; int err;
ret = kstrtoul(data, 10, &value); err = rdmsr_on_cpu(cpu, MSR_K7_HWCR, &l, &h);
if (ret < 0) { if (err) {
printk(KERN_ERR "Invalid bank value!\n"); pr_err("%s: error reading HWCR\n", __func__);
return -EINVAL; return err;
} }
if (value > 5) enable ? (l |= BIT(18)) : (l &= ~BIT(18));
if (boot_cpu_data.x86 != 0x15 || value > 6) {
printk(KERN_ERR "Non-existent MCE bank: %lu\n", value);
return -EINVAL;
}
i_mce.bank = value; err = wrmsr_on_cpu(cpu, MSR_K7_HWCR, l, h);
if (err)
pr_err("%s: error writing HWCR\n", __func__);
amd_decode_mce(NULL, 0, &i_mce); return err;
}
return count; static int flags_get(void *data, u64 *val)
{
struct mce *m = (struct mce *)data;
*val = m->inject_flags;
return 0;
} }
static ssize_t edac_inject_bank_show(struct kobject *kobj, static int flags_set(void *data, u64 val)
struct edac_mce_attr *attr, char *buf)
{ {
return sprintf(buf, "%d\n", i_mce.bank); struct mce *m = (struct mce *)data;
m->inject_flags = (u8)val;
return 0;
} }
EDAC_MCE_ATTR(bank, 0644, edac_inject_bank_show, edac_inject_bank_store); DEFINE_SIMPLE_ATTRIBUTE(flags_fops, flags_get, flags_set, "%llu\n");
static struct edac_mce_attr *sysfs_attrs[] = { &mce_attr_status, &mce_attr_misc, /*
&mce_attr_addr, &mce_attr_bank * On which CPU to inject?
}; */
MCE_INJECT_GET(extcpu);
static int __init edac_init_mce_inject(void) static int inj_extcpu_set(void *data, u64 val)
{ {
struct bus_type *edac_subsys = NULL; struct mce *m = (struct mce *)data;
int i, err = 0;
edac_subsys = edac_get_sysfs_subsys(); if (val >= nr_cpu_ids || !cpu_online(val)) {
if (!edac_subsys) pr_err("%s: Invalid CPU: %llu\n", __func__, val);
return -EINVAL; return -EINVAL;
}
m->extcpu = val;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n");
mce_kobj = kobject_create_and_add("mce", &edac_subsys->dev_root->kobj); static void trigger_mce(void *info)
if (!mce_kobj) { {
printk(KERN_ERR "Error creating a mce kset.\n"); asm volatile("int $18");
err = -ENOMEM; }
goto err_mce_kobj;
static void do_inject(void)
{
u64 mcg_status = 0;
unsigned int cpu = i_mce.extcpu;
u8 b = i_mce.bank;
if (!(i_mce.inject_flags & MCJ_EXCEPTION)) {
amd_decode_mce(NULL, 0, &i_mce);
return;
} }
for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) { get_online_cpus();
err = sysfs_create_file(mce_kobj, &sysfs_attrs[i]->attr); if (!cpu_online(cpu))
if (err) { goto err;
printk(KERN_ERR "Error creating %s in sysfs.\n",
sysfs_attrs[i]->attr.name); /* prep MCE global settings for the injection */
goto err_sysfs_create; mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
if (!(i_mce.status & MCI_STATUS_PCC))
mcg_status |= MCG_STATUS_RIPV;
toggle_hw_mce_inject(cpu, true);
wrmsr_on_cpu(cpu, MSR_IA32_MCG_STATUS,
(u32)mcg_status, (u32)(mcg_status >> 32));
wrmsr_on_cpu(cpu, MSR_IA32_MCx_STATUS(b),
(u32)i_mce.status, (u32)(i_mce.status >> 32));
wrmsr_on_cpu(cpu, MSR_IA32_MCx_ADDR(b),
(u32)i_mce.addr, (u32)(i_mce.addr >> 32));
wrmsr_on_cpu(cpu, MSR_IA32_MCx_MISC(b),
(u32)i_mce.misc, (u32)(i_mce.misc >> 32));
toggle_hw_mce_inject(cpu, false);
smp_call_function_single(cpu, trigger_mce, NULL, 0);
err:
put_online_cpus();
}
/*
* This denotes into which bank we're injecting and triggers
* the injection, at the same time.
*/
static int inj_bank_set(void *data, u64 val)
{
struct mce *m = (struct mce *)data;
if (val > 5) {
if (boot_cpu_data.x86 != 0x15 || val > 6) {
pr_err("Non-existent MCE bank: %llu\n", val);
return -EINVAL;
} }
} }
return 0;
err_sysfs_create: m->bank = val;
while (--i >= 0) do_inject();
sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
kobject_del(mce_kobj); return 0;
}
err_mce_kobj: static int inj_bank_get(void *data, u64 *val)
edac_put_sysfs_subsys(); {
struct mce *m = (struct mce *)data;
return err; *val = m->bank;
return 0;
} }
static void __exit edac_exit_mce_inject(void) DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
struct dfs_node {
char *name;
struct dentry *d;
const struct file_operations *fops;
} dfs_fls[] = {
{ .name = "status", .fops = &status_fops },
{ .name = "misc", .fops = &misc_fops },
{ .name = "addr", .fops = &addr_fops },
{ .name = "bank", .fops = &bank_fops },
{ .name = "flags", .fops = &flags_fops },
{ .name = "cpu", .fops = &extcpu_fops },
};
static int __init init_mce_inject(void)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) dfs_inj = debugfs_create_dir("mce-inject", NULL);
sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr); if (!dfs_inj)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(dfs_fls); i++) {
dfs_fls[i].d = debugfs_create_file(dfs_fls[i].name,
S_IRUSR | S_IWUSR,
dfs_inj,
&i_mce,
dfs_fls[i].fops);
if (!dfs_fls[i].d)
goto err_dfs_add;
}
return 0;
err_dfs_add:
while (--i >= 0)
debugfs_remove(dfs_fls[i].d);
kobject_del(mce_kobj); debugfs_remove(dfs_inj);
dfs_inj = NULL;
edac_put_sysfs_subsys(); return -ENOMEM;
} }
module_init(edac_init_mce_inject); static void __exit exit_mce_inject(void)
module_exit(edac_exit_mce_inject); {
int i;
for (i = 0; i < ARRAY_SIZE(dfs_fls); i++)
debugfs_remove(dfs_fls[i].d);
memset(&dfs_fls, 0, sizeof(dfs_fls));
debugfs_remove(dfs_inj);
dfs_inj = NULL;
}
module_init(init_mce_inject);
module_exit(exit_mce_inject);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>"); MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>");
MODULE_AUTHOR("AMD Inc."); MODULE_AUTHOR("AMD Inc.");
MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding"); MODULE_DESCRIPTION("MCE injection facility for RAS testing");
...@@ -178,7 +178,7 @@ static int mv64x60_pci_err_probe(struct platform_device *pdev) ...@@ -178,7 +178,7 @@ static int mv64x60_pci_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev, res = devm_request_irq(&pdev->dev,
pdata->irq, pdata->irq,
mv64x60_pci_isr, mv64x60_pci_isr,
IRQF_DISABLED, 0,
"[EDAC] PCI err", "[EDAC] PCI err",
pci); pci);
if (res < 0) { if (res < 0) {
...@@ -345,7 +345,7 @@ static int mv64x60_sram_err_probe(struct platform_device *pdev) ...@@ -345,7 +345,7 @@ static int mv64x60_sram_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev, res = devm_request_irq(&pdev->dev,
pdata->irq, pdata->irq,
mv64x60_sram_isr, mv64x60_sram_isr,
IRQF_DISABLED, 0,
"[EDAC] SRAM err", "[EDAC] SRAM err",
edac_dev); edac_dev);
if (res < 0) { if (res < 0) {
...@@ -540,7 +540,7 @@ static int mv64x60_cpu_err_probe(struct platform_device *pdev) ...@@ -540,7 +540,7 @@ static int mv64x60_cpu_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev, res = devm_request_irq(&pdev->dev,
pdata->irq, pdata->irq,
mv64x60_cpu_isr, mv64x60_cpu_isr,
IRQF_DISABLED, 0,
"[EDAC] CPU err", "[EDAC] CPU err",
edac_dev); edac_dev);
if (res < 0) { if (res < 0) {
...@@ -800,7 +800,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) ...@@ -800,7 +800,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev, res = devm_request_irq(&pdev->dev,
pdata->irq, pdata->irq,
mv64x60_mc_isr, mv64x60_mc_isr,
IRQF_DISABLED, 0,
"[EDAC] MC err", "[EDAC] MC err",
mci); mci);
if (res < 0) { if (res < 0) {
......
...@@ -1120,7 +1120,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op, ...@@ -1120,7 +1120,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op,
status = request_irq(ded_irq, status = request_irq(ded_irq,
ppc4xx_edac_isr, ppc4xx_edac_isr,
IRQF_DISABLED, 0,
"[EDAC] MC ECCDED", "[EDAC] MC ECCDED",
mci); mci);
...@@ -1134,7 +1134,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op, ...@@ -1134,7 +1134,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op,
status = request_irq(sec_irq, status = request_irq(sec_irq,
ppc4xx_edac_isr, ppc4xx_edac_isr,
IRQF_DISABLED, 0,
"[EDAC] MC ECCSEC", "[EDAC] MC ECCSEC",
mci); mci);
......
...@@ -500,8 +500,7 @@ static int __init x38_init(void) ...@@ -500,8 +500,7 @@ static int __init x38_init(void)
pci_unregister_driver(&x38_driver); pci_unregister_driver(&x38_driver);
fail0: fail0:
if (mci_pdev) pci_dev_put(mci_pdev);
pci_dev_put(mci_pdev);
return pci_rc; return pci_rc;
} }
......
...@@ -194,7 +194,8 @@ static inline char *mc_event_error_type(const unsigned int err_type) ...@@ -194,7 +194,8 @@ static inline char *mc_event_error_type(const unsigned int err_type)
* @MEM_DDR3: DDR3 RAM * @MEM_DDR3: DDR3 RAM
* @MEM_RDDR3: Registered DDR3 RAM * @MEM_RDDR3: Registered DDR3 RAM
* This is a variant of the DDR3 memories. * This is a variant of the DDR3 memories.
* @MEM_DDR4: DDR4 RAM * @MEM_LRDDR3 Load-Reduced DDR3 memory.
* @MEM_DDR4: Unbuffered DDR4 RAM
* @MEM_RDDR4: Registered DDR4 RAM * @MEM_RDDR4: Registered DDR4 RAM
* This is a variant of the DDR4 memories. * This is a variant of the DDR4 memories.
*/ */
...@@ -216,6 +217,7 @@ enum mem_type { ...@@ -216,6 +217,7 @@ enum mem_type {
MEM_XDR, MEM_XDR,
MEM_DDR3, MEM_DDR3,
MEM_RDDR3, MEM_RDDR3,
MEM_LRDDR3,
MEM_DDR4, MEM_DDR4,
MEM_RDDR4, MEM_RDDR4,
}; };
......
...@@ -522,6 +522,8 @@ ...@@ -522,6 +522,8 @@
#define PCI_DEVICE_ID_AMD_15H_M10H_F3 0x1403 #define PCI_DEVICE_ID_AMD_15H_M10H_F3 0x1403
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F3 0x141d #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F3 0x141d
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F4 0x141e #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F4 0x141e
#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F3 0x1573
#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F4 0x1574
#define PCI_DEVICE_ID_AMD_15H_NB_F0 0x1600 #define PCI_DEVICE_ID_AMD_15H_NB_F0 0x1600
#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 #define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 #define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
......
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