diff options
author | Aristeu Rozanski <arozansk@redhat.com> | 2013-10-30 12:27:06 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <m.chehab@samsung.com> | 2013-11-14 14:13:22 -0500 |
commit | 4d715a805b6dd8989cac57b70066bfec0ae413ed (patch) | |
tree | 45461d4f36d50f090f7f8d32255ca36602d03c18 /drivers/edac | |
parent | be3036d220c9f9350c9da92e9b4e66855cf90889 (diff) |
sb_edac: add support for Ivy Bridge
Since Ivy Bridge memory controller is very similar to Sandy Bridge, it's
wiser to modify sb_edac to support both instead of creating another
driver.
[m.chehab@samsung.com: Fix CodingStyle]
Signed-off-by: Aristeu Rozanski <arozansk@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/sb_edac.c | 446 |
1 files changed, 376 insertions, 70 deletions
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c index 90a62ffda626..a290f562949c 100644 --- a/drivers/edac/sb_edac.c +++ b/drivers/edac/sb_edac.c | |||
@@ -34,7 +34,7 @@ static int probed; | |||
34 | /* | 34 | /* |
35 | * Alter this version for the module when modifications are made | 35 | * Alter this version for the module when modifications are made |
36 | */ | 36 | */ |
37 | #define SBRIDGE_REVISION " Ver: 1.0.0 " | 37 | #define SBRIDGE_REVISION " Ver: 1.1.0 " |
38 | #define EDAC_MOD_STR "sbridge_edac" | 38 | #define EDAC_MOD_STR "sbridge_edac" |
39 | 39 | ||
40 | /* | 40 | /* |
@@ -88,6 +88,13 @@ static const u32 sbridge_dram_rule[] = { | |||
88 | 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, | 88 | 0xa8, 0xb0, 0xb8, 0xc0, 0xc8, |
89 | }; | 89 | }; |
90 | 90 | ||
91 | static const u32 ibridge_dram_rule[] = { | ||
92 | 0x60, 0x68, 0x70, 0x78, 0x80, | ||
93 | 0x88, 0x90, 0x98, 0xa0, 0xa8, | ||
94 | 0xb0, 0xb8, 0xc0, 0xc8, 0xd0, | ||
95 | 0xd8, 0xe0, 0xe8, 0xf0, 0xf8, | ||
96 | }; | ||
97 | |||
91 | #define SAD_LIMIT(reg) ((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff) | 98 | #define SAD_LIMIT(reg) ((GET_BITFIELD(reg, 6, 25) << 26) | 0x3ffffff) |
92 | #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) | 99 | #define DRAM_ATTR(reg) GET_BITFIELD(reg, 2, 3) |
93 | #define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1) | 100 | #define INTERLEAVE_MODE(reg) GET_BITFIELD(reg, 1, 1) |
@@ -112,6 +119,13 @@ static const u32 sbridge_interleave_list[] = { | |||
112 | 0xac, 0xb4, 0xbc, 0xc4, 0xcc, | 119 | 0xac, 0xb4, 0xbc, 0xc4, 0xcc, |
113 | }; | 120 | }; |
114 | 121 | ||
122 | static const u32 ibridge_interleave_list[] = { | ||
123 | 0x64, 0x6c, 0x74, 0x7c, 0x84, | ||
124 | 0x8c, 0x94, 0x9c, 0xa4, 0xac, | ||
125 | 0xb4, 0xbc, 0xc4, 0xcc, 0xd4, | ||
126 | 0xdc, 0xe4, 0xec, 0xf4, 0xfc, | ||
127 | }; | ||
128 | |||
115 | struct interleave_pkg { | 129 | struct interleave_pkg { |
116 | unsigned char start; | 130 | unsigned char start; |
117 | unsigned char end; | 131 | unsigned char end; |
@@ -128,6 +142,17 @@ static const struct interleave_pkg sbridge_interleave_pkg[] = { | |||
128 | { 27, 29 }, | 142 | { 27, 29 }, |
129 | }; | 143 | }; |
130 | 144 | ||
145 | static const struct interleave_pkg ibridge_interleave_pkg[] = { | ||
146 | { 0, 3 }, | ||
147 | { 4, 7 }, | ||
148 | { 8, 11 }, | ||
149 | { 12, 15 }, | ||
150 | { 16, 19 }, | ||
151 | { 20, 23 }, | ||
152 | { 24, 27 }, | ||
153 | { 28, 31 }, | ||
154 | }; | ||
155 | |||
131 | static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, | 156 | static inline int sad_pkg(const struct interleave_pkg *table, u32 reg, |
132 | int interleave) | 157 | int interleave) |
133 | { | 158 | { |
@@ -252,6 +277,8 @@ static const u32 correrrthrsld[] = { | |||
252 | 277 | ||
253 | #define SB_RANK_CFG_A 0x0328 | 278 | #define SB_RANK_CFG_A 0x0328 |
254 | 279 | ||
280 | #define IB_RANK_CFG_A 0x0320 | ||
281 | |||
255 | #define IS_RDIMM_ENABLED(reg) GET_BITFIELD(reg, 11, 11) | 282 | #define IS_RDIMM_ENABLED(reg) GET_BITFIELD(reg, 11, 11) |
256 | 283 | ||
257 | /* | 284 | /* |
@@ -261,8 +288,14 @@ static const u32 correrrthrsld[] = { | |||
261 | #define NUM_CHANNELS 4 | 288 | #define NUM_CHANNELS 4 |
262 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ | 289 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ |
263 | 290 | ||
291 | enum type { | ||
292 | SANDY_BRIDGE, | ||
293 | IVY_BRIDGE, | ||
294 | }; | ||
295 | |||
264 | struct sbridge_pvt; | 296 | struct sbridge_pvt; |
265 | struct sbridge_info { | 297 | struct sbridge_info { |
298 | enum type type; | ||
266 | u32 mcmtr; | 299 | u32 mcmtr; |
267 | u32 rankcfgr; | 300 | u32 rankcfgr; |
268 | u64 (*get_tolm)(struct sbridge_pvt *pvt); | 301 | u64 (*get_tolm)(struct sbridge_pvt *pvt); |
@@ -302,8 +335,9 @@ struct sbridge_dev { | |||
302 | 335 | ||
303 | struct sbridge_pvt { | 336 | struct sbridge_pvt { |
304 | struct pci_dev *pci_ta, *pci_ddrio, *pci_ras; | 337 | struct pci_dev *pci_ta, *pci_ddrio, *pci_ras; |
305 | struct pci_dev *pci_sad0, *pci_sad1, *pci_ha0; | 338 | struct pci_dev *pci_sad0, *pci_sad1; |
306 | struct pci_dev *pci_br0; | 339 | struct pci_dev *pci_ha0, *pci_ha1; |
340 | struct pci_dev *pci_br0, *pci_br1; | ||
307 | struct pci_dev *pci_tad[NUM_CHANNELS]; | 341 | struct pci_dev *pci_tad[NUM_CHANNELS]; |
308 | 342 | ||
309 | struct sbridge_dev *sbridge_dev; | 343 | struct sbridge_dev *sbridge_dev; |
@@ -361,11 +395,75 @@ static const struct pci_id_table pci_dev_descr_sbridge_table[] = { | |||
361 | {0,} /* 0 terminated list. */ | 395 | {0,} /* 0 terminated list. */ |
362 | }; | 396 | }; |
363 | 397 | ||
398 | /* This changes depending if 1HA or 2HA: | ||
399 | * 1HA: | ||
400 | * 0x0eb8 (17.0) is DDRIO0 | ||
401 | * 2HA: | ||
402 | * 0x0ebc (17.4) is DDRIO0 | ||
403 | */ | ||
404 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0 0x0eb8 | ||
405 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0 0x0ebc | ||
406 | |||
407 | /* pci ids */ | ||
408 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0 0x0ea0 | ||
409 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA 0x0ea8 | ||
410 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS 0x0e71 | ||
411 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0 0x0eaa | ||
412 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1 0x0eab | ||
413 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2 0x0eac | ||
414 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3 0x0ead | ||
415 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_SAD 0x0ec8 | ||
416 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_BR0 0x0ec9 | ||
417 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_BR1 0x0eca | ||
418 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1 0x0e60 | ||
419 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA 0x0e68 | ||
420 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS 0x0e79 | ||
421 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0 0x0e6a | ||
422 | #define PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1 0x0e6b | ||
423 | |||
424 | static const struct pci_id_descr pci_dev_descr_ibridge[] = { | ||
425 | /* Processor Home Agent */ | ||
426 | { PCI_DESCR(14, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0, 0) }, | ||
427 | |||
428 | /* Memory controller */ | ||
429 | { PCI_DESCR(15, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA, 0) }, | ||
430 | { PCI_DESCR(15, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_RAS, 0) }, | ||
431 | { PCI_DESCR(15, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD0, 0) }, | ||
432 | { PCI_DESCR(15, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD1, 0) }, | ||
433 | { PCI_DESCR(15, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD2, 0) }, | ||
434 | { PCI_DESCR(15, 5, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TAD3, 0) }, | ||
435 | |||
436 | /* System Address Decoder */ | ||
437 | { PCI_DESCR(22, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_SAD, 0) }, | ||
438 | |||
439 | /* Broadcast Registers */ | ||
440 | { PCI_DESCR(22, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_BR0, 1) }, | ||
441 | { PCI_DESCR(22, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_BR1, 0) }, | ||
442 | |||
443 | /* Optional, mode 2HA */ | ||
444 | { PCI_DESCR(28, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, 1) }, | ||
445 | #if 0 | ||
446 | { PCI_DESCR(29, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TA, 1) }, | ||
447 | { PCI_DESCR(29, 1, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_RAS, 1) }, | ||
448 | #endif | ||
449 | { PCI_DESCR(29, 2, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD0, 1) }, | ||
450 | { PCI_DESCR(29, 3, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1_TAD1, 1) }, | ||
451 | |||
452 | { PCI_DESCR(17, 0, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_1HA_DDRIO0, 1) }, | ||
453 | { PCI_DESCR(17, 4, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_2HA_DDRIO0, 1) }, | ||
454 | }; | ||
455 | |||
456 | static const struct pci_id_table pci_dev_descr_ibridge_table[] = { | ||
457 | PCI_ID_TABLE_ENTRY(pci_dev_descr_ibridge), | ||
458 | {0,} /* 0 terminated list. */ | ||
459 | }; | ||
460 | |||
364 | /* | 461 | /* |
365 | * pci_device_id table for which devices we are looking for | 462 | * pci_device_id table for which devices we are looking for |
366 | */ | 463 | */ |
367 | static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = { | 464 | static DEFINE_PCI_DEVICE_TABLE(sbridge_pci_tbl) = { |
368 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, | 465 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA)}, |
466 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)}, | ||
369 | {0,} /* 0 terminated list. */ | 467 | {0,} /* 0 terminated list. */ |
370 | }; | 468 | }; |
371 | 469 | ||
@@ -472,6 +570,35 @@ static u64 sbridge_get_tohm(struct sbridge_pvt *pvt) | |||
472 | return GET_TOHM(reg); | 570 | return GET_TOHM(reg); |
473 | } | 571 | } |
474 | 572 | ||
573 | static u64 ibridge_get_tolm(struct sbridge_pvt *pvt) | ||
574 | { | ||
575 | u32 reg; | ||
576 | |||
577 | pci_read_config_dword(pvt->pci_br1, TOLM, ®); | ||
578 | |||
579 | return GET_TOLM(reg); | ||
580 | } | ||
581 | |||
582 | static u64 ibridge_get_tohm(struct sbridge_pvt *pvt) | ||
583 | { | ||
584 | u32 reg; | ||
585 | |||
586 | pci_read_config_dword(pvt->pci_br1, TOHM, ®); | ||
587 | |||
588 | return GET_TOHM(reg); | ||
589 | } | ||
590 | |||
591 | static inline u8 sad_pkg_socket(u8 pkg) | ||
592 | { | ||
593 | /* on Ivy Bridge, nodeID is SASS, where A is HA and S is node id */ | ||
594 | return (pkg >> 3) | (pkg & 0x3); | ||
595 | } | ||
596 | |||
597 | static inline u8 sad_pkg_ha(u8 pkg) | ||
598 | { | ||
599 | return (pkg >> 2) & 0x1; | ||
600 | } | ||
601 | |||
475 | /**************************************************************************** | 602 | /**************************************************************************** |
476 | Memory check routines | 603 | Memory check routines |
477 | ****************************************************************************/ | 604 | ****************************************************************************/ |
@@ -534,8 +661,6 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
534 | enum edac_type mode; | 661 | enum edac_type mode; |
535 | enum mem_type mtype; | 662 | enum mem_type mtype; |
536 | 663 | ||
537 | pvt->info.rankcfgr = SB_RANK_CFG_A; | ||
538 | |||
539 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); | 664 | pci_read_config_dword(pvt->pci_br0, SAD_TARGET, ®); |
540 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); | 665 | pvt->sbridge_dev->source_id = SOURCE_ID(reg); |
541 | 666 | ||
@@ -810,12 +935,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
810 | { | 935 | { |
811 | struct mem_ctl_info *new_mci; | 936 | struct mem_ctl_info *new_mci; |
812 | struct sbridge_pvt *pvt = mci->pvt_info; | 937 | struct sbridge_pvt *pvt = mci->pvt_info; |
938 | struct pci_dev *pci_ha; | ||
813 | int n_rir, n_sads, n_tads, sad_way, sck_xch; | 939 | int n_rir, n_sads, n_tads, sad_way, sck_xch; |
814 | int sad_interl, idx, base_ch; | 940 | int sad_interl, idx, base_ch; |
815 | int interleave_mode; | 941 | int interleave_mode; |
816 | unsigned sad_interleave[pvt->info.max_interleave]; | 942 | unsigned sad_interleave[pvt->info.max_interleave]; |
817 | u32 reg; | 943 | u32 reg; |
818 | u8 ch_way,sck_way; | 944 | u8 ch_way, sck_way, pkg, sad_ha = 0; |
819 | u32 tad_offset; | 945 | u32 tad_offset; |
820 | u32 rir_way; | 946 | u32 rir_way; |
821 | u32 mb, kb; | 947 | u32 mb, kb; |
@@ -866,45 +992,56 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
866 | 992 | ||
867 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], | 993 | pci_read_config_dword(pvt->pci_sad0, pvt->info.interleave_list[n_sads], |
868 | ®); | 994 | ®); |
869 | sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0); | 995 | |
870 | for (sad_way = 0; sad_way < 8; sad_way++) { | 996 | if (pvt->info.type == SANDY_BRIDGE) { |
871 | u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way); | 997 | sad_interl = sad_pkg(pvt->info.interleave_pkg, reg, 0); |
872 | if (sad_way > 0 && sad_interl == pkg) | 998 | for (sad_way = 0; sad_way < 8; sad_way++) { |
999 | u32 pkg = sad_pkg(pvt->info.interleave_pkg, reg, sad_way); | ||
1000 | if (sad_way > 0 && sad_interl == pkg) | ||
1001 | break; | ||
1002 | sad_interleave[sad_way] = pkg; | ||
1003 | edac_dbg(0, "SAD interleave #%d: %d\n", | ||
1004 | sad_way, sad_interleave[sad_way]); | ||
1005 | } | ||
1006 | edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n", | ||
1007 | pvt->sbridge_dev->mc, | ||
1008 | n_sads, | ||
1009 | addr, | ||
1010 | limit, | ||
1011 | sad_way + 7, | ||
1012 | !interleave_mode ? "" : "XOR[18:16]"); | ||
1013 | if (interleave_mode) | ||
1014 | idx = ((addr >> 6) ^ (addr >> 16)) & 7; | ||
1015 | else | ||
1016 | idx = (addr >> 6) & 7; | ||
1017 | switch (sad_way) { | ||
1018 | case 1: | ||
1019 | idx = 0; | ||
873 | break; | 1020 | break; |
874 | sad_interleave[sad_way] = pkg; | 1021 | case 2: |
875 | edac_dbg(0, "SAD interleave #%d: %d\n", | 1022 | idx = idx & 1; |
876 | sad_way, sad_interleave[sad_way]); | 1023 | break; |
877 | } | 1024 | case 4: |
878 | edac_dbg(0, "mc#%d: Error detected on SAD#%d: address 0x%016Lx < 0x%016Lx, Interleave [%d:6]%s\n", | 1025 | idx = idx & 3; |
879 | pvt->sbridge_dev->mc, | 1026 | break; |
880 | n_sads, | 1027 | case 8: |
881 | addr, | 1028 | break; |
882 | limit, | 1029 | default: |
883 | sad_way + 7, | 1030 | sprintf(msg, "Can't discover socket interleave"); |
884 | interleave_mode ? "" : "XOR[18:16]"); | 1031 | return -EINVAL; |
885 | if (interleave_mode) | 1032 | } |
886 | idx = ((addr >> 6) ^ (addr >> 16)) & 7; | 1033 | *socket = sad_interleave[idx]; |
887 | else | 1034 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", |
1035 | idx, sad_way, *socket); | ||
1036 | } else { | ||
1037 | /* Ivy Bridge's SAD mode doesn't support XOR interleave mode */ | ||
888 | idx = (addr >> 6) & 7; | 1038 | idx = (addr >> 6) & 7; |
889 | switch (sad_way) { | 1039 | pkg = sad_pkg(pvt->info.interleave_pkg, reg, idx); |
890 | case 1: | 1040 | *socket = sad_pkg_socket(pkg); |
891 | idx = 0; | 1041 | sad_ha = sad_pkg_ha(pkg); |
892 | break; | 1042 | edac_dbg(0, "SAD interleave package: %d = CPU socket %d, HA %d\n", |
893 | case 2: | 1043 | idx, *socket, sad_ha); |
894 | idx = idx & 1; | ||
895 | break; | ||
896 | case 4: | ||
897 | idx = idx & 3; | ||
898 | break; | ||
899 | case 8: | ||
900 | break; | ||
901 | default: | ||
902 | sprintf(msg, "Can't discover socket interleave"); | ||
903 | return -EINVAL; | ||
904 | } | 1044 | } |
905 | *socket = sad_interleave[idx]; | ||
906 | edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n", | ||
907 | idx, sad_way, *socket); | ||
908 | 1045 | ||
909 | /* | 1046 | /* |
910 | * Move to the proper node structure, in order to access the | 1047 | * Move to the proper node structure, in order to access the |
@@ -923,9 +1060,16 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
923 | * Step 2) Get memory channel | 1060 | * Step 2) Get memory channel |
924 | */ | 1061 | */ |
925 | prv = 0; | 1062 | prv = 0; |
1063 | if (pvt->info.type == SANDY_BRIDGE) | ||
1064 | pci_ha = pvt->pci_ha0; | ||
1065 | else { | ||
1066 | if (sad_ha) | ||
1067 | pci_ha = pvt->pci_ha1; | ||
1068 | else | ||
1069 | pci_ha = pvt->pci_ha0; | ||
1070 | } | ||
926 | for (n_tads = 0; n_tads < MAX_TAD; n_tads++) { | 1071 | for (n_tads = 0; n_tads < MAX_TAD; n_tads++) { |
927 | pci_read_config_dword(pvt->pci_ha0, tad_dram_rule[n_tads], | 1072 | pci_read_config_dword(pci_ha, tad_dram_rule[n_tads], ®); |
928 | ®); | ||
929 | limit = TAD_LIMIT(reg); | 1073 | limit = TAD_LIMIT(reg); |
930 | if (limit <= prv) { | 1074 | if (limit <= prv) { |
931 | sprintf(msg, "Can't discover the memory channel"); | 1075 | sprintf(msg, "Can't discover the memory channel"); |
@@ -935,14 +1079,13 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
935 | break; | 1079 | break; |
936 | prv = limit; | 1080 | prv = limit; |
937 | } | 1081 | } |
1082 | if (n_tads == MAX_TAD) { | ||
1083 | sprintf(msg, "Can't discover the memory channel"); | ||
1084 | return -EINVAL; | ||
1085 | } | ||
1086 | |||
938 | ch_way = TAD_CH(reg) + 1; | 1087 | ch_way = TAD_CH(reg) + 1; |
939 | sck_way = TAD_SOCK(reg) + 1; | 1088 | sck_way = TAD_SOCK(reg) + 1; |
940 | /* | ||
941 | * FIXME: Is it right to always use channel 0 for offsets? | ||
942 | */ | ||
943 | pci_read_config_dword(pvt->pci_tad[0], | ||
944 | tad_ch_nilv_offset[n_tads], | ||
945 | &tad_offset); | ||
946 | 1089 | ||
947 | if (ch_way == 3) | 1090 | if (ch_way == 3) |
948 | idx = addr >> 6; | 1091 | idx = addr >> 6; |
@@ -972,6 +1115,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci, | |||
972 | } | 1115 | } |
973 | *channel_mask = 1 << base_ch; | 1116 | *channel_mask = 1 << base_ch; |
974 | 1117 | ||
1118 | pci_read_config_dword(pvt->pci_tad[base_ch], | ||
1119 | tad_ch_nilv_offset[n_tads], | ||
1120 | &tad_offset); | ||
1121 | |||
975 | if (pvt->is_mirrored) { | 1122 | if (pvt->is_mirrored) { |
976 | *channel_mask |= 1 << ((base_ch + 2) % 4); | 1123 | *channel_mask |= 1 << ((base_ch + 2) % 4); |
977 | switch(ch_way) { | 1124 | switch(ch_way) { |
@@ -1347,6 +1494,131 @@ error: | |||
1347 | return -EINVAL; | 1494 | return -EINVAL; |
1348 | } | 1495 | } |
1349 | 1496 | ||
1497 | static int ibridge_mci_bind_devs(struct mem_ctl_info *mci, | ||
1498 | struct sbridge_dev *sbridge_dev) | ||
1499 | { | ||
1500 | struct sbridge_pvt *pvt = mci->pvt_info; | ||
1501 | struct pci_dev *pdev, *tmp; | ||
1502 | int i, func, slot; | ||
1503 | bool mode_2ha = false; | ||
1504 | |||
1505 | tmp = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
1506 | PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA1, NULL); | ||
1507 | if (tmp) { | ||
1508 | mode_2ha = true; | ||
1509 | pci_dev_put(tmp); | ||
1510 | } | ||
1511 | |||
1512 | for (i = 0; i < sbridge_dev->n_devs; i++) { | ||
1513 | pdev = sbridge_dev->pdev[i]; | ||
1514 | if (!pdev) | ||
1515 | continue; | ||
1516 | slot = PCI_SLOT(pdev->devfn); | ||
1517 | func = PCI_FUNC(pdev->devfn); | ||
1518 | |||
1519 | switch (slot) { | ||
1520 | case 14: | ||
1521 | if (func == 0) { | ||
1522 | pvt->pci_ha0 = pdev; | ||
1523 | break; | ||
1524 | } | ||
1525 | goto error; | ||
1526 | case 15: | ||
1527 | switch (func) { | ||
1528 | case 0: | ||
1529 | pvt->pci_ta = pdev; | ||
1530 | break; | ||
1531 | case 1: | ||
1532 | pvt->pci_ras = pdev; | ||
1533 | break; | ||
1534 | case 4: | ||
1535 | case 5: | ||
1536 | /* if we have 2 HAs active, channels 2 and 3 | ||
1537 | * are in other device */ | ||
1538 | if (mode_2ha) | ||
1539 | break; | ||
1540 | /* fall through */ | ||
1541 | case 2: | ||
1542 | case 3: | ||
1543 | pvt->pci_tad[func - 2] = pdev; | ||
1544 | break; | ||
1545 | default: | ||
1546 | goto error; | ||
1547 | } | ||
1548 | break; | ||
1549 | case 17: | ||
1550 | if (func == 4) { | ||
1551 | pvt->pci_ddrio = pdev; | ||
1552 | break; | ||
1553 | } else if (func == 0) { | ||
1554 | if (!mode_2ha) | ||
1555 | pvt->pci_ddrio = pdev; | ||
1556 | break; | ||
1557 | } | ||
1558 | goto error; | ||
1559 | case 22: | ||
1560 | switch (func) { | ||
1561 | case 0: | ||
1562 | pvt->pci_sad0 = pdev; | ||
1563 | break; | ||
1564 | case 1: | ||
1565 | pvt->pci_br0 = pdev; | ||
1566 | break; | ||
1567 | case 2: | ||
1568 | pvt->pci_br1 = pdev; | ||
1569 | break; | ||
1570 | default: | ||
1571 | goto error; | ||
1572 | } | ||
1573 | break; | ||
1574 | case 28: | ||
1575 | if (func == 0) { | ||
1576 | pvt->pci_ha1 = pdev; | ||
1577 | break; | ||
1578 | } | ||
1579 | goto error; | ||
1580 | case 29: | ||
1581 | /* we shouldn't have this device if we have just one | ||
1582 | * HA present */ | ||
1583 | WARN_ON(!mode_2ha); | ||
1584 | if (func == 2 || func == 3) { | ||
1585 | pvt->pci_tad[func] = pdev; | ||
1586 | break; | ||
1587 | } | ||
1588 | goto error; | ||
1589 | default: | ||
1590 | goto error; | ||
1591 | } | ||
1592 | |||
1593 | edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n", | ||
1594 | sbridge_dev->bus, | ||
1595 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
1596 | pdev); | ||
1597 | } | ||
1598 | |||
1599 | /* Check if everything were registered */ | ||
1600 | if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_br0 || | ||
1601 | !pvt->pci_br1 || !pvt->pci_tad || !pvt->pci_ras || | ||
1602 | !pvt->pci_ta) | ||
1603 | goto enodev; | ||
1604 | |||
1605 | for (i = 0; i < NUM_CHANNELS; i++) { | ||
1606 | if (!pvt->pci_tad[i]) | ||
1607 | goto enodev; | ||
1608 | } | ||
1609 | return 0; | ||
1610 | |||
1611 | enodev: | ||
1612 | sbridge_printk(KERN_ERR, "Some needed devices are missing\n"); | ||
1613 | return -ENODEV; | ||
1614 | |||
1615 | error: | ||
1616 | sbridge_printk(KERN_ERR, | ||
1617 | "Device %d, function %d is out of the expected range\n", | ||
1618 | slot, func); | ||
1619 | return -EINVAL; | ||
1620 | } | ||
1621 | |||
1350 | /**************************************************************************** | 1622 | /**************************************************************************** |
1351 | Error check routines | 1623 | Error check routines |
1352 | ****************************************************************************/ | 1624 | ****************************************************************************/ |
@@ -1367,7 +1639,7 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, | |||
1367 | bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0); | 1639 | bool ripv = GET_BITFIELD(m->mcgstatus, 0, 0); |
1368 | bool overflow = GET_BITFIELD(m->status, 62, 62); | 1640 | bool overflow = GET_BITFIELD(m->status, 62, 62); |
1369 | bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); | 1641 | bool uncorrected_error = GET_BITFIELD(m->status, 61, 61); |
1370 | bool recoverable = GET_BITFIELD(m->status, 56, 56); | 1642 | bool recoverable; |
1371 | u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52); | 1643 | u32 core_err_cnt = GET_BITFIELD(m->status, 38, 52); |
1372 | u32 mscod = GET_BITFIELD(m->status, 16, 31); | 1644 | u32 mscod = GET_BITFIELD(m->status, 16, 31); |
1373 | u32 errcode = GET_BITFIELD(m->status, 0, 15); | 1645 | u32 errcode = GET_BITFIELD(m->status, 0, 15); |
@@ -1378,6 +1650,11 @@ static void sbridge_mce_output_error(struct mem_ctl_info *mci, | |||
1378 | int rc, dimm; | 1650 | int rc, dimm; |
1379 | char *area_type = NULL; | 1651 | char *area_type = NULL; |
1380 | 1652 | ||
1653 | if (pvt->info.type == IVY_BRIDGE) | ||
1654 | recoverable = true; | ||
1655 | else | ||
1656 | recoverable = GET_BITFIELD(m->status, 56, 56); | ||
1657 | |||
1381 | if (uncorrected_error) { | 1658 | if (uncorrected_error) { |
1382 | if (ripv) { | 1659 | if (ripv) { |
1383 | type = "FATAL"; | 1660 | type = "FATAL"; |
@@ -1636,11 +1913,12 @@ static void sbridge_unregister_mci(struct sbridge_dev *sbridge_dev) | |||
1636 | sbridge_dev->mci = NULL; | 1913 | sbridge_dev->mci = NULL; |
1637 | } | 1914 | } |
1638 | 1915 | ||
1639 | static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) | 1916 | static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type) |
1640 | { | 1917 | { |
1641 | struct mem_ctl_info *mci; | 1918 | struct mem_ctl_info *mci; |
1642 | struct edac_mc_layer layers[2]; | 1919 | struct edac_mc_layer layers[2]; |
1643 | struct sbridge_pvt *pvt; | 1920 | struct sbridge_pvt *pvt; |
1921 | struct pci_dev *pdev = sbridge_dev->pdev[0]; | ||
1644 | int rc; | 1922 | int rc; |
1645 | 1923 | ||
1646 | /* Check the number of active and not disabled channels */ | 1924 | /* Check the number of active and not disabled channels */ |
@@ -1662,7 +1940,7 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) | |||
1662 | return -ENOMEM; | 1940 | return -ENOMEM; |
1663 | 1941 | ||
1664 | edac_dbg(0, "MC: mci = %p, dev = %p\n", | 1942 | edac_dbg(0, "MC: mci = %p, dev = %p\n", |
1665 | mci, &sbridge_dev->pdev[0]->dev); | 1943 | mci, &pdev->dev); |
1666 | 1944 | ||
1667 | pvt = mci->pvt_info; | 1945 | pvt = mci->pvt_info; |
1668 | memset(pvt, 0, sizeof(*pvt)); | 1946 | memset(pvt, 0, sizeof(*pvt)); |
@@ -1676,31 +1954,52 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev) | |||
1676 | mci->edac_cap = EDAC_FLAG_NONE; | 1954 | mci->edac_cap = EDAC_FLAG_NONE; |
1677 | mci->mod_name = "sbridge_edac.c"; | 1955 | mci->mod_name = "sbridge_edac.c"; |
1678 | mci->mod_ver = SBRIDGE_REVISION; | 1956 | mci->mod_ver = SBRIDGE_REVISION; |
1679 | mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); | 1957 | mci->dev_name = pci_name(pdev); |
1680 | mci->dev_name = pci_name(sbridge_dev->pdev[0]); | ||
1681 | mci->ctl_page_to_phys = NULL; | 1958 | mci->ctl_page_to_phys = NULL; |
1682 | pvt->info.get_tolm = sbridge_get_tolm; | ||
1683 | pvt->info.get_tohm = sbridge_get_tohm; | ||
1684 | pvt->info.dram_rule = sbridge_dram_rule; | ||
1685 | pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); | ||
1686 | pvt->info.interleave_list = sbridge_interleave_list; | ||
1687 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); | ||
1688 | pvt->info.interleave_pkg = sbridge_interleave_pkg; | ||
1689 | 1959 | ||
1690 | /* Set the function pointer to an actual operation function */ | 1960 | /* Set the function pointer to an actual operation function */ |
1691 | mci->edac_check = sbridge_check_error; | 1961 | mci->edac_check = sbridge_check_error; |
1692 | 1962 | ||
1693 | /* Store pci devices at mci for faster access */ | 1963 | pvt->info.type = type; |
1694 | rc = sbridge_mci_bind_devs(mci, sbridge_dev); | 1964 | if (type == IVY_BRIDGE) { |
1695 | if (unlikely(rc < 0)) | 1965 | pvt->info.rankcfgr = IB_RANK_CFG_A; |
1696 | goto fail0; | 1966 | pvt->info.get_tolm = ibridge_get_tolm; |
1967 | pvt->info.get_tohm = ibridge_get_tohm; | ||
1968 | pvt->info.dram_rule = ibridge_dram_rule; | ||
1969 | pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule); | ||
1970 | pvt->info.interleave_list = ibridge_interleave_list; | ||
1971 | pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list); | ||
1972 | pvt->info.interleave_pkg = ibridge_interleave_pkg; | ||
1973 | mci->ctl_name = kasprintf(GFP_KERNEL, "Ivy Bridge Socket#%d", mci->mc_idx); | ||
1974 | |||
1975 | /* Store pci devices at mci for faster access */ | ||
1976 | rc = ibridge_mci_bind_devs(mci, sbridge_dev); | ||
1977 | if (unlikely(rc < 0)) | ||
1978 | goto fail0; | ||
1979 | } else { | ||
1980 | pvt->info.rankcfgr = SB_RANK_CFG_A; | ||
1981 | pvt->info.get_tolm = sbridge_get_tolm; | ||
1982 | pvt->info.get_tohm = sbridge_get_tohm; | ||
1983 | pvt->info.dram_rule = sbridge_dram_rule; | ||
1984 | pvt->info.max_sad = ARRAY_SIZE(sbridge_dram_rule); | ||
1985 | pvt->info.interleave_list = sbridge_interleave_list; | ||
1986 | pvt->info.max_interleave = ARRAY_SIZE(sbridge_interleave_list); | ||
1987 | pvt->info.interleave_pkg = sbridge_interleave_pkg; | ||
1988 | mci->ctl_name = kasprintf(GFP_KERNEL, "Sandy Bridge Socket#%d", mci->mc_idx); | ||
1989 | |||
1990 | /* Store pci devices at mci for faster access */ | ||
1991 | rc = sbridge_mci_bind_devs(mci, sbridge_dev); | ||
1992 | if (unlikely(rc < 0)) | ||
1993 | goto fail0; | ||
1994 | } | ||
1995 | |||
1697 | 1996 | ||
1698 | /* Get dimm basic config and the memory layout */ | 1997 | /* Get dimm basic config and the memory layout */ |
1699 | get_dimm_config(mci); | 1998 | get_dimm_config(mci); |
1700 | get_memory_layout(mci); | 1999 | get_memory_layout(mci); |
1701 | 2000 | ||
1702 | /* record ptr to the generic device */ | 2001 | /* record ptr to the generic device */ |
1703 | mci->pdev = &sbridge_dev->pdev[0]->dev; | 2002 | mci->pdev = &pdev->dev; |
1704 | 2003 | ||
1705 | /* add this new MC control structure to EDAC's list of MCs */ | 2004 | /* add this new MC control structure to EDAC's list of MCs */ |
1706 | if (unlikely(edac_mc_add_mc(mci))) { | 2005 | if (unlikely(edac_mc_add_mc(mci))) { |
@@ -1731,6 +2030,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1731 | int rc; | 2030 | int rc; |
1732 | u8 mc, num_mc = 0; | 2031 | u8 mc, num_mc = 0; |
1733 | struct sbridge_dev *sbridge_dev; | 2032 | struct sbridge_dev *sbridge_dev; |
2033 | enum type type; | ||
1734 | 2034 | ||
1735 | /* get the pci devices we want to reserve for our use */ | 2035 | /* get the pci devices we want to reserve for our use */ |
1736 | mutex_lock(&sbridge_edac_lock); | 2036 | mutex_lock(&sbridge_edac_lock); |
@@ -1744,7 +2044,13 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1744 | } | 2044 | } |
1745 | probed++; | 2045 | probed++; |
1746 | 2046 | ||
1747 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); | 2047 | if (pdev->device == PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA) { |
2048 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table); | ||
2049 | type = IVY_BRIDGE; | ||
2050 | } else { | ||
2051 | rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table); | ||
2052 | type = SANDY_BRIDGE; | ||
2053 | } | ||
1748 | if (unlikely(rc < 0)) | 2054 | if (unlikely(rc < 0)) |
1749 | goto fail0; | 2055 | goto fail0; |
1750 | mc = 0; | 2056 | mc = 0; |
@@ -1753,7 +2059,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id) | |||
1753 | edac_dbg(0, "Registering MC#%d (%d of %d)\n", | 2059 | edac_dbg(0, "Registering MC#%d (%d of %d)\n", |
1754 | mc, mc + 1, num_mc); | 2060 | mc, mc + 1, num_mc); |
1755 | sbridge_dev->mc = mc++; | 2061 | sbridge_dev->mc = mc++; |
1756 | rc = sbridge_register_mci(sbridge_dev); | 2062 | rc = sbridge_register_mci(sbridge_dev, type); |
1757 | if (unlikely(rc < 0)) | 2063 | if (unlikely(rc < 0)) |
1758 | goto fail1; | 2064 | goto fail1; |
1759 | } | 2065 | } |
@@ -1868,5 +2174,5 @@ MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI"); | |||
1868 | MODULE_LICENSE("GPL"); | 2174 | MODULE_LICENSE("GPL"); |
1869 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); | 2175 | MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>"); |
1870 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); | 2176 | MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)"); |
1871 | MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge memory controllers - " | 2177 | MODULE_DESCRIPTION("MC Driver for Intel Sandy Bridge and Ivy Bridge memory controllers - " |
1872 | SBRIDGE_REVISION); | 2178 | SBRIDGE_REVISION); |