diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-08 23:17:49 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-12-08 23:17:49 -0500 |
commit | 0160928e792eff243c84b39a46cddb2fb89da0cb (patch) | |
tree | 0d8f0b4c0a6218c1618771bed48af1695ee2a3be /drivers/edac | |
parent | 3a7dbed7f23cdde8394e9adf92cc222856e0fc1e (diff) | |
parent | 50872ccd8786dc72bc5a32c17695561e031fae4c (diff) |
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
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/Kconfig | 16 | ||||
-rw-r--r-- | drivers/edac/Makefile | 2 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.c | 260 | ||||
-rw-r--r-- | drivers/edac/amd64_edac.h | 15 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 40 | ||||
-rw-r--r-- | drivers/edac/edac_pci_sysfs.c | 5 | ||||
-rw-r--r-- | drivers/edac/ghes_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/i3000_edac.c | 3 | ||||
-rw-r--r-- | drivers/edac/i3200_edac.c | 3 | ||||
-rw-r--r-- | drivers/edac/i82443bxgx_edac.c | 3 | ||||
-rw-r--r-- | drivers/edac/mce_amd.c | 47 | ||||
-rw-r--r-- | drivers/edac/mce_amd_inj.c | 293 | ||||
-rw-r--r-- | drivers/edac/mv64x60_edac.c | 8 | ||||
-rw-r--r-- | drivers/edac/ppc4xx_edac.c | 4 | ||||
-rw-r--r-- | drivers/edac/x38_edac.c | 3 |
15 files changed, 439 insertions, 267 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 7072c2892d63..49c265255a07 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -61,14 +61,14 @@ config EDAC_DECODE_MCE | |||
61 | has been initialized. | 61 | has been initialized. |
62 | 62 | ||
63 | config EDAC_MCE_INJ | 63 | config EDAC_MCE_INJ |
64 | tristate "Simple MCE injection interface over /sysfs" | 64 | tristate "Simple MCE injection interface" |
65 | depends on EDAC_DECODE_MCE | 65 | depends on EDAC_DECODE_MCE && DEBUG_FS |
66 | default n | 66 | default n |
67 | help | 67 | help |
68 | This is a simple interface to inject MCEs over /sysfs and test | 68 | This is a simple debugfs interface to inject MCEs and test different |
69 | the MCE decoding code in EDAC. | 69 | aspects of the MCE handling code. |
70 | 70 | ||
71 | This is currently AMD-only. | 71 | WARNING: Do not even assume this interface is staying stable! |
72 | 72 | ||
73 | config EDAC_MM_EDAC | 73 | config EDAC_MM_EDAC |
74 | tristate "Main Memory EDAC (Error Detection And Correction) reporting" | 74 | tristate "Main Memory EDAC (Error Detection And Correction) reporting" |
@@ -105,11 +105,11 @@ config EDAC_GHES | |||
105 | In doubt, say 'Y'. | 105 | In doubt, say 'Y'. |
106 | 106 | ||
107 | config EDAC_AMD64 | 107 | config EDAC_AMD64 |
108 | tristate "AMD64 (Opteron, Athlon64) K8, F10h" | 108 | tristate "AMD64 (Opteron, Athlon64)" |
109 | depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE | 109 | depends on EDAC_MM_EDAC && AMD_NB && EDAC_DECODE_MCE |
110 | help | 110 | help |
111 | Support for error detection and correction of DRAM ECC errors on | 111 | Support for error detection and correction of DRAM ECC errors on |
112 | the AMD64 families of memory controllers (K8 and F10h) | 112 | the AMD64 families (>= K8) of memory controllers. |
113 | 113 | ||
114 | config EDAC_AMD64_ERROR_INJECTION | 114 | config EDAC_AMD64_ERROR_INJECTION |
115 | bool "Sysfs HW Error injection facilities" | 115 | bool "Sysfs HW Error injection facilities" |
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile index 359aa499b200..d40c69a04df7 100644 --- a/drivers/edac/Makefile +++ b/drivers/edac/Makefile | |||
@@ -9,7 +9,7 @@ | |||
9 | obj-$(CONFIG_EDAC) := edac_stub.o | 9 | obj-$(CONFIG_EDAC) := edac_stub.o |
10 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o | 10 | obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o |
11 | 11 | ||
12 | edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o | 12 | edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o |
13 | edac_core-y += edac_module.o edac_device_sysfs.o | 13 | edac_core-y += edac_module.o edac_device_sysfs.o |
14 | 14 | ||
15 | ifdef CONFIG_PCI | 15 | ifdef CONFIG_PCI |
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c index bbd65149cdb2..17638d7cf5c2 100644 --- a/drivers/edac/amd64_edac.c +++ b/drivers/edac/amd64_edac.c | |||
@@ -692,9 +692,19 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan) | |||
692 | { | 692 | { |
693 | edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr); | 693 | edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr); |
694 | 694 | ||
695 | edac_dbg(1, " DIMM type: %sbuffered; all DIMMs support ECC: %s\n", | 695 | if (pvt->dram_type == MEM_LRDDR3) { |
696 | (dclr & BIT(16)) ? "un" : "", | 696 | u32 dcsm = pvt->csels[chan].csmasks[0]; |
697 | (dclr & BIT(19)) ? "yes" : "no"); | 697 | /* |
698 | * It's assumed all LRDIMMs in a DCT are going to be of | ||
699 | * same 'type' until proven otherwise. So, use a cs | ||
700 | * value of '0' here to get dcsm value. | ||
701 | */ | ||
702 | edac_dbg(1, " LRDIMM %dx rank multiply\n", (dcsm & 0x3)); | ||
703 | } | ||
704 | |||
705 | edac_dbg(1, "All DIMMs support ECC:%s\n", | ||
706 | (dclr & BIT(19)) ? "yes" : "no"); | ||
707 | |||
698 | 708 | ||
699 | edac_dbg(1, " PAR/ERR parity: %s\n", | 709 | edac_dbg(1, " PAR/ERR parity: %s\n", |
700 | (dclr & BIT(8)) ? "enabled" : "disabled"); | 710 | (dclr & BIT(8)) ? "enabled" : "disabled"); |
@@ -756,7 +766,7 @@ static void prep_chip_selects(struct amd64_pvt *pvt) | |||
756 | if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { | 766 | if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) { |
757 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; | 767 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8; |
758 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8; | 768 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8; |
759 | } else if (pvt->fam == 0x15 && pvt->model >= 0x30) { | 769 | } else if (pvt->fam == 0x15 && pvt->model == 0x30) { |
760 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; | 770 | pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4; |
761 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; | 771 | pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2; |
762 | } else { | 772 | } else { |
@@ -813,25 +823,63 @@ static void read_dct_base_mask(struct amd64_pvt *pvt) | |||
813 | } | 823 | } |
814 | } | 824 | } |
815 | 825 | ||
816 | static enum mem_type determine_memory_type(struct amd64_pvt *pvt, int cs) | 826 | static void determine_memory_type(struct amd64_pvt *pvt) |
817 | { | 827 | { |
818 | enum mem_type type; | 828 | u32 dram_ctrl, dcsm; |
819 | 829 | ||
820 | /* F15h supports only DDR3 */ | 830 | switch (pvt->fam) { |
821 | if (pvt->fam >= 0x15) | 831 | case 0xf: |
822 | type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; | 832 | if (pvt->ext_model >= K8_REV_F) |
823 | else if (pvt->fam == 0x10 || pvt->ext_model >= K8_REV_F) { | 833 | goto ddr3; |
834 | |||
835 | pvt->dram_type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR; | ||
836 | return; | ||
837 | |||
838 | case 0x10: | ||
824 | if (pvt->dchr0 & DDR3_MODE) | 839 | if (pvt->dchr0 & DDR3_MODE) |
825 | type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; | 840 | goto ddr3; |
841 | |||
842 | pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2; | ||
843 | return; | ||
844 | |||
845 | case 0x15: | ||
846 | if (pvt->model < 0x60) | ||
847 | goto ddr3; | ||
848 | |||
849 | /* | ||
850 | * Model 0x60h needs special handling: | ||
851 | * | ||
852 | * We use a Chip Select value of '0' to obtain dcsm. | ||
853 | * Theoretically, it is possible to populate LRDIMMs of different | ||
854 | * 'Rank' value on a DCT. But this is not the common case. So, | ||
855 | * it's reasonable to assume all DIMMs are going to be of same | ||
856 | * 'type' until proven otherwise. | ||
857 | */ | ||
858 | amd64_read_dct_pci_cfg(pvt, 0, DRAM_CONTROL, &dram_ctrl); | ||
859 | dcsm = pvt->csels[0].csmasks[0]; | ||
860 | |||
861 | if (((dram_ctrl >> 8) & 0x7) == 0x2) | ||
862 | pvt->dram_type = MEM_DDR4; | ||
863 | else if (pvt->dclr0 & BIT(16)) | ||
864 | pvt->dram_type = MEM_DDR3; | ||
865 | else if (dcsm & 0x3) | ||
866 | pvt->dram_type = MEM_LRDDR3; | ||
826 | else | 867 | else |
827 | type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2; | 868 | pvt->dram_type = MEM_RDDR3; |
828 | } else { | ||
829 | type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR; | ||
830 | } | ||
831 | 869 | ||
832 | amd64_info("CS%d: %s\n", cs, edac_mem_types[type]); | 870 | return; |
833 | 871 | ||
834 | return type; | 872 | case 0x16: |
873 | goto ddr3; | ||
874 | |||
875 | default: | ||
876 | WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam); | ||
877 | pvt->dram_type = MEM_EMPTY; | ||
878 | } | ||
879 | return; | ||
880 | |||
881 | ddr3: | ||
882 | pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3; | ||
835 | } | 883 | } |
836 | 884 | ||
837 | /* Get the number of DCT channels the memory controller is using. */ | 885 | /* Get the number of DCT channels the memory controller is using. */ |
@@ -958,8 +1006,12 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range) | |||
958 | if (WARN_ON(!nb)) | 1006 | if (WARN_ON(!nb)) |
959 | return; | 1007 | return; |
960 | 1008 | ||
961 | pci_func = (pvt->model == 0x30) ? PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 | 1009 | if (pvt->model == 0x60) |
962 | : PCI_DEVICE_ID_AMD_15H_NB_F1; | 1010 | pci_func = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1; |
1011 | else if (pvt->model == 0x30) | ||
1012 | pci_func = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1; | ||
1013 | else | ||
1014 | pci_func = PCI_DEVICE_ID_AMD_15H_NB_F1; | ||
963 | 1015 | ||
964 | f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc); | 1016 | f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc); |
965 | if (WARN_ON(!f1)) | 1017 | if (WARN_ON(!f1)) |
@@ -1049,7 +1101,7 @@ static int ddr2_cs_size(unsigned i, bool dct_width) | |||
1049 | } | 1101 | } |
1050 | 1102 | ||
1051 | static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, | 1103 | static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, |
1052 | unsigned cs_mode) | 1104 | unsigned cs_mode, int cs_mask_nr) |
1053 | { | 1105 | { |
1054 | u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; | 1106 | u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; |
1055 | 1107 | ||
@@ -1167,8 +1219,43 @@ static int ddr3_cs_size(unsigned i, bool dct_width) | |||
1167 | return cs_size; | 1219 | return cs_size; |
1168 | } | 1220 | } |
1169 | 1221 | ||
1222 | static int ddr3_lrdimm_cs_size(unsigned i, unsigned rank_multiply) | ||
1223 | { | ||
1224 | unsigned shift = 0; | ||
1225 | int cs_size = 0; | ||
1226 | |||
1227 | if (i < 4 || i == 6) | ||
1228 | cs_size = -1; | ||
1229 | else if (i == 12) | ||
1230 | shift = 7; | ||
1231 | else if (!(i & 0x1)) | ||
1232 | shift = i >> 1; | ||
1233 | else | ||
1234 | shift = (i + 1) >> 1; | ||
1235 | |||
1236 | if (cs_size != -1) | ||
1237 | cs_size = rank_multiply * (128 << shift); | ||
1238 | |||
1239 | return cs_size; | ||
1240 | } | ||
1241 | |||
1242 | static int ddr4_cs_size(unsigned i) | ||
1243 | { | ||
1244 | int cs_size = 0; | ||
1245 | |||
1246 | if (i == 0) | ||
1247 | cs_size = -1; | ||
1248 | else if (i == 1) | ||
1249 | cs_size = 1024; | ||
1250 | else | ||
1251 | /* Min cs_size = 1G */ | ||
1252 | cs_size = 1024 * (1 << (i >> 1)); | ||
1253 | |||
1254 | return cs_size; | ||
1255 | } | ||
1256 | |||
1170 | static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, | 1257 | static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, |
1171 | unsigned cs_mode) | 1258 | unsigned cs_mode, int cs_mask_nr) |
1172 | { | 1259 | { |
1173 | u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; | 1260 | u32 dclr = dct ? pvt->dclr1 : pvt->dclr0; |
1174 | 1261 | ||
@@ -1184,18 +1271,49 @@ static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, | |||
1184 | * F15h supports only 64bit DCT interfaces | 1271 | * F15h supports only 64bit DCT interfaces |
1185 | */ | 1272 | */ |
1186 | static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, | 1273 | static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, |
1187 | unsigned cs_mode) | 1274 | unsigned cs_mode, int cs_mask_nr) |
1188 | { | 1275 | { |
1189 | WARN_ON(cs_mode > 12); | 1276 | WARN_ON(cs_mode > 12); |
1190 | 1277 | ||
1191 | return ddr3_cs_size(cs_mode, false); | 1278 | return ddr3_cs_size(cs_mode, false); |
1192 | } | 1279 | } |
1193 | 1280 | ||
1281 | /* F15h M60h supports DDR4 mapping as well.. */ | ||
1282 | static int f15_m60h_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, | ||
1283 | unsigned cs_mode, int cs_mask_nr) | ||
1284 | { | ||
1285 | int cs_size; | ||
1286 | u32 dcsm = pvt->csels[dct].csmasks[cs_mask_nr]; | ||
1287 | |||
1288 | WARN_ON(cs_mode > 12); | ||
1289 | |||
1290 | if (pvt->dram_type == MEM_DDR4) { | ||
1291 | if (cs_mode > 9) | ||
1292 | return -1; | ||
1293 | |||
1294 | cs_size = ddr4_cs_size(cs_mode); | ||
1295 | } else if (pvt->dram_type == MEM_LRDDR3) { | ||
1296 | unsigned rank_multiply = dcsm & 0xf; | ||
1297 | |||
1298 | if (rank_multiply == 3) | ||
1299 | rank_multiply = 4; | ||
1300 | cs_size = ddr3_lrdimm_cs_size(cs_mode, rank_multiply); | ||
1301 | } else { | ||
1302 | /* Minimum cs size is 512mb for F15hM60h*/ | ||
1303 | if (cs_mode == 0x1) | ||
1304 | return -1; | ||
1305 | |||
1306 | cs_size = ddr3_cs_size(cs_mode, false); | ||
1307 | } | ||
1308 | |||
1309 | return cs_size; | ||
1310 | } | ||
1311 | |||
1194 | /* | 1312 | /* |
1195 | * F16h and F15h model 30h have only limited cs_modes. | 1313 | * F16h and F15h model 30h have only limited cs_modes. |
1196 | */ | 1314 | */ |
1197 | static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, | 1315 | static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct, |
1198 | unsigned cs_mode) | 1316 | unsigned cs_mode, int cs_mask_nr) |
1199 | { | 1317 | { |
1200 | WARN_ON(cs_mode > 12); | 1318 | WARN_ON(cs_mode > 12); |
1201 | 1319 | ||
@@ -1757,13 +1875,20 @@ static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl) | |||
1757 | 1875 | ||
1758 | size0 = 0; | 1876 | size0 = 0; |
1759 | if (dcsb[dimm*2] & DCSB_CS_ENABLE) | 1877 | if (dcsb[dimm*2] & DCSB_CS_ENABLE) |
1878 | /* For f15m60h, need multiplier for LRDIMM cs_size | ||
1879 | * calculation. We pass 'dimm' value to the dbam_to_cs | ||
1880 | * mapper so we can find the multiplier from the | ||
1881 | * corresponding DCSM. | ||
1882 | */ | ||
1760 | size0 = pvt->ops->dbam_to_cs(pvt, ctrl, | 1883 | size0 = pvt->ops->dbam_to_cs(pvt, ctrl, |
1761 | DBAM_DIMM(dimm, dbam)); | 1884 | DBAM_DIMM(dimm, dbam), |
1885 | dimm); | ||
1762 | 1886 | ||
1763 | size1 = 0; | 1887 | size1 = 0; |
1764 | if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE) | 1888 | if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE) |
1765 | size1 = pvt->ops->dbam_to_cs(pvt, ctrl, | 1889 | size1 = pvt->ops->dbam_to_cs(pvt, ctrl, |
1766 | DBAM_DIMM(dimm, dbam)); | 1890 | DBAM_DIMM(dimm, dbam), |
1891 | dimm); | ||
1767 | 1892 | ||
1768 | amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", | 1893 | amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n", |
1769 | dimm * 2, size0, | 1894 | dimm * 2, size0, |
@@ -1812,6 +1937,16 @@ static struct amd64_family_type family_types[] = { | |||
1812 | .dbam_to_cs = f16_dbam_to_chip_select, | 1937 | .dbam_to_cs = f16_dbam_to_chip_select, |
1813 | } | 1938 | } |
1814 | }, | 1939 | }, |
1940 | [F15_M60H_CPUS] = { | ||
1941 | .ctl_name = "F15h_M60h", | ||
1942 | .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1, | ||
1943 | .f3_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F3, | ||
1944 | .ops = { | ||
1945 | .early_channel_count = f1x_early_channel_count, | ||
1946 | .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow, | ||
1947 | .dbam_to_cs = f15_m60h_dbam_to_chip_select, | ||
1948 | } | ||
1949 | }, | ||
1815 | [F16_CPUS] = { | 1950 | [F16_CPUS] = { |
1816 | .ctl_name = "F16h", | 1951 | .ctl_name = "F16h", |
1817 | .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1, | 1952 | .f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1, |
@@ -2175,6 +2310,8 @@ static void read_mc_regs(struct amd64_pvt *pvt) | |||
2175 | } | 2310 | } |
2176 | 2311 | ||
2177 | pvt->ecc_sym_sz = 4; | 2312 | pvt->ecc_sym_sz = 4; |
2313 | determine_memory_type(pvt); | ||
2314 | edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]); | ||
2178 | 2315 | ||
2179 | if (pvt->fam >= 0x10) { | 2316 | if (pvt->fam >= 0x10) { |
2180 | amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); | 2317 | amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp); |
@@ -2238,7 +2375,8 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr) | |||
2238 | */ | 2375 | */ |
2239 | cs_mode = DBAM_DIMM(csrow_nr / 2, dbam); | 2376 | cs_mode = DBAM_DIMM(csrow_nr / 2, dbam); |
2240 | 2377 | ||
2241 | nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT); | 2378 | nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, (csrow_nr / 2)) |
2379 | << (20 - PAGE_SHIFT); | ||
2242 | 2380 | ||
2243 | edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n", | 2381 | edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n", |
2244 | csrow_nr, dct, cs_mode); | 2382 | csrow_nr, dct, cs_mode); |
@@ -2257,7 +2395,6 @@ static int init_csrows(struct mem_ctl_info *mci) | |||
2257 | struct csrow_info *csrow; | 2395 | struct csrow_info *csrow; |
2258 | struct dimm_info *dimm; | 2396 | struct dimm_info *dimm; |
2259 | enum edac_type edac_mode; | 2397 | enum edac_type edac_mode; |
2260 | enum mem_type mtype; | ||
2261 | int i, j, empty = 1; | 2398 | int i, j, empty = 1; |
2262 | int nr_pages = 0; | 2399 | int nr_pages = 0; |
2263 | u32 val; | 2400 | u32 val; |
@@ -2302,8 +2439,6 @@ static int init_csrows(struct mem_ctl_info *mci) | |||
2302 | nr_pages += row_dct1_pages; | 2439 | nr_pages += row_dct1_pages; |
2303 | } | 2440 | } |
2304 | 2441 | ||
2305 | mtype = determine_memory_type(pvt, i); | ||
2306 | |||
2307 | edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages); | 2442 | edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages); |
2308 | 2443 | ||
2309 | /* | 2444 | /* |
@@ -2317,7 +2452,7 @@ static int init_csrows(struct mem_ctl_info *mci) | |||
2317 | 2452 | ||
2318 | for (j = 0; j < pvt->channel_count; j++) { | 2453 | for (j = 0; j < pvt->channel_count; j++) { |
2319 | dimm = csrow->channels[j]->dimm; | 2454 | dimm = csrow->channels[j]->dimm; |
2320 | dimm->mtype = mtype; | 2455 | dimm->mtype = pvt->dram_type; |
2321 | dimm->edac_mode = edac_mode; | 2456 | dimm->edac_mode = edac_mode; |
2322 | } | 2457 | } |
2323 | } | 2458 | } |
@@ -2604,6 +2739,10 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt) | |||
2604 | fam_type = &family_types[F15_M30H_CPUS]; | 2739 | fam_type = &family_types[F15_M30H_CPUS]; |
2605 | pvt->ops = &family_types[F15_M30H_CPUS].ops; | 2740 | pvt->ops = &family_types[F15_M30H_CPUS].ops; |
2606 | break; | 2741 | break; |
2742 | } else if (pvt->model == 0x60) { | ||
2743 | fam_type = &family_types[F15_M60H_CPUS]; | ||
2744 | pvt->ops = &family_types[F15_M60H_CPUS].ops; | ||
2745 | break; | ||
2607 | } | 2746 | } |
2608 | 2747 | ||
2609 | fam_type = &family_types[F15_CPUS]; | 2748 | fam_type = &family_types[F15_CPUS]; |
@@ -2828,55 +2967,13 @@ static void remove_one_instance(struct pci_dev *pdev) | |||
2828 | * inquiry this table to see if this driver is for a given device found. | 2967 | * inquiry this table to see if this driver is for a given device found. |
2829 | */ | 2968 | */ |
2830 | static const struct pci_device_id amd64_pci_table[] = { | 2969 | static const struct pci_device_id amd64_pci_table[] = { |
2831 | { | 2970 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_K8_NB_MEMCTL) }, |
2832 | .vendor = PCI_VENDOR_ID_AMD, | 2971 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_DRAM) }, |
2833 | .device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL, | 2972 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F2) }, |
2834 | .subvendor = PCI_ANY_ID, | 2973 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F2) }, |
2835 | .subdevice = PCI_ANY_ID, | 2974 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F2) }, |
2836 | .class = 0, | 2975 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F2) }, |
2837 | .class_mask = 0, | 2976 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F2) }, |
2838 | }, | ||
2839 | { | ||
2840 | .vendor = PCI_VENDOR_ID_AMD, | ||
2841 | .device = PCI_DEVICE_ID_AMD_10H_NB_DRAM, | ||
2842 | .subvendor = PCI_ANY_ID, | ||
2843 | .subdevice = PCI_ANY_ID, | ||
2844 | .class = 0, | ||
2845 | .class_mask = 0, | ||
2846 | }, | ||
2847 | { | ||
2848 | .vendor = PCI_VENDOR_ID_AMD, | ||
2849 | .device = PCI_DEVICE_ID_AMD_15H_NB_F2, | ||
2850 | .subvendor = PCI_ANY_ID, | ||
2851 | .subdevice = PCI_ANY_ID, | ||
2852 | .class = 0, | ||
2853 | .class_mask = 0, | ||
2854 | }, | ||
2855 | { | ||
2856 | .vendor = PCI_VENDOR_ID_AMD, | ||
2857 | .device = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2, | ||
2858 | .subvendor = PCI_ANY_ID, | ||
2859 | .subdevice = PCI_ANY_ID, | ||
2860 | .class = 0, | ||
2861 | .class_mask = 0, | ||
2862 | }, | ||
2863 | { | ||
2864 | .vendor = PCI_VENDOR_ID_AMD, | ||
2865 | .device = PCI_DEVICE_ID_AMD_16H_NB_F2, | ||
2866 | .subvendor = PCI_ANY_ID, | ||
2867 | .subdevice = PCI_ANY_ID, | ||
2868 | .class = 0, | ||
2869 | .class_mask = 0, | ||
2870 | }, | ||
2871 | { | ||
2872 | .vendor = PCI_VENDOR_ID_AMD, | ||
2873 | .device = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2, | ||
2874 | .subvendor = PCI_ANY_ID, | ||
2875 | .subdevice = PCI_ANY_ID, | ||
2876 | .class = 0, | ||
2877 | .class_mask = 0, | ||
2878 | }, | ||
2879 | |||
2880 | {0, } | 2977 | {0, } |
2881 | }; | 2978 | }; |
2882 | MODULE_DEVICE_TABLE(pci, amd64_pci_table); | 2979 | MODULE_DEVICE_TABLE(pci, amd64_pci_table); |
@@ -2938,6 +3035,11 @@ static int __init amd64_edac_init(void) | |||
2938 | goto err_no_instances; | 3035 | goto err_no_instances; |
2939 | 3036 | ||
2940 | setup_pci_device(); | 3037 | setup_pci_device(); |
3038 | |||
3039 | #ifdef CONFIG_X86_32 | ||
3040 | amd64_err("%s on 32-bit is unsupported. USE AT YOUR OWN RISK!\n", EDAC_MOD_STR); | ||
3041 | #endif | ||
3042 | |||
2941 | return 0; | 3043 | return 0; |
2942 | 3044 | ||
2943 | err_no_instances: | 3045 | err_no_instances: |
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h index 55fb5941c6d4..d8468c667925 100644 --- a/drivers/edac/amd64_edac.h +++ b/drivers/edac/amd64_edac.h | |||
@@ -162,10 +162,12 @@ | |||
162 | /* | 162 | /* |
163 | * PCI-defined configuration space registers | 163 | * PCI-defined configuration space registers |
164 | */ | 164 | */ |
165 | #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b | ||
166 | #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c | ||
167 | #define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 | 165 | #define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601 |
168 | #define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 | 166 | #define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602 |
167 | #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b | ||
168 | #define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c | ||
169 | #define PCI_DEVICE_ID_AMD_15H_M60H_NB_F1 0x1571 | ||
170 | #define PCI_DEVICE_ID_AMD_15H_M60H_NB_F2 0x1572 | ||
169 | #define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531 | 171 | #define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531 |
170 | #define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532 | 172 | #define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532 |
171 | #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581 | 173 | #define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581 |
@@ -221,6 +223,8 @@ | |||
221 | 223 | ||
222 | #define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE) | 224 | #define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE) |
223 | 225 | ||
226 | #define DRAM_CONTROL 0x78 | ||
227 | |||
224 | #define DBAM0 0x80 | 228 | #define DBAM0 0x80 |
225 | #define DBAM1 0x180 | 229 | #define DBAM1 0x180 |
226 | 230 | ||
@@ -301,6 +305,7 @@ enum amd_families { | |||
301 | F10_CPUS, | 305 | F10_CPUS, |
302 | F15_CPUS, | 306 | F15_CPUS, |
303 | F15_M30H_CPUS, | 307 | F15_M30H_CPUS, |
308 | F15_M60H_CPUS, | ||
304 | F16_CPUS, | 309 | F16_CPUS, |
305 | F16_M30H_CPUS, | 310 | F16_M30H_CPUS, |
306 | NUM_FAMILIES, | 311 | NUM_FAMILIES, |
@@ -379,6 +384,9 @@ struct amd64_pvt { | |||
379 | 384 | ||
380 | /* place to store error injection parameters prior to issue */ | 385 | /* place to store error injection parameters prior to issue */ |
381 | struct error_injection injection; | 386 | struct error_injection injection; |
387 | |||
388 | /* cache the dram_type */ | ||
389 | enum mem_type dram_type; | ||
382 | }; | 390 | }; |
383 | 391 | ||
384 | enum err_codes { | 392 | enum err_codes { |
@@ -480,7 +488,8 @@ struct low_ops { | |||
480 | int (*early_channel_count) (struct amd64_pvt *pvt); | 488 | int (*early_channel_count) (struct amd64_pvt *pvt); |
481 | void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, | 489 | void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr, |
482 | struct err_info *); | 490 | struct err_info *); |
483 | int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode); | 491 | int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, |
492 | unsigned cs_mode, int cs_mask_nr); | ||
484 | }; | 493 | }; |
485 | 494 | ||
486 | struct amd64_family_type { | 495 | struct amd64_family_type { |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index c3893b0ddb18..1747906f10ce 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -125,27 +125,27 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci) | |||
125 | 125 | ||
126 | #endif /* CONFIG_EDAC_DEBUG */ | 126 | #endif /* CONFIG_EDAC_DEBUG */ |
127 | 127 | ||
128 | /* | ||
129 | * keep those in sync with the enum mem_type | ||
130 | */ | ||
131 | const char * const edac_mem_types[] = { | 128 | const char * const edac_mem_types[] = { |
132 | "Empty csrow", | 129 | [MEM_EMPTY] = "Empty csrow", |
133 | "Reserved csrow type", | 130 | [MEM_RESERVED] = "Reserved csrow type", |
134 | "Unknown csrow type", | 131 | [MEM_UNKNOWN] = "Unknown csrow type", |
135 | "Fast page mode RAM", | 132 | [MEM_FPM] = "Fast page mode RAM", |
136 | "Extended data out RAM", | 133 | [MEM_EDO] = "Extended data out RAM", |
137 | "Burst Extended data out RAM", | 134 | [MEM_BEDO] = "Burst Extended data out RAM", |
138 | "Single data rate SDRAM", | 135 | [MEM_SDR] = "Single data rate SDRAM", |
139 | "Registered single data rate SDRAM", | 136 | [MEM_RDR] = "Registered single data rate SDRAM", |
140 | "Double data rate SDRAM", | 137 | [MEM_DDR] = "Double data rate SDRAM", |
141 | "Registered Double data rate SDRAM", | 138 | [MEM_RDDR] = "Registered Double data rate SDRAM", |
142 | "Rambus DRAM", | 139 | [MEM_RMBS] = "Rambus DRAM", |
143 | "Unbuffered DDR2 RAM", | 140 | [MEM_DDR2] = "Unbuffered DDR2 RAM", |
144 | "Fully buffered DDR2", | 141 | [MEM_FB_DDR2] = "Fully buffered DDR2", |
145 | "Registered DDR2 RAM", | 142 | [MEM_RDDR2] = "Registered DDR2 RAM", |
146 | "Rambus XDR", | 143 | [MEM_XDR] = "Rambus XDR", |
147 | "Unbuffered DDR3 RAM", | 144 | [MEM_DDR3] = "Unbuffered DDR3 RAM", |
148 | "Registered DDR3 RAM", | 145 | [MEM_RDDR3] = "Registered DDR3 RAM", |
146 | [MEM_LRDDR3] = "Load-Reduced DDR3 RAM", | ||
147 | [MEM_DDR4] = "Unbuffered DDR4 RAM", | ||
148 | [MEM_RDDR4] = "Registered DDR4 RAM", | ||
149 | }; | 149 | }; |
150 | EXPORT_SYMBOL_GPL(edac_mem_types); | 150 | EXPORT_SYMBOL_GPL(edac_mem_types); |
151 | 151 | ||
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c index e8658e451762..24d877f6e577 100644 --- a/drivers/edac/edac_pci_sysfs.c +++ b/drivers/edac/edac_pci_sysfs.c | |||
@@ -14,9 +14,6 @@ | |||
14 | #include "edac_core.h" | 14 | #include "edac_core.h" |
15 | #include "edac_module.h" | 15 | #include "edac_module.h" |
16 | 16 | ||
17 | /* Turn off this whole feature if PCI is not configured */ | ||
18 | #ifdef CONFIG_PCI | ||
19 | |||
20 | #define EDAC_PCI_SYMLINK "device" | 17 | #define EDAC_PCI_SYMLINK "device" |
21 | 18 | ||
22 | /* data variables exported via sysfs */ | 19 | /* data variables exported via sysfs */ |
@@ -761,5 +758,3 @@ MODULE_PARM_DESC(check_pci_errors, | |||
761 | module_param(edac_pci_panic_on_pe, int, 0644); | 758 | module_param(edac_pci_panic_on_pe, int, 0644); |
762 | MODULE_PARM_DESC(edac_pci_panic_on_pe, | 759 | MODULE_PARM_DESC(edac_pci_panic_on_pe, |
763 | "Panic on PCI Bus Parity error: 0=off 1=on"); | 760 | "Panic on PCI Bus Parity error: 0=off 1=on"); |
764 | |||
765 | #endif /* CONFIG_PCI */ | ||
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c index 8399b4e16fe0..b24681998740 100644 --- a/drivers/edac/ghes_edac.c +++ b/drivers/edac/ghes_edac.c | |||
@@ -413,8 +413,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev, | |||
413 | 413 | ||
414 | /* Generate the trace event */ | 414 | /* Generate the trace event */ |
415 | grain_bits = fls_long(e->grain); | 415 | grain_bits = fls_long(e->grain); |
416 | sprintf(pvt->detail_location, "APEI location: %s %s", | 416 | snprintf(pvt->detail_location, sizeof(pvt->detail_location), |
417 | e->location, e->other_detail); | 417 | "APEI location: %s %s", e->location, e->other_detail); |
418 | trace_mc_event(type, e->msg, e->label, e->error_count, | 418 | trace_mc_event(type, e->msg, e->label, e->error_count, |
419 | mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer, | 419 | mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer, |
420 | PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page, | 420 | PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page, |
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c index cd28b968e5c7..5cb36a6022cc 100644 --- a/drivers/edac/i3000_edac.c +++ b/drivers/edac/i3000_edac.c | |||
@@ -542,8 +542,7 @@ fail1: | |||
542 | pci_unregister_driver(&i3000_driver); | 542 | pci_unregister_driver(&i3000_driver); |
543 | 543 | ||
544 | fail0: | 544 | fail0: |
545 | if (mci_pdev) | 545 | pci_dev_put(mci_pdev); |
546 | pci_dev_put(mci_pdev); | ||
547 | 546 | ||
548 | return pci_rc; | 547 | return pci_rc; |
549 | } | 548 | } |
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c index aa98b136f5d0..4ad062b0ef26 100644 --- a/drivers/edac/i3200_edac.c +++ b/drivers/edac/i3200_edac.c | |||
@@ -523,8 +523,7 @@ fail1: | |||
523 | pci_unregister_driver(&i3200_driver); | 523 | pci_unregister_driver(&i3200_driver); |
524 | 524 | ||
525 | fail0: | 525 | fail0: |
526 | if (mci_pdev) | 526 | pci_dev_put(mci_pdev); |
527 | pci_dev_put(mci_pdev); | ||
528 | 527 | ||
529 | return pci_rc; | 528 | return pci_rc; |
530 | } | 529 | } |
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c index d730e276d1a8..b4705d9366bf 100644 --- a/drivers/edac/i82443bxgx_edac.c +++ b/drivers/edac/i82443bxgx_edac.c | |||
@@ -458,8 +458,7 @@ static void __exit i82443bxgx_edacmc_exit(void) | |||
458 | if (!i82443bxgx_registered) | 458 | if (!i82443bxgx_registered) |
459 | i82443bxgx_edacmc_remove_one(mci_pdev); | 459 | i82443bxgx_edacmc_remove_one(mci_pdev); |
460 | 460 | ||
461 | if (mci_pdev) | 461 | pci_dev_put(mci_pdev); |
462 | pci_dev_put(mci_pdev); | ||
463 | } | 462 | } |
464 | 463 | ||
465 | module_init(i82443bxgx_edacmc_init); | 464 | module_init(i82443bxgx_edacmc_init); |
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c index f78c1c54dbd5..58586d59bf8e 100644 --- a/drivers/edac/mce_amd.c +++ b/drivers/edac/mce_amd.c | |||
@@ -138,6 +138,15 @@ static const char * const mc5_mce_desc[] = { | |||
138 | "Retire status queue" | 138 | "Retire status queue" |
139 | }; | 139 | }; |
140 | 140 | ||
141 | static const char * const mc6_mce_desc[] = { | ||
142 | "Hardware Assertion", | ||
143 | "Free List", | ||
144 | "Physical Register File", | ||
145 | "Retire Queue", | ||
146 | "Scheduler table", | ||
147 | "Status Register File", | ||
148 | }; | ||
149 | |||
141 | static bool f12h_mc0_mce(u16 ec, u8 xec) | 150 | static bool f12h_mc0_mce(u16 ec, u8 xec) |
142 | { | 151 | { |
143 | bool ret = false; | 152 | bool ret = false; |
@@ -432,8 +441,8 @@ static bool k8_mc2_mce(u16 ec, u8 xec) | |||
432 | pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec)); | 441 | pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec)); |
433 | else if (xec == 0x0) { | 442 | else if (xec == 0x0) { |
434 | if (TLB_ERROR(ec)) | 443 | if (TLB_ERROR(ec)) |
435 | pr_cont(": %s error in a Page Descriptor Cache or " | 444 | pr_cont("%s error in a Page Descriptor Cache or Guest TLB.\n", |
436 | "Guest TLB.\n", TT_MSG(ec)); | 445 | TT_MSG(ec)); |
437 | else if (BUS_ERROR(ec)) | 446 | else if (BUS_ERROR(ec)) |
438 | pr_cont(": %s/ECC error in data read from NB: %s.\n", | 447 | pr_cont(": %s/ECC error in data read from NB: %s.\n", |
439 | R4_MSG(ec), PP_MSG(ec)); | 448 | R4_MSG(ec), PP_MSG(ec)); |
@@ -672,38 +681,10 @@ static void decode_mc6_mce(struct mce *m) | |||
672 | 681 | ||
673 | pr_emerg(HW_ERR "MC6 Error: "); | 682 | pr_emerg(HW_ERR "MC6 Error: "); |
674 | 683 | ||
675 | switch (xec) { | 684 | if (xec > 0x5) |
676 | case 0x0: | ||
677 | pr_cont("Hardware Assertion"); | ||
678 | break; | ||
679 | |||
680 | case 0x1: | ||
681 | pr_cont("Free List"); | ||
682 | break; | ||
683 | |||
684 | case 0x2: | ||
685 | pr_cont("Physical Register File"); | ||
686 | break; | ||
687 | |||
688 | case 0x3: | ||
689 | pr_cont("Retire Queue"); | ||
690 | break; | ||
691 | |||
692 | case 0x4: | ||
693 | pr_cont("Scheduler table"); | ||
694 | break; | ||
695 | |||
696 | case 0x5: | ||
697 | pr_cont("Status Register File"); | ||
698 | break; | ||
699 | |||
700 | default: | ||
701 | goto wrong_mc6_mce; | 685 | goto wrong_mc6_mce; |
702 | break; | ||
703 | } | ||
704 | |||
705 | pr_cont(" parity error.\n"); | ||
706 | 686 | ||
687 | pr_cont("%s parity error.\n", mc6_mce_desc[xec]); | ||
707 | return; | 688 | return; |
708 | 689 | ||
709 | wrong_mc6_mce: | 690 | wrong_mc6_mce: |
@@ -800,7 +781,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data) | |||
800 | pr_cont("]: 0x%016llx\n", m->status); | 781 | pr_cont("]: 0x%016llx\n", m->status); |
801 | 782 | ||
802 | if (m->status & MCI_STATUS_ADDRV) | 783 | if (m->status & MCI_STATUS_ADDRV) |
803 | pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr); | 784 | pr_emerg(HW_ERR "MC%d Error Address: 0x%016llx\n", m->bank, m->addr); |
804 | 785 | ||
805 | if (!fam_ops) | 786 | if (!fam_ops) |
806 | goto err_code; | 787 | goto err_code; |
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c index 5e46a9fea31b..0bd91a802c67 100644 --- a/drivers/edac/mce_amd_inj.c +++ b/drivers/edac/mce_amd_inj.c | |||
@@ -1,173 +1,262 @@ | |||
1 | /* | 1 | /* |
2 | * A simple MCE injection facility for testing the MCE decoding code. This | 2 | * A simple MCE injection facility for testing different aspects of the RAS |
3 | * driver should be built as module so that it can be loaded on production | 3 | * code. This driver should be built as module so that it can be loaded |
4 | * kernels for testing purposes. | 4 | * on production kernels for testing purposes. |
5 | * | 5 | * |
6 | * This file may be distributed under the terms of the GNU General Public | 6 | * This file may be distributed under the terms of the GNU General Public |
7 | * License version 2. | 7 | * License version 2. |
8 | * | 8 | * |
9 | * Copyright (c) 2010: Borislav Petkov <bp@alien8.de> | 9 | * Copyright (c) 2010-14: Borislav Petkov <bp@alien8.de> |
10 | * Advanced Micro Devices Inc. | 10 | * Advanced Micro Devices Inc. |
11 | */ | 11 | */ |
12 | 12 | ||
13 | #include <linux/kobject.h> | 13 | #include <linux/kobject.h> |
14 | #include <linux/debugfs.h> | ||
14 | #include <linux/device.h> | 15 | #include <linux/device.h> |
15 | #include <linux/edac.h> | ||
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/cpu.h> | ||
17 | #include <asm/mce.h> | 18 | #include <asm/mce.h> |
18 | 19 | ||
19 | #include "mce_amd.h" | 20 | #include "mce_amd.h" |
20 | 21 | ||
21 | struct edac_mce_attr { | ||
22 | struct attribute attr; | ||
23 | ssize_t (*show) (struct kobject *kobj, struct edac_mce_attr *attr, char *buf); | ||
24 | ssize_t (*store)(struct kobject *kobj, struct edac_mce_attr *attr, | ||
25 | const char *buf, size_t count); | ||
26 | }; | ||
27 | |||
28 | #define EDAC_MCE_ATTR(_name, _mode, _show, _store) \ | ||
29 | static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _store) | ||
30 | |||
31 | static struct kobject *mce_kobj; | ||
32 | |||
33 | /* | 22 | /* |
34 | * Collect all the MCi_XXX settings | 23 | * Collect all the MCi_XXX settings |
35 | */ | 24 | */ |
36 | static struct mce i_mce; | 25 | static struct mce i_mce; |
26 | static struct dentry *dfs_inj; | ||
37 | 27 | ||
38 | #define MCE_INJECT_STORE(reg) \ | 28 | #define MCE_INJECT_SET(reg) \ |
39 | static ssize_t edac_inject_##reg##_store(struct kobject *kobj, \ | 29 | static int inj_##reg##_set(void *data, u64 val) \ |
40 | struct edac_mce_attr *attr, \ | ||
41 | const char *data, size_t count)\ | ||
42 | { \ | 30 | { \ |
43 | int ret = 0; \ | 31 | struct mce *m = (struct mce *)data; \ |
44 | unsigned long value; \ | ||
45 | \ | ||
46 | ret = kstrtoul(data, 16, &value); \ | ||
47 | if (ret < 0) \ | ||
48 | printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \ | ||
49 | \ | 32 | \ |
50 | i_mce.reg = value; \ | 33 | m->reg = val; \ |
51 | \ | 34 | return 0; \ |
52 | return count; \ | ||
53 | } | 35 | } |
54 | 36 | ||
55 | MCE_INJECT_STORE(status); | 37 | MCE_INJECT_SET(status); |
56 | MCE_INJECT_STORE(misc); | 38 | MCE_INJECT_SET(misc); |
57 | MCE_INJECT_STORE(addr); | 39 | MCE_INJECT_SET(addr); |
58 | 40 | ||
59 | #define MCE_INJECT_SHOW(reg) \ | 41 | #define MCE_INJECT_GET(reg) \ |
60 | static ssize_t edac_inject_##reg##_show(struct kobject *kobj, \ | 42 | static int inj_##reg##_get(void *data, u64 *val) \ |
61 | struct edac_mce_attr *attr, \ | ||
62 | char *buf) \ | ||
63 | { \ | 43 | { \ |
64 | return sprintf(buf, "0x%016llx\n", i_mce.reg); \ | 44 | struct mce *m = (struct mce *)data; \ |
45 | \ | ||
46 | *val = m->reg; \ | ||
47 | return 0; \ | ||
65 | } | 48 | } |
66 | 49 | ||
67 | MCE_INJECT_SHOW(status); | 50 | MCE_INJECT_GET(status); |
68 | MCE_INJECT_SHOW(misc); | 51 | MCE_INJECT_GET(misc); |
69 | MCE_INJECT_SHOW(addr); | 52 | MCE_INJECT_GET(addr); |
70 | 53 | ||
71 | EDAC_MCE_ATTR(status, 0644, edac_inject_status_show, edac_inject_status_store); | 54 | DEFINE_SIMPLE_ATTRIBUTE(status_fops, inj_status_get, inj_status_set, "%llx\n"); |
72 | EDAC_MCE_ATTR(misc, 0644, edac_inject_misc_show, edac_inject_misc_store); | 55 | DEFINE_SIMPLE_ATTRIBUTE(misc_fops, inj_misc_get, inj_misc_set, "%llx\n"); |
73 | EDAC_MCE_ATTR(addr, 0644, edac_inject_addr_show, edac_inject_addr_store); | 56 | DEFINE_SIMPLE_ATTRIBUTE(addr_fops, inj_addr_get, inj_addr_set, "%llx\n"); |
74 | 57 | ||
75 | /* | 58 | /* |
76 | * This denotes into which bank we're injecting and triggers | 59 | * Caller needs to be make sure this cpu doesn't disappear |
77 | * the injection, at the same time. | 60 | * from under us, i.e.: get_cpu/put_cpu. |
78 | */ | 61 | */ |
79 | static ssize_t edac_inject_bank_store(struct kobject *kobj, | 62 | static int toggle_hw_mce_inject(unsigned int cpu, bool enable) |
80 | struct edac_mce_attr *attr, | ||
81 | const char *data, size_t count) | ||
82 | { | 63 | { |
83 | int ret = 0; | 64 | u32 l, h; |
84 | unsigned long value; | 65 | int err; |
85 | 66 | ||
86 | ret = kstrtoul(data, 10, &value); | 67 | err = rdmsr_on_cpu(cpu, MSR_K7_HWCR, &l, &h); |
87 | if (ret < 0) { | 68 | if (err) { |
88 | printk(KERN_ERR "Invalid bank value!\n"); | 69 | pr_err("%s: error reading HWCR\n", __func__); |
89 | return -EINVAL; | 70 | return err; |
90 | } | 71 | } |
91 | 72 | ||
92 | if (value > 5) | 73 | enable ? (l |= BIT(18)) : (l &= ~BIT(18)); |
93 | if (boot_cpu_data.x86 != 0x15 || value > 6) { | ||
94 | printk(KERN_ERR "Non-existent MCE bank: %lu\n", value); | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | 74 | ||
98 | i_mce.bank = value; | 75 | err = wrmsr_on_cpu(cpu, MSR_K7_HWCR, l, h); |
76 | if (err) | ||
77 | pr_err("%s: error writing HWCR\n", __func__); | ||
99 | 78 | ||
100 | amd_decode_mce(NULL, 0, &i_mce); | 79 | return err; |
80 | } | ||
101 | 81 | ||
102 | return count; | 82 | static int flags_get(void *data, u64 *val) |
83 | { | ||
84 | struct mce *m = (struct mce *)data; | ||
85 | |||
86 | *val = m->inject_flags; | ||
87 | |||
88 | return 0; | ||
103 | } | 89 | } |
104 | 90 | ||
105 | static ssize_t edac_inject_bank_show(struct kobject *kobj, | 91 | static int flags_set(void *data, u64 val) |
106 | struct edac_mce_attr *attr, char *buf) | ||
107 | { | 92 | { |
108 | return sprintf(buf, "%d\n", i_mce.bank); | 93 | struct mce *m = (struct mce *)data; |
94 | |||
95 | m->inject_flags = (u8)val; | ||
96 | return 0; | ||
109 | } | 97 | } |
110 | 98 | ||
111 | EDAC_MCE_ATTR(bank, 0644, edac_inject_bank_show, edac_inject_bank_store); | 99 | DEFINE_SIMPLE_ATTRIBUTE(flags_fops, flags_get, flags_set, "%llu\n"); |
112 | 100 | ||
113 | static struct edac_mce_attr *sysfs_attrs[] = { &mce_attr_status, &mce_attr_misc, | 101 | /* |
114 | &mce_attr_addr, &mce_attr_bank | 102 | * On which CPU to inject? |
115 | }; | 103 | */ |
104 | MCE_INJECT_GET(extcpu); | ||
116 | 105 | ||
117 | static int __init edac_init_mce_inject(void) | 106 | static int inj_extcpu_set(void *data, u64 val) |
118 | { | 107 | { |
119 | struct bus_type *edac_subsys = NULL; | 108 | struct mce *m = (struct mce *)data; |
120 | int i, err = 0; | ||
121 | 109 | ||
122 | edac_subsys = edac_get_sysfs_subsys(); | 110 | if (val >= nr_cpu_ids || !cpu_online(val)) { |
123 | if (!edac_subsys) | 111 | pr_err("%s: Invalid CPU: %llu\n", __func__, val); |
124 | return -EINVAL; | 112 | return -EINVAL; |
113 | } | ||
114 | m->extcpu = val; | ||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n"); | ||
125 | 119 | ||
126 | mce_kobj = kobject_create_and_add("mce", &edac_subsys->dev_root->kobj); | 120 | static void trigger_mce(void *info) |
127 | if (!mce_kobj) { | 121 | { |
128 | printk(KERN_ERR "Error creating a mce kset.\n"); | 122 | asm volatile("int $18"); |
129 | err = -ENOMEM; | 123 | } |
130 | goto err_mce_kobj; | 124 | |
125 | static void do_inject(void) | ||
126 | { | ||
127 | u64 mcg_status = 0; | ||
128 | unsigned int cpu = i_mce.extcpu; | ||
129 | u8 b = i_mce.bank; | ||
130 | |||
131 | if (!(i_mce.inject_flags & MCJ_EXCEPTION)) { | ||
132 | amd_decode_mce(NULL, 0, &i_mce); | ||
133 | return; | ||
131 | } | 134 | } |
132 | 135 | ||
133 | for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) { | 136 | get_online_cpus(); |
134 | err = sysfs_create_file(mce_kobj, &sysfs_attrs[i]->attr); | 137 | if (!cpu_online(cpu)) |
135 | if (err) { | 138 | goto err; |
136 | printk(KERN_ERR "Error creating %s in sysfs.\n", | 139 | |
137 | sysfs_attrs[i]->attr.name); | 140 | /* prep MCE global settings for the injection */ |
138 | goto err_sysfs_create; | 141 | mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV; |
142 | |||
143 | if (!(i_mce.status & MCI_STATUS_PCC)) | ||
144 | mcg_status |= MCG_STATUS_RIPV; | ||
145 | |||
146 | toggle_hw_mce_inject(cpu, true); | ||
147 | |||
148 | wrmsr_on_cpu(cpu, MSR_IA32_MCG_STATUS, | ||
149 | (u32)mcg_status, (u32)(mcg_status >> 32)); | ||
150 | |||
151 | wrmsr_on_cpu(cpu, MSR_IA32_MCx_STATUS(b), | ||
152 | (u32)i_mce.status, (u32)(i_mce.status >> 32)); | ||
153 | |||
154 | wrmsr_on_cpu(cpu, MSR_IA32_MCx_ADDR(b), | ||
155 | (u32)i_mce.addr, (u32)(i_mce.addr >> 32)); | ||
156 | |||
157 | wrmsr_on_cpu(cpu, MSR_IA32_MCx_MISC(b), | ||
158 | (u32)i_mce.misc, (u32)(i_mce.misc >> 32)); | ||
159 | |||
160 | toggle_hw_mce_inject(cpu, false); | ||
161 | |||
162 | smp_call_function_single(cpu, trigger_mce, NULL, 0); | ||
163 | |||
164 | err: | ||
165 | put_online_cpus(); | ||
166 | |||
167 | } | ||
168 | |||
169 | /* | ||
170 | * This denotes into which bank we're injecting and triggers | ||
171 | * the injection, at the same time. | ||
172 | */ | ||
173 | static int inj_bank_set(void *data, u64 val) | ||
174 | { | ||
175 | struct mce *m = (struct mce *)data; | ||
176 | |||
177 | if (val > 5) { | ||
178 | if (boot_cpu_data.x86 != 0x15 || val > 6) { | ||
179 | pr_err("Non-existent MCE bank: %llu\n", val); | ||
180 | return -EINVAL; | ||
139 | } | 181 | } |
140 | } | 182 | } |
141 | return 0; | ||
142 | 183 | ||
143 | err_sysfs_create: | 184 | m->bank = val; |
144 | while (--i >= 0) | 185 | do_inject(); |
145 | sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr); | ||
146 | 186 | ||
147 | kobject_del(mce_kobj); | 187 | return 0; |
188 | } | ||
148 | 189 | ||
149 | err_mce_kobj: | 190 | static int inj_bank_get(void *data, u64 *val) |
150 | edac_put_sysfs_subsys(); | 191 | { |
192 | struct mce *m = (struct mce *)data; | ||
151 | 193 | ||
152 | return err; | 194 | *val = m->bank; |
195 | return 0; | ||
153 | } | 196 | } |
154 | 197 | ||
155 | static void __exit edac_exit_mce_inject(void) | 198 | DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n"); |
199 | |||
200 | struct dfs_node { | ||
201 | char *name; | ||
202 | struct dentry *d; | ||
203 | const struct file_operations *fops; | ||
204 | } dfs_fls[] = { | ||
205 | { .name = "status", .fops = &status_fops }, | ||
206 | { .name = "misc", .fops = &misc_fops }, | ||
207 | { .name = "addr", .fops = &addr_fops }, | ||
208 | { .name = "bank", .fops = &bank_fops }, | ||
209 | { .name = "flags", .fops = &flags_fops }, | ||
210 | { .name = "cpu", .fops = &extcpu_fops }, | ||
211 | }; | ||
212 | |||
213 | static int __init init_mce_inject(void) | ||
156 | { | 214 | { |
157 | int i; | 215 | int i; |
158 | 216 | ||
159 | for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) | 217 | dfs_inj = debugfs_create_dir("mce-inject", NULL); |
160 | sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr); | 218 | if (!dfs_inj) |
219 | return -EINVAL; | ||
220 | |||
221 | for (i = 0; i < ARRAY_SIZE(dfs_fls); i++) { | ||
222 | dfs_fls[i].d = debugfs_create_file(dfs_fls[i].name, | ||
223 | S_IRUSR | S_IWUSR, | ||
224 | dfs_inj, | ||
225 | &i_mce, | ||
226 | dfs_fls[i].fops); | ||
227 | |||
228 | if (!dfs_fls[i].d) | ||
229 | goto err_dfs_add; | ||
230 | } | ||
231 | |||
232 | return 0; | ||
233 | |||
234 | err_dfs_add: | ||
235 | while (--i >= 0) | ||
236 | debugfs_remove(dfs_fls[i].d); | ||
161 | 237 | ||
162 | kobject_del(mce_kobj); | 238 | debugfs_remove(dfs_inj); |
239 | dfs_inj = NULL; | ||
163 | 240 | ||
164 | edac_put_sysfs_subsys(); | 241 | return -ENOMEM; |
165 | } | 242 | } |
166 | 243 | ||
167 | module_init(edac_init_mce_inject); | 244 | static void __exit exit_mce_inject(void) |
168 | module_exit(edac_exit_mce_inject); | 245 | { |
246 | int i; | ||
247 | |||
248 | for (i = 0; i < ARRAY_SIZE(dfs_fls); i++) | ||
249 | debugfs_remove(dfs_fls[i].d); | ||
250 | |||
251 | memset(&dfs_fls, 0, sizeof(dfs_fls)); | ||
252 | |||
253 | debugfs_remove(dfs_inj); | ||
254 | dfs_inj = NULL; | ||
255 | } | ||
256 | module_init(init_mce_inject); | ||
257 | module_exit(exit_mce_inject); | ||
169 | 258 | ||
170 | MODULE_LICENSE("GPL"); | 259 | MODULE_LICENSE("GPL"); |
171 | MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>"); | 260 | MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>"); |
172 | MODULE_AUTHOR("AMD Inc."); | 261 | MODULE_AUTHOR("AMD Inc."); |
173 | MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding"); | 262 | MODULE_DESCRIPTION("MCE injection facility for RAS testing"); |
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c index 542fad70e360..6366e880f978 100644 --- a/drivers/edac/mv64x60_edac.c +++ b/drivers/edac/mv64x60_edac.c | |||
@@ -178,7 +178,7 @@ static int mv64x60_pci_err_probe(struct platform_device *pdev) | |||
178 | res = devm_request_irq(&pdev->dev, | 178 | res = devm_request_irq(&pdev->dev, |
179 | pdata->irq, | 179 | pdata->irq, |
180 | mv64x60_pci_isr, | 180 | mv64x60_pci_isr, |
181 | IRQF_DISABLED, | 181 | 0, |
182 | "[EDAC] PCI err", | 182 | "[EDAC] PCI err", |
183 | pci); | 183 | pci); |
184 | if (res < 0) { | 184 | if (res < 0) { |
@@ -345,7 +345,7 @@ static int mv64x60_sram_err_probe(struct platform_device *pdev) | |||
345 | res = devm_request_irq(&pdev->dev, | 345 | res = devm_request_irq(&pdev->dev, |
346 | pdata->irq, | 346 | pdata->irq, |
347 | mv64x60_sram_isr, | 347 | mv64x60_sram_isr, |
348 | IRQF_DISABLED, | 348 | 0, |
349 | "[EDAC] SRAM err", | 349 | "[EDAC] SRAM err", |
350 | edac_dev); | 350 | edac_dev); |
351 | if (res < 0) { | 351 | if (res < 0) { |
@@ -540,7 +540,7 @@ static int mv64x60_cpu_err_probe(struct platform_device *pdev) | |||
540 | res = devm_request_irq(&pdev->dev, | 540 | res = devm_request_irq(&pdev->dev, |
541 | pdata->irq, | 541 | pdata->irq, |
542 | mv64x60_cpu_isr, | 542 | mv64x60_cpu_isr, |
543 | IRQF_DISABLED, | 543 | 0, |
544 | "[EDAC] CPU err", | 544 | "[EDAC] CPU err", |
545 | edac_dev); | 545 | edac_dev); |
546 | if (res < 0) { | 546 | if (res < 0) { |
@@ -800,7 +800,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev) | |||
800 | res = devm_request_irq(&pdev->dev, | 800 | res = devm_request_irq(&pdev->dev, |
801 | pdata->irq, | 801 | pdata->irq, |
802 | mv64x60_mc_isr, | 802 | mv64x60_mc_isr, |
803 | IRQF_DISABLED, | 803 | 0, |
804 | "[EDAC] MC err", | 804 | "[EDAC] MC err", |
805 | mci); | 805 | mci); |
806 | if (res < 0) { | 806 | if (res < 0) { |
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c index 0f04d5ead521..41593539cec4 100644 --- a/drivers/edac/ppc4xx_edac.c +++ b/drivers/edac/ppc4xx_edac.c | |||
@@ -1120,7 +1120,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op, | |||
1120 | 1120 | ||
1121 | status = request_irq(ded_irq, | 1121 | status = request_irq(ded_irq, |
1122 | ppc4xx_edac_isr, | 1122 | ppc4xx_edac_isr, |
1123 | IRQF_DISABLED, | 1123 | 0, |
1124 | "[EDAC] MC ECCDED", | 1124 | "[EDAC] MC ECCDED", |
1125 | mci); | 1125 | mci); |
1126 | 1126 | ||
@@ -1134,7 +1134,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op, | |||
1134 | 1134 | ||
1135 | status = request_irq(sec_irq, | 1135 | status = request_irq(sec_irq, |
1136 | ppc4xx_edac_isr, | 1136 | ppc4xx_edac_isr, |
1137 | IRQF_DISABLED, | 1137 | 0, |
1138 | "[EDAC] MC ECCSEC", | 1138 | "[EDAC] MC ECCSEC", |
1139 | mci); | 1139 | mci); |
1140 | 1140 | ||
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c index e644b52c287c..7c5cdc62f31c 100644 --- a/drivers/edac/x38_edac.c +++ b/drivers/edac/x38_edac.c | |||
@@ -500,8 +500,7 @@ fail1: | |||
500 | pci_unregister_driver(&x38_driver); | 500 | pci_unregister_driver(&x38_driver); |
501 | 501 | ||
502 | fail0: | 502 | fail0: |
503 | if (mci_pdev) | 503 | pci_dev_put(mci_pdev); |
504 | pci_dev_put(mci_pdev); | ||
505 | 504 | ||
506 | return pci_rc; | 505 | return pci_rc; |
507 | } | 506 | } |