diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-09-05 01:35:08 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-10 10:44:58 -0400 |
commit | f47429494fd50c0b7396fe3f8a26ea638b47c5ba (patch) | |
tree | cb951ca0a07f97f19205b9e593b4343662867cbe /drivers/edac | |
parent | 66607706cee7b6901aa0509198f075859c93ec6a (diff) |
i7core_edac: create one mc per socket/QPI
Instead of creating just one memory controller, create one per socket
(e. g. per Quick Link Path Interconnect).
This better reflects the Nehalem architecture.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/i7core_edac.c | 507 |
1 files changed, 228 insertions, 279 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 7bcb5993b501..5bc316b8e805 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c | |||
@@ -29,11 +29,21 @@ | |||
29 | #include <linux/mmzone.h> | 29 | #include <linux/mmzone.h> |
30 | #include <linux/edac_mce.h> | 30 | #include <linux/edac_mce.h> |
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | #include <linux/smp.h> | ||
32 | #include <asm/processor.h> | 33 | #include <asm/processor.h> |
33 | 34 | ||
34 | #include "edac_core.h" | 35 | #include "edac_core.h" |
35 | 36 | ||
36 | /* | 37 | /* |
38 | * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core | ||
39 | * registers start at bus 255, and are not reported by BIOS. | ||
40 | * We currently find devices with only 2 sockets. In order to support more QPI | ||
41 | * Quick Path Interconnect, just increment this number. | ||
42 | */ | ||
43 | #define MAX_SOCKET_BUSES 2 | ||
44 | |||
45 | |||
46 | /* | ||
37 | * Alter this version for the module when modifications are made | 47 | * Alter this version for the module when modifications are made |
38 | */ | 48 | */ |
39 | #define I7CORE_REVISION " Ver: 1.0.0 " __DATE__ | 49 | #define I7CORE_REVISION " Ver: 1.0.0 " __DATE__ |
@@ -162,7 +172,6 @@ | |||
162 | 172 | ||
163 | #define NUM_CHANS 3 | 173 | #define NUM_CHANS 3 |
164 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ | 174 | #define MAX_DIMMS 3 /* Max DIMMS per channel */ |
165 | #define NUM_SOCKETS 2 /* Max number of MC sockets */ | ||
166 | #define MAX_MCR_FUNC 4 | 175 | #define MAX_MCR_FUNC 4 |
167 | #define MAX_CHAN_FUNC 3 | 176 | #define MAX_CHAN_FUNC 3 |
168 | 177 | ||
@@ -177,7 +186,6 @@ struct i7core_info { | |||
177 | struct i7core_inject { | 186 | struct i7core_inject { |
178 | int enable; | 187 | int enable; |
179 | 188 | ||
180 | u8 socket; | ||
181 | u32 section; | 189 | u32 section; |
182 | u32 type; | 190 | u32 type; |
183 | u32 eccmask; | 191 | u32 eccmask; |
@@ -197,29 +205,37 @@ struct pci_id_descr { | |||
197 | int dev_id; | 205 | int dev_id; |
198 | }; | 206 | }; |
199 | 207 | ||
208 | struct i7core_dev { | ||
209 | struct list_head list; | ||
210 | u8 socket; | ||
211 | struct pci_dev **pdev; | ||
212 | struct mem_ctl_info *mci; | ||
213 | }; | ||
214 | |||
200 | struct i7core_pvt { | 215 | struct i7core_pvt { |
201 | struct pci_dev *pci_noncore[NUM_SOCKETS]; | 216 | struct pci_dev *pci_noncore; |
202 | struct pci_dev *pci_mcr[NUM_SOCKETS][MAX_MCR_FUNC + 1]; | 217 | struct pci_dev *pci_mcr[MAX_MCR_FUNC + 1]; |
203 | struct pci_dev *pci_ch[NUM_SOCKETS][NUM_CHANS][MAX_CHAN_FUNC + 1]; | 218 | struct pci_dev *pci_ch[NUM_CHANS][MAX_CHAN_FUNC + 1]; |
219 | |||
220 | struct i7core_dev *i7core_dev; | ||
204 | 221 | ||
205 | struct i7core_info info; | 222 | struct i7core_info info; |
206 | struct i7core_inject inject; | 223 | struct i7core_inject inject; |
207 | struct i7core_channel channel[NUM_SOCKETS][NUM_CHANS]; | 224 | struct i7core_channel channel[NUM_CHANS]; |
208 | 225 | ||
209 | int sockets; /* Number of sockets */ | 226 | int channels; /* Number of active channels */ |
210 | int channels; /* Number of active channels */ | ||
211 | 227 | ||
212 | int ce_count_available[NUM_SOCKETS]; | 228 | int ce_count_available; |
213 | int csrow_map[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; | 229 | int csrow_map[NUM_CHANS][MAX_DIMMS]; |
214 | 230 | ||
215 | /* ECC corrected errors counts per udimm */ | 231 | /* ECC corrected errors counts per udimm */ |
216 | unsigned long udimm_ce_count[NUM_SOCKETS][MAX_DIMMS]; | 232 | unsigned long udimm_ce_count[MAX_DIMMS]; |
217 | int udimm_last_ce_count[NUM_SOCKETS][MAX_DIMMS]; | 233 | int udimm_last_ce_count[MAX_DIMMS]; |
218 | /* ECC corrected errors counts per rdimm */ | 234 | /* ECC corrected errors counts per rdimm */ |
219 | unsigned long rdimm_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; | 235 | unsigned long rdimm_ce_count[NUM_CHANS][MAX_DIMMS]; |
220 | int rdimm_last_ce_count[NUM_SOCKETS][NUM_CHANS][MAX_DIMMS]; | 236 | int rdimm_last_ce_count[NUM_CHANS][MAX_DIMMS]; |
221 | 237 | ||
222 | unsigned int is_registered[NUM_SOCKETS]; | 238 | unsigned int is_registered; |
223 | 239 | ||
224 | /* mcelog glue */ | 240 | /* mcelog glue */ |
225 | struct edac_mce edac_mce; | 241 | struct edac_mce edac_mce; |
@@ -228,22 +244,10 @@ struct i7core_pvt { | |||
228 | spinlock_t mce_lock; | 244 | spinlock_t mce_lock; |
229 | }; | 245 | }; |
230 | 246 | ||
231 | struct i7core_dev { | ||
232 | struct list_head list; | ||
233 | |||
234 | int socket; | ||
235 | struct pci_dev **pdev; | ||
236 | }; | ||
237 | |||
238 | /* Static vars */ | 247 | /* Static vars */ |
239 | static LIST_HEAD(i7core_edac_list); | 248 | static LIST_HEAD(i7core_edac_list); |
240 | static DEFINE_MUTEX(i7core_edac_lock); | 249 | static DEFINE_MUTEX(i7core_edac_lock); |
241 | 250 | static u8 max_num_sockets; | |
242 | /* Device name and register DID (Device ID) */ | ||
243 | struct i7core_dev_info { | ||
244 | const char *ctl_name; /* name for this device */ | ||
245 | u16 fsb_mapping_errors; /* DID for the branchmap,control */ | ||
246 | }; | ||
247 | 251 | ||
248 | #define PCI_DESCR(device, function, device_id) \ | 252 | #define PCI_DESCR(device, function, device_id) \ |
249 | .dev = (device), \ | 253 | .dev = (device), \ |
@@ -295,15 +299,6 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { | |||
295 | {0,} /* 0 terminated list. */ | 299 | {0,} /* 0 terminated list. */ |
296 | }; | 300 | }; |
297 | 301 | ||
298 | |||
299 | /* Table of devices attributes supported by this driver */ | ||
300 | static const struct i7core_dev_info i7core_probe_devs[] = { | ||
301 | { | ||
302 | .ctl_name = "i7 Core", | ||
303 | .fsb_mapping_errors = PCI_DEVICE_ID_INTEL_I7_MCR, | ||
304 | }, | ||
305 | }; | ||
306 | |||
307 | static struct edac_pci_ctl_info *i7core_pci; | 302 | static struct edac_pci_ctl_info *i7core_pci; |
308 | 303 | ||
309 | /**************************************************************************** | 304 | /**************************************************************************** |
@@ -356,7 +351,7 @@ static inline int numcol(u32 col) | |||
356 | return cols[col & 0x3]; | 351 | return cols[col & 0x3]; |
357 | } | 352 | } |
358 | 353 | ||
359 | static struct i7core_dev *get_i7core_dev(int socket) | 354 | static struct i7core_dev *get_i7core_dev(u8 socket) |
360 | { | 355 | { |
361 | struct i7core_dev *i7core_dev; | 356 | struct i7core_dev *i7core_dev; |
362 | 357 | ||
@@ -471,18 +466,19 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, | |||
471 | return 0; | 466 | return 0; |
472 | } | 467 | } |
473 | 468 | ||
474 | static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) | 469 | static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) |
475 | { | 470 | { |
476 | struct i7core_pvt *pvt = mci->pvt_info; | 471 | struct i7core_pvt *pvt = mci->pvt_info; |
477 | struct csrow_info *csr; | 472 | struct csrow_info *csr; |
478 | struct pci_dev *pdev; | 473 | struct pci_dev *pdev; |
479 | int i, j; | 474 | int i, j; |
475 | u8 socket = pvt->i7core_dev->socket; | ||
480 | unsigned long last_page = 0; | 476 | unsigned long last_page = 0; |
481 | enum edac_type mode; | 477 | enum edac_type mode; |
482 | enum mem_type mtype; | 478 | enum mem_type mtype; |
483 | 479 | ||
484 | /* Get data from the MC register, function 0 */ | 480 | /* Get data from the MC register, function 0 */ |
485 | pdev = pvt->pci_mcr[socket][0]; | 481 | pdev = pvt->pci_mcr[0]; |
486 | if (!pdev) | 482 | if (!pdev) |
487 | return -ENODEV; | 483 | return -ENODEV; |
488 | 484 | ||
@@ -529,10 +525,10 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) | |||
529 | } | 525 | } |
530 | 526 | ||
531 | /* Devices 4-6 function 0 */ | 527 | /* Devices 4-6 function 0 */ |
532 | pci_read_config_dword(pvt->pci_ch[socket][i][0], | 528 | pci_read_config_dword(pvt->pci_ch[i][0], |
533 | MC_CHANNEL_DIMM_INIT_PARAMS, &data); | 529 | MC_CHANNEL_DIMM_INIT_PARAMS, &data); |
534 | 530 | ||
535 | pvt->channel[socket][i].ranks = (data & QUAD_RANK_PRESENT) ? | 531 | pvt->channel[i].ranks = (data & QUAD_RANK_PRESENT) ? |
536 | 4 : 2; | 532 | 4 : 2; |
537 | 533 | ||
538 | if (data & REGISTERED_DIMM) | 534 | if (data & REGISTERED_DIMM) |
@@ -549,11 +545,11 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) | |||
549 | #endif | 545 | #endif |
550 | 546 | ||
551 | /* Devices 4-6 function 1 */ | 547 | /* Devices 4-6 function 1 */ |
552 | pci_read_config_dword(pvt->pci_ch[socket][i][1], | 548 | pci_read_config_dword(pvt->pci_ch[i][1], |
553 | MC_DOD_CH_DIMM0, &dimm_dod[0]); | 549 | MC_DOD_CH_DIMM0, &dimm_dod[0]); |
554 | pci_read_config_dword(pvt->pci_ch[socket][i][1], | 550 | pci_read_config_dword(pvt->pci_ch[i][1], |
555 | MC_DOD_CH_DIMM1, &dimm_dod[1]); | 551 | MC_DOD_CH_DIMM1, &dimm_dod[1]); |
556 | pci_read_config_dword(pvt->pci_ch[socket][i][1], | 552 | pci_read_config_dword(pvt->pci_ch[i][1], |
557 | MC_DOD_CH_DIMM2, &dimm_dod[2]); | 553 | MC_DOD_CH_DIMM2, &dimm_dod[2]); |
558 | 554 | ||
559 | debugf0("Ch%d phy rd%d, wr%d (0x%08x): " | 555 | debugf0("Ch%d phy rd%d, wr%d (0x%08x): " |
@@ -561,7 +557,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) | |||
561 | i, | 557 | i, |
562 | RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), | 558 | RDLCH(pvt->info.ch_map, i), WRLCH(pvt->info.ch_map, i), |
563 | data, | 559 | data, |
564 | pvt->channel[socket][i].ranks, | 560 | pvt->channel[i].ranks, |
565 | (data & REGISTERED_DIMM) ? 'R' : 'U'); | 561 | (data & REGISTERED_DIMM) ? 'R' : 'U'); |
566 | 562 | ||
567 | for (j = 0; j < 3; j++) { | 563 | for (j = 0; j < 3; j++) { |
@@ -579,7 +575,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) | |||
579 | /* DDR3 has 8 I/O banks */ | 575 | /* DDR3 has 8 I/O banks */ |
580 | size = (rows * cols * banks * ranks) >> (20 - 3); | 576 | size = (rows * cols * banks * ranks) >> (20 - 3); |
581 | 577 | ||
582 | pvt->channel[socket][i].dimms++; | 578 | pvt->channel[i].dimms++; |
583 | 579 | ||
584 | debugf0("\tdimm %d %d Mb offset: %x, " | 580 | debugf0("\tdimm %d %d Mb offset: %x, " |
585 | "bank: %d, rank: %d, row: %#x, col: %#x\n", | 581 | "bank: %d, rank: %d, row: %#x, col: %#x\n", |
@@ -607,7 +603,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow, u8 socket) | |||
607 | csr->channels[0].chan_idx = i; | 603 | csr->channels[0].chan_idx = i; |
608 | csr->channels[0].ce_count = 0; | 604 | csr->channels[0].ce_count = 0; |
609 | 605 | ||
610 | pvt->csrow_map[socket][i][j] = *csrow; | 606 | pvt->csrow_map[i][j] = *csrow; |
611 | 607 | ||
612 | switch (banks) { | 608 | switch (banks) { |
613 | case 4: | 609 | case 4: |
@@ -665,43 +661,16 @@ static int disable_inject(struct mem_ctl_info *mci) | |||
665 | 661 | ||
666 | pvt->inject.enable = 0; | 662 | pvt->inject.enable = 0; |
667 | 663 | ||
668 | if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) | 664 | if (!pvt->pci_ch[pvt->inject.channel][0]) |
669 | return -ENODEV; | 665 | return -ENODEV; |
670 | 666 | ||
671 | pci_write_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], | 667 | pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], |
672 | MC_CHANNEL_ERROR_INJECT, 0); | 668 | MC_CHANNEL_ERROR_INJECT, 0); |
673 | 669 | ||
674 | return 0; | 670 | return 0; |
675 | } | 671 | } |
676 | 672 | ||
677 | /* | 673 | /* |
678 | * i7core inject inject.socket | ||
679 | * | ||
680 | * accept and store error injection inject.socket value | ||
681 | */ | ||
682 | static ssize_t i7core_inject_socket_store(struct mem_ctl_info *mci, | ||
683 | const char *data, size_t count) | ||
684 | { | ||
685 | struct i7core_pvt *pvt = mci->pvt_info; | ||
686 | unsigned long value; | ||
687 | int rc; | ||
688 | |||
689 | rc = strict_strtoul(data, 10, &value); | ||
690 | if ((rc < 0) || (value >= pvt->sockets)) | ||
691 | return -EIO; | ||
692 | |||
693 | pvt->inject.socket = (u32) value; | ||
694 | return count; | ||
695 | } | ||
696 | |||
697 | static ssize_t i7core_inject_socket_show(struct mem_ctl_info *mci, | ||
698 | char *data) | ||
699 | { | ||
700 | struct i7core_pvt *pvt = mci->pvt_info; | ||
701 | return sprintf(data, "%d\n", pvt->inject.socket); | ||
702 | } | ||
703 | |||
704 | /* | ||
705 | * i7core inject inject.section | 674 | * i7core inject inject.section |
706 | * | 675 | * |
707 | * accept and store error injection inject.section value | 676 | * accept and store error injection inject.section value |
@@ -965,7 +934,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, | |||
965 | int rc; | 934 | int rc; |
966 | long enable; | 935 | long enable; |
967 | 936 | ||
968 | if (!pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0]) | 937 | if (!pvt->pci_ch[pvt->inject.channel][0]) |
969 | return 0; | 938 | return 0; |
970 | 939 | ||
971 | rc = strict_strtoul(data, 10, &enable); | 940 | rc = strict_strtoul(data, 10, &enable); |
@@ -983,7 +952,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, | |||
983 | if (pvt->inject.dimm < 0) | 952 | if (pvt->inject.dimm < 0) |
984 | mask |= 1L << 41; | 953 | mask |= 1L << 41; |
985 | else { | 954 | else { |
986 | if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) | 955 | if (pvt->channel[pvt->inject.channel].dimms > 2) |
987 | mask |= (pvt->inject.dimm & 0x3L) << 35; | 956 | mask |= (pvt->inject.dimm & 0x3L) << 35; |
988 | else | 957 | else |
989 | mask |= (pvt->inject.dimm & 0x1L) << 36; | 958 | mask |= (pvt->inject.dimm & 0x1L) << 36; |
@@ -993,7 +962,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, | |||
993 | if (pvt->inject.rank < 0) | 962 | if (pvt->inject.rank < 0) |
994 | mask |= 1L << 40; | 963 | mask |= 1L << 40; |
995 | else { | 964 | else { |
996 | if (pvt->channel[pvt->inject.socket][pvt->inject.channel].dimms > 2) | 965 | if (pvt->channel[pvt->inject.channel].dimms > 2) |
997 | mask |= (pvt->inject.rank & 0x1L) << 34; | 966 | mask |= (pvt->inject.rank & 0x1L) << 34; |
998 | else | 967 | else |
999 | mask |= (pvt->inject.rank & 0x3L) << 34; | 968 | mask |= (pvt->inject.rank & 0x3L) << 34; |
@@ -1029,18 +998,18 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, | |||
1029 | (pvt->inject.type & 0x6) << (3 - 1); | 998 | (pvt->inject.type & 0x6) << (3 - 1); |
1030 | 999 | ||
1031 | /* Unlock writes to registers - this register is write only */ | 1000 | /* Unlock writes to registers - this register is write only */ |
1032 | pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], | 1001 | pci_write_config_dword(pvt->pci_noncore, |
1033 | MC_CFG_CONTROL, 0x2); | 1002 | MC_CFG_CONTROL, 0x2); |
1034 | 1003 | ||
1035 | write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], | 1004 | write_and_test(pvt->pci_ch[pvt->inject.channel][0], |
1036 | MC_CHANNEL_ADDR_MATCH, mask); | 1005 | MC_CHANNEL_ADDR_MATCH, mask); |
1037 | write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], | 1006 | write_and_test(pvt->pci_ch[pvt->inject.channel][0], |
1038 | MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); | 1007 | MC_CHANNEL_ADDR_MATCH + 4, mask >> 32L); |
1039 | 1008 | ||
1040 | write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], | 1009 | write_and_test(pvt->pci_ch[pvt->inject.channel][0], |
1041 | MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); | 1010 | MC_CHANNEL_ERROR_MASK, pvt->inject.eccmask); |
1042 | 1011 | ||
1043 | write_and_test(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], | 1012 | write_and_test(pvt->pci_ch[pvt->inject.channel][0], |
1044 | MC_CHANNEL_ERROR_INJECT, injectmask); | 1013 | MC_CHANNEL_ERROR_INJECT, injectmask); |
1045 | 1014 | ||
1046 | /* | 1015 | /* |
@@ -1048,7 +1017,7 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, | |||
1048 | * Without writing 8 to this register, errors aren't injected. Not sure | 1017 | * Without writing 8 to this register, errors aren't injected. Not sure |
1049 | * why. | 1018 | * why. |
1050 | */ | 1019 | */ |
1051 | pci_write_config_dword(pvt->pci_noncore[pvt->inject.socket], | 1020 | pci_write_config_dword(pvt->pci_noncore, |
1052 | MC_CFG_CONTROL, 8); | 1021 | MC_CFG_CONTROL, 8); |
1053 | 1022 | ||
1054 | debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," | 1023 | debugf0("Error inject addr match 0x%016llx, ecc 0x%08x," |
@@ -1065,7 +1034,7 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, | |||
1065 | struct i7core_pvt *pvt = mci->pvt_info; | 1034 | struct i7core_pvt *pvt = mci->pvt_info; |
1066 | u32 injectmask; | 1035 | u32 injectmask; |
1067 | 1036 | ||
1068 | pci_read_config_dword(pvt->pci_ch[pvt->inject.socket][pvt->inject.channel][0], | 1037 | pci_read_config_dword(pvt->pci_ch[pvt->inject.channel][0], |
1069 | MC_CHANNEL_ERROR_INJECT, &injectmask); | 1038 | MC_CHANNEL_ERROR_INJECT, &injectmask); |
1070 | 1039 | ||
1071 | debugf0("Inject error read: 0x%018x\n", injectmask); | 1040 | debugf0("Inject error read: 0x%018x\n", injectmask); |
@@ -1078,34 +1047,30 @@ static ssize_t i7core_inject_enable_show(struct mem_ctl_info *mci, | |||
1078 | 1047 | ||
1079 | static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) | 1048 | static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) |
1080 | { | 1049 | { |
1081 | unsigned i, j, count, total = 0; | 1050 | unsigned i, count, total = 0; |
1082 | struct i7core_pvt *pvt = mci->pvt_info; | 1051 | struct i7core_pvt *pvt = mci->pvt_info; |
1083 | 1052 | ||
1084 | for (i = 0; i < pvt->sockets; i++) { | 1053 | if (!pvt->ce_count_available) { |
1085 | if (!pvt->ce_count_available[i]) { | 1054 | count = sprintf(data, "data unavailable\n"); |
1086 | count = sprintf(data, "socket 0 data unavailable\n"); | 1055 | return 0; |
1087 | continue; | ||
1088 | } | ||
1089 | if (!pvt->is_registered[i]) | ||
1090 | count = sprintf(data, "socket %d, dimm0: %lu\n" | ||
1091 | "dimm1: %lu\ndimm2: %lu\n", | ||
1092 | i, | ||
1093 | pvt->udimm_ce_count[i][0], | ||
1094 | pvt->udimm_ce_count[i][1], | ||
1095 | pvt->udimm_ce_count[i][2]); | ||
1096 | else | ||
1097 | for (j = 0; j < NUM_CHANS; j++) { | ||
1098 | count = sprintf(data, "socket %d, channel %d " | ||
1099 | "RDIMM0: %lu " | ||
1100 | "RDIMM1: %lu RDIMM2: %lu\n", | ||
1101 | i, j, | ||
1102 | pvt->rdimm_ce_count[i][j][0], | ||
1103 | pvt->rdimm_ce_count[i][j][1], | ||
1104 | pvt->rdimm_ce_count[i][j][2]); | ||
1105 | } | ||
1106 | data += count; | ||
1107 | total += count; | ||
1108 | } | 1056 | } |
1057 | if (!pvt->is_registered) | ||
1058 | count = sprintf(data, "all channels " | ||
1059 | "UDIMM0: %lu UDIMM1: %lu UDIMM2: %lu\n", | ||
1060 | pvt->udimm_ce_count[0], | ||
1061 | pvt->udimm_ce_count[1], | ||
1062 | pvt->udimm_ce_count[2]); | ||
1063 | else | ||
1064 | for (i = 0; i < NUM_CHANS; i++) { | ||
1065 | count = sprintf(data, "channel %d RDIMM0: %lu " | ||
1066 | "RDIMM1: %lu RDIMM2: %lu\n", | ||
1067 | i, | ||
1068 | pvt->rdimm_ce_count[i][0], | ||
1069 | pvt->rdimm_ce_count[i][1], | ||
1070 | pvt->rdimm_ce_count[i][2]); | ||
1071 | } | ||
1072 | data += count; | ||
1073 | total += count; | ||
1109 | 1074 | ||
1110 | return total; | 1075 | return total; |
1111 | } | 1076 | } |
@@ -1116,13 +1081,6 @@ static ssize_t i7core_ce_regs_show(struct mem_ctl_info *mci, char *data) | |||
1116 | static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { | 1081 | static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { |
1117 | { | 1082 | { |
1118 | .attr = { | 1083 | .attr = { |
1119 | .name = "inject_socket", | ||
1120 | .mode = (S_IRUGO | S_IWUSR) | ||
1121 | }, | ||
1122 | .show = i7core_inject_socket_show, | ||
1123 | .store = i7core_inject_socket_store, | ||
1124 | }, { | ||
1125 | .attr = { | ||
1126 | .name = "inject_section", | 1084 | .name = "inject_section", |
1127 | .mode = (S_IRUGO | S_IWUSR) | 1085 | .mode = (S_IRUGO | S_IWUSR) |
1128 | }, | 1086 | }, |
@@ -1178,7 +1136,7 @@ static void i7core_put_devices(void) | |||
1178 | { | 1136 | { |
1179 | int i, j; | 1137 | int i, j; |
1180 | 1138 | ||
1181 | for (i = 0; i < NUM_SOCKETS; i++) { | 1139 | for (i = 0; i < max_num_sockets; i++) { |
1182 | struct i7core_dev *i7core_dev = get_i7core_dev(i); | 1140 | struct i7core_dev *i7core_dev = get_i7core_dev(i); |
1183 | if (!i7core_dev) | 1141 | if (!i7core_dev) |
1184 | continue; | 1142 | continue; |
@@ -1204,7 +1162,7 @@ static void i7core_xeon_pci_fixup(void) | |||
1204 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1162 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1205 | pci_dev_descr[0].dev_id, NULL); | 1163 | pci_dev_descr[0].dev_id, NULL); |
1206 | if (unlikely(!pdev)) { | 1164 | if (unlikely(!pdev)) { |
1207 | for (i = 0; i < NUM_SOCKETS; i ++) | 1165 | for (i = 0; i < MAX_SOCKET_BUSES; i++) |
1208 | pcibios_scan_specific_bus(255-i); | 1166 | pcibios_scan_specific_bus(255-i); |
1209 | } | 1167 | } |
1210 | } | 1168 | } |
@@ -1323,13 +1281,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno) | |||
1323 | return 0; | 1281 | return 0; |
1324 | } | 1282 | } |
1325 | 1283 | ||
1326 | static int i7core_get_devices(u8 *sockets) | 1284 | static int i7core_get_devices(void) |
1327 | { | 1285 | { |
1328 | int i; | 1286 | int i; |
1329 | struct pci_dev *pdev = NULL; | 1287 | struct pci_dev *pdev = NULL; |
1330 | struct i7core_dev *i7core_dev = NULL; | ||
1331 | 1288 | ||
1332 | *sockets = 0; | ||
1333 | for (i = 0; i < N_DEVS; i++) { | 1289 | for (i = 0; i < N_DEVS; i++) { |
1334 | pdev = NULL; | 1290 | pdev = NULL; |
1335 | do { | 1291 | do { |
@@ -1340,55 +1296,48 @@ static int i7core_get_devices(u8 *sockets) | |||
1340 | } while (pdev); | 1296 | } while (pdev); |
1341 | } | 1297 | } |
1342 | 1298 | ||
1343 | list_for_each_entry(i7core_dev, &i7core_edac_list, list) { | ||
1344 | if (i7core_dev->socket + 1 > *sockets) | ||
1345 | *sockets = i7core_dev->socket + 1; | ||
1346 | } | ||
1347 | |||
1348 | return 0; | 1299 | return 0; |
1349 | } | 1300 | } |
1350 | 1301 | ||
1351 | static int mci_bind_devs(struct mem_ctl_info *mci) | 1302 | static int mci_bind_devs(struct mem_ctl_info *mci, |
1303 | struct i7core_dev *i7core_dev) | ||
1352 | { | 1304 | { |
1353 | struct i7core_pvt *pvt = mci->pvt_info; | 1305 | struct i7core_pvt *pvt = mci->pvt_info; |
1354 | struct pci_dev *pdev; | 1306 | struct pci_dev *pdev; |
1355 | int i, j, func, slot; | 1307 | int i, func, slot; |
1356 | 1308 | ||
1357 | for (i = 0; i < pvt->sockets; i++) { | 1309 | /* Associates i7core_dev and mci for future usage */ |
1358 | struct i7core_dev *i7core_dev = get_i7core_dev(i); | 1310 | pvt->i7core_dev = i7core_dev; |
1311 | i7core_dev->mci = mci; | ||
1359 | 1312 | ||
1360 | if (!i7core_dev) | 1313 | pvt->is_registered = 0; |
1314 | for (i = 0; i < N_DEVS; i++) { | ||
1315 | pdev = i7core_dev->pdev[i]; | ||
1316 | if (!pdev) | ||
1361 | continue; | 1317 | continue; |
1362 | 1318 | ||
1363 | pvt->is_registered[i] = 0; | 1319 | func = PCI_FUNC(pdev->devfn); |
1364 | for (j = 0; j < N_DEVS; j++) { | 1320 | slot = PCI_SLOT(pdev->devfn); |
1365 | pdev = i7core_dev->pdev[j]; | 1321 | if (slot == 3) { |
1366 | if (!pdev) | 1322 | if (unlikely(func > MAX_MCR_FUNC)) |
1367 | continue; | 1323 | goto error; |
1368 | 1324 | pvt->pci_mcr[func] = pdev; | |
1369 | func = PCI_FUNC(pdev->devfn); | 1325 | } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { |
1370 | slot = PCI_SLOT(pdev->devfn); | 1326 | if (unlikely(func > MAX_CHAN_FUNC)) |
1371 | if (slot == 3) { | ||
1372 | if (unlikely(func > MAX_MCR_FUNC)) | ||
1373 | goto error; | ||
1374 | pvt->pci_mcr[i][func] = pdev; | ||
1375 | } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { | ||
1376 | if (unlikely(func > MAX_CHAN_FUNC)) | ||
1377 | goto error; | ||
1378 | pvt->pci_ch[i][slot - 4][func] = pdev; | ||
1379 | } else if (!slot && !func) | ||
1380 | pvt->pci_noncore[i] = pdev; | ||
1381 | else | ||
1382 | goto error; | 1327 | goto error; |
1328 | pvt->pci_ch[slot - 4][func] = pdev; | ||
1329 | } else if (!slot && !func) | ||
1330 | pvt->pci_noncore = pdev; | ||
1331 | else | ||
1332 | goto error; | ||
1383 | 1333 | ||
1384 | debugf0("Associated fn %d.%d, dev = %p, socket %d\n", | 1334 | debugf0("Associated fn %d.%d, dev = %p, socket %d\n", |
1385 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | 1335 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), |
1386 | pdev, i); | 1336 | pdev, i7core_dev->socket); |
1387 | 1337 | ||
1388 | if (PCI_SLOT(pdev->devfn) == 3 && | 1338 | if (PCI_SLOT(pdev->devfn) == 3 && |
1389 | PCI_FUNC(pdev->devfn) == 2) | 1339 | PCI_FUNC(pdev->devfn) == 2) |
1390 | pvt->is_registered[i] = 1; | 1340 | pvt->is_registered = 1; |
1391 | } | ||
1392 | } | 1341 | } |
1393 | 1342 | ||
1394 | return 0; | 1343 | return 0; |
@@ -1403,17 +1352,17 @@ error: | |||
1403 | /**************************************************************************** | 1352 | /**************************************************************************** |
1404 | Error check routines | 1353 | Error check routines |
1405 | ****************************************************************************/ | 1354 | ****************************************************************************/ |
1406 | static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, | 1355 | static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, |
1407 | int chan, int dimm, int add) | 1356 | int chan, int dimm, int add) |
1408 | { | 1357 | { |
1409 | char *msg; | 1358 | char *msg; |
1410 | struct i7core_pvt *pvt = mci->pvt_info; | 1359 | struct i7core_pvt *pvt = mci->pvt_info; |
1411 | int row = pvt->csrow_map[socket][chan][dimm], i; | 1360 | int row = pvt->csrow_map[chan][dimm], i; |
1412 | 1361 | ||
1413 | for (i = 0; i < add; i++) { | 1362 | for (i = 0; i < add; i++) { |
1414 | msg = kasprintf(GFP_KERNEL, "Corrected error " | 1363 | msg = kasprintf(GFP_KERNEL, "Corrected error " |
1415 | "(Socket=%d channel=%d dimm=%d", | 1364 | "(Socket=%d channel=%d dimm=%d)", |
1416 | socket, chan, dimm); | 1365 | pvt->i7core_dev->socket, chan, dimm); |
1417 | 1366 | ||
1418 | edac_mc_handle_fbd_ce(mci, row, 0, msg); | 1367 | edac_mc_handle_fbd_ce(mci, row, 0, msg); |
1419 | kfree (msg); | 1368 | kfree (msg); |
@@ -1421,71 +1370,71 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, int socket, | |||
1421 | } | 1370 | } |
1422 | 1371 | ||
1423 | static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, | 1372 | static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, |
1424 | int socket, int chan, int new0, int new1, int new2) | 1373 | int chan, int new0, int new1, int new2) |
1425 | { | 1374 | { |
1426 | struct i7core_pvt *pvt = mci->pvt_info; | 1375 | struct i7core_pvt *pvt = mci->pvt_info; |
1427 | int add0 = 0, add1 = 0, add2 = 0; | 1376 | int add0 = 0, add1 = 0, add2 = 0; |
1428 | /* Updates CE counters if it is not the first time here */ | 1377 | /* Updates CE counters if it is not the first time here */ |
1429 | if (pvt->ce_count_available[socket]) { | 1378 | if (pvt->ce_count_available) { |
1430 | /* Updates CE counters */ | 1379 | /* Updates CE counters */ |
1431 | 1380 | ||
1432 | add2 = new2 - pvt->rdimm_last_ce_count[socket][chan][2]; | 1381 | add2 = new2 - pvt->rdimm_last_ce_count[chan][2]; |
1433 | add1 = new1 - pvt->rdimm_last_ce_count[socket][chan][1]; | 1382 | add1 = new1 - pvt->rdimm_last_ce_count[chan][1]; |
1434 | add0 = new0 - pvt->rdimm_last_ce_count[socket][chan][0]; | 1383 | add0 = new0 - pvt->rdimm_last_ce_count[chan][0]; |
1435 | 1384 | ||
1436 | if (add2 < 0) | 1385 | if (add2 < 0) |
1437 | add2 += 0x7fff; | 1386 | add2 += 0x7fff; |
1438 | pvt->rdimm_ce_count[socket][chan][2] += add2; | 1387 | pvt->rdimm_ce_count[chan][2] += add2; |
1439 | 1388 | ||
1440 | if (add1 < 0) | 1389 | if (add1 < 0) |
1441 | add1 += 0x7fff; | 1390 | add1 += 0x7fff; |
1442 | pvt->rdimm_ce_count[socket][chan][1] += add1; | 1391 | pvt->rdimm_ce_count[chan][1] += add1; |
1443 | 1392 | ||
1444 | if (add0 < 0) | 1393 | if (add0 < 0) |
1445 | add0 += 0x7fff; | 1394 | add0 += 0x7fff; |
1446 | pvt->rdimm_ce_count[socket][chan][0] += add0; | 1395 | pvt->rdimm_ce_count[chan][0] += add0; |
1447 | } else | 1396 | } else |
1448 | pvt->ce_count_available[socket] = 1; | 1397 | pvt->ce_count_available = 1; |
1449 | 1398 | ||
1450 | /* Store the new values */ | 1399 | /* Store the new values */ |
1451 | pvt->rdimm_last_ce_count[socket][chan][2] = new2; | 1400 | pvt->rdimm_last_ce_count[chan][2] = new2; |
1452 | pvt->rdimm_last_ce_count[socket][chan][1] = new1; | 1401 | pvt->rdimm_last_ce_count[chan][1] = new1; |
1453 | pvt->rdimm_last_ce_count[socket][chan][0] = new0; | 1402 | pvt->rdimm_last_ce_count[chan][0] = new0; |
1454 | 1403 | ||
1455 | /*updated the edac core */ | 1404 | /*updated the edac core */ |
1456 | if (add0 != 0) | 1405 | if (add0 != 0) |
1457 | i7core_rdimm_update_csrow(mci, socket, chan, 0, add0); | 1406 | i7core_rdimm_update_csrow(mci, chan, 0, add0); |
1458 | if (add1 != 0) | 1407 | if (add1 != 0) |
1459 | i7core_rdimm_update_csrow(mci, socket, chan, 1, add1); | 1408 | i7core_rdimm_update_csrow(mci, chan, 1, add1); |
1460 | if (add2 != 0) | 1409 | if (add2 != 0) |
1461 | i7core_rdimm_update_csrow(mci, socket, chan, 2, add2); | 1410 | i7core_rdimm_update_csrow(mci, chan, 2, add2); |
1462 | 1411 | ||
1463 | } | 1412 | } |
1464 | 1413 | ||
1465 | static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) | 1414 | static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci) |
1466 | { | 1415 | { |
1467 | struct i7core_pvt *pvt = mci->pvt_info; | 1416 | struct i7core_pvt *pvt = mci->pvt_info; |
1468 | u32 rcv[3][2]; | 1417 | u32 rcv[3][2]; |
1469 | int i, new0, new1, new2; | 1418 | int i, new0, new1, new2; |
1470 | 1419 | ||
1471 | /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/ | 1420 | /*Read DEV 3: FUN 2: MC_COR_ECC_CNT regs directly*/ |
1472 | pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_0, | 1421 | pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_0, |
1473 | &rcv[0][0]); | 1422 | &rcv[0][0]); |
1474 | pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_1, | 1423 | pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_1, |
1475 | &rcv[0][1]); | 1424 | &rcv[0][1]); |
1476 | pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_2, | 1425 | pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_2, |
1477 | &rcv[1][0]); | 1426 | &rcv[1][0]); |
1478 | pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_3, | 1427 | pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_3, |
1479 | &rcv[1][1]); | 1428 | &rcv[1][1]); |
1480 | pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_4, | 1429 | pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_4, |
1481 | &rcv[2][0]); | 1430 | &rcv[2][0]); |
1482 | pci_read_config_dword(pvt->pci_mcr[socket][2], MC_COR_ECC_CNT_5, | 1431 | pci_read_config_dword(pvt->pci_mcr[2], MC_COR_ECC_CNT_5, |
1483 | &rcv[2][1]); | 1432 | &rcv[2][1]); |
1484 | for (i = 0 ; i < 3; i++) { | 1433 | for (i = 0 ; i < 3; i++) { |
1485 | debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n", | 1434 | debugf3("MC_COR_ECC_CNT%d = 0x%x; MC_COR_ECC_CNT%d = 0x%x\n", |
1486 | (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]); | 1435 | (i * 2), rcv[i][0], (i * 2) + 1, rcv[i][1]); |
1487 | /*if the channel has 3 dimms*/ | 1436 | /*if the channel has 3 dimms*/ |
1488 | if (pvt->channel[socket][i].dimms > 2) { | 1437 | if (pvt->channel[i].dimms > 2) { |
1489 | new0 = DIMM_BOT_COR_ERR(rcv[i][0]); | 1438 | new0 = DIMM_BOT_COR_ERR(rcv[i][0]); |
1490 | new1 = DIMM_TOP_COR_ERR(rcv[i][0]); | 1439 | new1 = DIMM_TOP_COR_ERR(rcv[i][0]); |
1491 | new2 = DIMM_BOT_COR_ERR(rcv[i][1]); | 1440 | new2 = DIMM_BOT_COR_ERR(rcv[i][1]); |
@@ -1497,7 +1446,7 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) | |||
1497 | new2 = 0; | 1446 | new2 = 0; |
1498 | } | 1447 | } |
1499 | 1448 | ||
1500 | i7core_rdimm_update_ce_count(mci, socket, i, new0, new1, new2); | 1449 | i7core_rdimm_update_ce_count(mci, i, new0, new1, new2); |
1501 | } | 1450 | } |
1502 | } | 1451 | } |
1503 | 1452 | ||
@@ -1507,20 +1456,20 @@ static void i7core_rdimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) | |||
1507 | * also available at: | 1456 | * also available at: |
1508 | * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf | 1457 | * http://www.arrownac.com/manufacturers/intel/s/nehalem/5500-datasheet-v2.pdf |
1509 | */ | 1458 | */ |
1510 | static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) | 1459 | static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci) |
1511 | { | 1460 | { |
1512 | struct i7core_pvt *pvt = mci->pvt_info; | 1461 | struct i7core_pvt *pvt = mci->pvt_info; |
1513 | u32 rcv1, rcv0; | 1462 | u32 rcv1, rcv0; |
1514 | int new0, new1, new2; | 1463 | int new0, new1, new2; |
1515 | 1464 | ||
1516 | if (!pvt->pci_mcr[socket][4]) { | 1465 | if (!pvt->pci_mcr[4]) { |
1517 | debugf0("%s MCR registers not found\n", __func__); | 1466 | debugf0("%s MCR registers not found\n", __func__); |
1518 | return; | 1467 | return; |
1519 | } | 1468 | } |
1520 | 1469 | ||
1521 | /* Corrected test errors */ | 1470 | /* Corrected test errors */ |
1522 | pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV1, &rcv1); | 1471 | pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV1, &rcv1); |
1523 | pci_read_config_dword(pvt->pci_mcr[socket][4], MC_TEST_ERR_RCV0, &rcv0); | 1472 | pci_read_config_dword(pvt->pci_mcr[4], MC_TEST_ERR_RCV0, &rcv0); |
1524 | 1473 | ||
1525 | /* Store the new values */ | 1474 | /* Store the new values */ |
1526 | new2 = DIMM2_COR_ERR(rcv1); | 1475 | new2 = DIMM2_COR_ERR(rcv1); |
@@ -1528,37 +1477,37 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci, u8 socket) | |||
1528 | new0 = DIMM0_COR_ERR(rcv0); | 1477 | new0 = DIMM0_COR_ERR(rcv0); |
1529 | 1478 | ||
1530 | /* Updates CE counters if it is not the first time here */ | 1479 | /* Updates CE counters if it is not the first time here */ |
1531 | if (pvt->ce_count_available[socket]) { | 1480 | if (pvt->ce_count_available) { |
1532 | /* Updates CE counters */ | 1481 | /* Updates CE counters */ |
1533 | int add0, add1, add2; | 1482 | int add0, add1, add2; |
1534 | 1483 | ||
1535 | add2 = new2 - pvt->udimm_last_ce_count[socket][2]; | 1484 | add2 = new2 - pvt->udimm_last_ce_count[2]; |
1536 | add1 = new1 - pvt->udimm_last_ce_count[socket][1]; | 1485 | add1 = new1 - pvt->udimm_last_ce_count[1]; |
1537 | add0 = new0 - pvt->udimm_last_ce_count[socket][0]; | 1486 | add0 = new0 - pvt->udimm_last_ce_count[0]; |
1538 | 1487 | ||
1539 | if (add2 < 0) | 1488 | if (add2 < 0) |
1540 | add2 += 0x7fff; | 1489 | add2 += 0x7fff; |
1541 | pvt->udimm_ce_count[socket][2] += add2; | 1490 | pvt->udimm_ce_count[2] += add2; |
1542 | 1491 | ||
1543 | if (add1 < 0) | 1492 | if (add1 < 0) |
1544 | add1 += 0x7fff; | 1493 | add1 += 0x7fff; |
1545 | pvt->udimm_ce_count[socket][1] += add1; | 1494 | pvt->udimm_ce_count[1] += add1; |
1546 | 1495 | ||
1547 | if (add0 < 0) | 1496 | if (add0 < 0) |
1548 | add0 += 0x7fff; | 1497 | add0 += 0x7fff; |
1549 | pvt->udimm_ce_count[socket][0] += add0; | 1498 | pvt->udimm_ce_count[0] += add0; |
1550 | 1499 | ||
1551 | if (add0 | add1 | add2) | 1500 | if (add0 | add1 | add2) |
1552 | i7core_printk(KERN_ERR, "New Corrected error(s): " | 1501 | i7core_printk(KERN_ERR, "New Corrected error(s): " |
1553 | "dimm0: +%d, dimm1: +%d, dimm2 +%d\n", | 1502 | "dimm0: +%d, dimm1: +%d, dimm2 +%d\n", |
1554 | add0, add1, add2); | 1503 | add0, add1, add2); |
1555 | } else | 1504 | } else |
1556 | pvt->ce_count_available[socket] = 1; | 1505 | pvt->ce_count_available = 1; |
1557 | 1506 | ||
1558 | /* Store the new values */ | 1507 | /* Store the new values */ |
1559 | pvt->udimm_last_ce_count[socket][2] = new2; | 1508 | pvt->udimm_last_ce_count[2] = new2; |
1560 | pvt->udimm_last_ce_count[socket][1] = new1; | 1509 | pvt->udimm_last_ce_count[1] = new1; |
1561 | pvt->udimm_last_ce_count[socket][0] = new0; | 1510 | pvt->udimm_last_ce_count[0] = new0; |
1562 | } | 1511 | } |
1563 | 1512 | ||
1564 | /* | 1513 | /* |
@@ -1587,13 +1536,6 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, | |||
1587 | u32 syndrome = m->misc >> 32; | 1536 | u32 syndrome = m->misc >> 32; |
1588 | u32 errnum = find_first_bit(&error, 32); | 1537 | u32 errnum = find_first_bit(&error, 32); |
1589 | int csrow; | 1538 | int csrow; |
1590 | /* FIXME */ | ||
1591 | //#ifdef CONFIG_SMP | ||
1592 | #if 0 | ||
1593 | u32 socket_id = per_cpu(cpu_data, cpu).phys_proc_id; | ||
1594 | #else | ||
1595 | u32 socket_id = 0; | ||
1596 | #endif | ||
1597 | 1539 | ||
1598 | if (m->mcgstatus & 1) | 1540 | if (m->mcgstatus & 1) |
1599 | type = "FATAL"; | 1541 | type = "FATAL"; |
@@ -1655,24 +1597,21 @@ static void i7core_mce_output_error(struct mem_ctl_info *mci, | |||
1655 | 1597 | ||
1656 | /* FIXME: should convert addr into bank and rank information */ | 1598 | /* FIXME: should convert addr into bank and rank information */ |
1657 | msg = kasprintf(GFP_ATOMIC, | 1599 | msg = kasprintf(GFP_ATOMIC, |
1658 | "%s (addr = 0x%08llx, socket=%d, Dimm=%d, Channel=%d, " | 1600 | "%s (addr = 0x%08llx, cpu=%d, Dimm=%d, Channel=%d, " |
1659 | "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", | 1601 | "syndrome=0x%08x, count=%d, Err=%08llx:%08llx (%s: %s))\n", |
1660 | type, (long long) m->addr, socket_id, dimm, channel, | 1602 | type, (long long) m->addr, m->cpu, dimm, channel, |
1661 | syndrome, core_err_cnt, (long long)m->status, | 1603 | syndrome, core_err_cnt, (long long)m->status, |
1662 | (long long)m->misc, optype, err); | 1604 | (long long)m->misc, optype, err); |
1663 | 1605 | ||
1664 | debugf0("%s", msg); | 1606 | debugf0("%s", msg); |
1665 | 1607 | ||
1666 | if (socket_id < NUM_SOCKETS) | 1608 | csrow = pvt->csrow_map[channel][dimm]; |
1667 | csrow = pvt->csrow_map[socket_id][channel][dimm]; | ||
1668 | else | ||
1669 | csrow = -1; | ||
1670 | 1609 | ||
1671 | /* Call the helper to output message */ | 1610 | /* Call the helper to output message */ |
1672 | if (m->mcgstatus & 1) | 1611 | if (m->mcgstatus & 1) |
1673 | edac_mc_handle_fbd_ue(mci, csrow, 0, | 1612 | edac_mc_handle_fbd_ue(mci, csrow, 0, |
1674 | 0 /* FIXME: should be channel here */, msg); | 1613 | 0 /* FIXME: should be channel here */, msg); |
1675 | else if (!pvt->is_registered[socket_id]) | 1614 | else if (!pvt->is_registered) |
1676 | edac_mc_handle_fbd_ce(mci, csrow, | 1615 | edac_mc_handle_fbd_ce(mci, csrow, |
1677 | 0 /* FIXME: should be channel here */, msg); | 1616 | 0 /* FIXME: should be channel here */, msg); |
1678 | 1617 | ||
@@ -1695,12 +1634,14 @@ static void i7core_check_error(struct mem_ctl_info *mci) | |||
1695 | spin_lock_irqsave(&pvt->mce_lock, flags); | 1634 | spin_lock_irqsave(&pvt->mce_lock, flags); |
1696 | if (pvt->mce_count) { | 1635 | if (pvt->mce_count) { |
1697 | m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); | 1636 | m = kmalloc(sizeof(*m) * pvt->mce_count, GFP_ATOMIC); |
1637 | |||
1698 | if (m) { | 1638 | if (m) { |
1699 | count = pvt->mce_count; | 1639 | count = pvt->mce_count; |
1700 | memcpy(m, &pvt->mce_entry, sizeof(*m) * count); | 1640 | memcpy(m, &pvt->mce_entry, sizeof(*m) * count); |
1701 | } | 1641 | } |
1702 | pvt->mce_count = 0; | 1642 | pvt->mce_count = 0; |
1703 | } | 1643 | } |
1644 | |||
1704 | spin_unlock_irqrestore(&pvt->mce_lock, flags); | 1645 | spin_unlock_irqrestore(&pvt->mce_lock, flags); |
1705 | 1646 | ||
1706 | /* proccess mcelog errors */ | 1647 | /* proccess mcelog errors */ |
@@ -1710,11 +1651,10 @@ static void i7core_check_error(struct mem_ctl_info *mci) | |||
1710 | kfree(m); | 1651 | kfree(m); |
1711 | 1652 | ||
1712 | /* check memory count errors */ | 1653 | /* check memory count errors */ |
1713 | for (i = 0; i < pvt->sockets; i++) | 1654 | if (!pvt->is_registered) |
1714 | if (!pvt->is_registered[i]) | 1655 | i7core_udimm_check_mc_ecc_err(mci); |
1715 | i7core_udimm_check_mc_ecc_err(mci, i); | 1656 | else |
1716 | else | 1657 | i7core_rdimm_check_mc_ecc_err(mci); |
1717 | i7core_rdimm_check_mc_ecc_err(mci, i); | ||
1718 | } | 1658 | } |
1719 | 1659 | ||
1720 | /* | 1660 | /* |
@@ -1740,6 +1680,10 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) | |||
1740 | if (mce->bank != 8) | 1680 | if (mce->bank != 8) |
1741 | return 0; | 1681 | return 0; |
1742 | 1682 | ||
1683 | /* Only handle if it is the right mc controller */ | ||
1684 | if (cpu_data(mce->cpu).phys_proc_id != pvt->i7core_dev->socket) | ||
1685 | return 0; | ||
1686 | |||
1743 | spin_lock_irqsave(&pvt->mce_lock, flags); | 1687 | spin_lock_irqsave(&pvt->mce_lock, flags); |
1744 | if (pvt->mce_count < MCE_LOG_LEN) { | 1688 | if (pvt->mce_count < MCE_LOG_LEN) { |
1745 | memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); | 1689 | memcpy(&pvt->mce_entry[pvt->mce_count], mce, sizeof(*mce)); |
@@ -1755,63 +1699,26 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) | |||
1755 | return 1; | 1699 | return 1; |
1756 | } | 1700 | } |
1757 | 1701 | ||
1758 | /* | 1702 | static int i7core_register_mci(struct i7core_dev *i7core_dev, |
1759 | * i7core_probe Probe for ONE instance of device to see if it is | 1703 | int num_channels, int num_csrows) |
1760 | * present. | ||
1761 | * return: | ||
1762 | * 0 for FOUND a device | ||
1763 | * < 0 for error code | ||
1764 | */ | ||
1765 | static int __devinit i7core_probe(struct pci_dev *pdev, | ||
1766 | const struct pci_device_id *id) | ||
1767 | { | 1704 | { |
1768 | struct mem_ctl_info *mci; | 1705 | struct mem_ctl_info *mci; |
1769 | struct i7core_pvt *pvt; | 1706 | struct i7core_pvt *pvt; |
1770 | int num_channels = 0; | ||
1771 | int num_csrows = 0; | ||
1772 | int csrow = 0; | 1707 | int csrow = 0; |
1773 | int dev_idx = id->driver_data; | 1708 | int rc; |
1774 | int rc, i; | ||
1775 | u8 sockets; | ||
1776 | |||
1777 | /* | ||
1778 | * FIXME: All memory controllers are allocated at the first pass. | ||
1779 | */ | ||
1780 | if (unlikely(dev_idx >= 1)) | ||
1781 | return -EINVAL; | ||
1782 | |||
1783 | /* get the pci devices we want to reserve for our use */ | ||
1784 | mutex_lock(&i7core_edac_lock); | ||
1785 | rc = i7core_get_devices(&sockets); | ||
1786 | if (unlikely(rc < 0)) | ||
1787 | goto fail0; | ||
1788 | |||
1789 | for (i = 0; i < sockets; i++) { | ||
1790 | int channels; | ||
1791 | int csrows; | ||
1792 | |||
1793 | /* Check the number of active and not disabled channels */ | ||
1794 | rc = i7core_get_active_channels(i, &channels, &csrows); | ||
1795 | if (unlikely(rc < 0)) | ||
1796 | goto fail1; | ||
1797 | |||
1798 | num_channels += channels; | ||
1799 | num_csrows += csrows; | ||
1800 | } | ||
1801 | 1709 | ||
1802 | /* allocate a new MC control structure */ | 1710 | /* allocate a new MC control structure */ |
1803 | mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); | 1711 | mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); |
1804 | if (unlikely(!mci)) { | 1712 | if (unlikely(!mci)) |
1805 | rc = -ENOMEM; | 1713 | return -ENOMEM; |
1806 | goto fail1; | ||
1807 | } | ||
1808 | 1714 | ||
1809 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); | 1715 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); |
1810 | 1716 | ||
1811 | mci->dev = &pdev->dev; /* record ptr to the generic device */ | 1717 | /* record ptr to the generic device */ |
1718 | mci->dev = &i7core_dev->pdev[0]->dev; | ||
1719 | |||
1812 | pvt = mci->pvt_info; | 1720 | pvt = mci->pvt_info; |
1813 | memset(pvt, 0, sizeof(*pvt)); | 1721 | memset(pvt, 0, sizeof(*pvt)); |
1814 | pvt->sockets = sockets; | ||
1815 | mci->mc_idx = 0; | 1722 | mci->mc_idx = 0; |
1816 | 1723 | ||
1817 | /* | 1724 | /* |
@@ -1824,21 +1731,21 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1824 | mci->edac_cap = EDAC_FLAG_NONE; | 1731 | mci->edac_cap = EDAC_FLAG_NONE; |
1825 | mci->mod_name = "i7core_edac.c"; | 1732 | mci->mod_name = "i7core_edac.c"; |
1826 | mci->mod_ver = I7CORE_REVISION; | 1733 | mci->mod_ver = I7CORE_REVISION; |
1827 | mci->ctl_name = i7core_probe_devs[dev_idx].ctl_name; | 1734 | mci->ctl_name = kasprintf(GFP_KERNEL, "i7 core #%d", |
1828 | mci->dev_name = pci_name(pdev); | 1735 | i7core_dev->socket); |
1736 | mci->dev_name = pci_name(i7core_dev->pdev[0]); | ||
1829 | mci->ctl_page_to_phys = NULL; | 1737 | mci->ctl_page_to_phys = NULL; |
1830 | mci->mc_driver_sysfs_attributes = i7core_inj_attrs; | 1738 | mci->mc_driver_sysfs_attributes = i7core_inj_attrs; |
1831 | /* Set the function pointer to an actual operation function */ | 1739 | /* Set the function pointer to an actual operation function */ |
1832 | mci->edac_check = i7core_check_error; | 1740 | mci->edac_check = i7core_check_error; |
1833 | 1741 | ||
1834 | /* Store pci devices at mci for faster access */ | 1742 | /* Store pci devices at mci for faster access */ |
1835 | rc = mci_bind_devs(mci); | 1743 | rc = mci_bind_devs(mci, i7core_dev); |
1836 | if (unlikely(rc < 0)) | 1744 | if (unlikely(rc < 0)) |
1837 | goto fail2; | 1745 | goto fail; |
1838 | 1746 | ||
1839 | /* Get dimm basic config */ | 1747 | /* Get dimm basic config */ |
1840 | for (i = 0; i < sockets; i++) | 1748 | get_dimm_config(mci, &csrow); |
1841 | get_dimm_config(mci, &csrow, i); | ||
1842 | 1749 | ||
1843 | /* add this new MC control structure to EDAC's list of MCs */ | 1750 | /* add this new MC control structure to EDAC's list of MCs */ |
1844 | if (unlikely(edac_mc_add_mc(mci))) { | 1751 | if (unlikely(edac_mc_add_mc(mci))) { |
@@ -1849,11 +1756,12 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1849 | */ | 1756 | */ |
1850 | 1757 | ||
1851 | rc = -EINVAL; | 1758 | rc = -EINVAL; |
1852 | goto fail2; | 1759 | goto fail; |
1853 | } | 1760 | } |
1854 | 1761 | ||
1855 | /* allocating generic PCI control info */ | 1762 | /* allocating generic PCI control info */ |
1856 | i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | 1763 | i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, |
1764 | EDAC_MOD_STR); | ||
1857 | if (unlikely(!i7core_pci)) { | 1765 | if (unlikely(!i7core_pci)) { |
1858 | printk(KERN_WARNING | 1766 | printk(KERN_WARNING |
1859 | "%s(): Unable to create PCI control\n", | 1767 | "%s(): Unable to create PCI control\n", |
@@ -1880,7 +1788,50 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1880 | if (unlikely(rc < 0)) { | 1788 | if (unlikely(rc < 0)) { |
1881 | debugf0("MC: " __FILE__ | 1789 | debugf0("MC: " __FILE__ |
1882 | ": %s(): failed edac_mce_register()\n", __func__); | 1790 | ": %s(): failed edac_mce_register()\n", __func__); |
1883 | goto fail2; | 1791 | } |
1792 | |||
1793 | fail: | ||
1794 | edac_mc_free(mci); | ||
1795 | return rc; | ||
1796 | } | ||
1797 | |||
1798 | /* | ||
1799 | * i7core_probe Probe for ONE instance of device to see if it is | ||
1800 | * present. | ||
1801 | * return: | ||
1802 | * 0 for FOUND a device | ||
1803 | * < 0 for error code | ||
1804 | */ | ||
1805 | static int __devinit i7core_probe(struct pci_dev *pdev, | ||
1806 | const struct pci_device_id *id) | ||
1807 | { | ||
1808 | int dev_idx = id->driver_data; | ||
1809 | int rc; | ||
1810 | struct i7core_dev *i7core_dev; | ||
1811 | |||
1812 | /* | ||
1813 | * FIXME: All memory controllers are allocated at the first pass. | ||
1814 | */ | ||
1815 | if (unlikely(dev_idx >= 1)) | ||
1816 | return -EINVAL; | ||
1817 | |||
1818 | /* get the pci devices we want to reserve for our use */ | ||
1819 | mutex_lock(&i7core_edac_lock); | ||
1820 | rc = i7core_get_devices(); | ||
1821 | if (unlikely(rc < 0)) | ||
1822 | goto fail0; | ||
1823 | |||
1824 | list_for_each_entry(i7core_dev, &i7core_edac_list, list) { | ||
1825 | int channels; | ||
1826 | int csrows; | ||
1827 | |||
1828 | /* Check the number of active and not disabled channels */ | ||
1829 | rc = i7core_get_active_channels(i7core_dev->socket, | ||
1830 | &channels, &csrows); | ||
1831 | if (unlikely(rc < 0)) | ||
1832 | goto fail1; | ||
1833 | |||
1834 | i7core_register_mci(i7core_dev, channels, csrows); | ||
1884 | } | 1835 | } |
1885 | 1836 | ||
1886 | i7core_printk(KERN_INFO, "Driver loaded.\n"); | 1837 | i7core_printk(KERN_INFO, "Driver loaded.\n"); |
@@ -1888,9 +1839,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1888 | mutex_unlock(&i7core_edac_lock); | 1839 | mutex_unlock(&i7core_edac_lock); |
1889 | return 0; | 1840 | return 0; |
1890 | 1841 | ||
1891 | fail2: | ||
1892 | edac_mc_free(mci); | ||
1893 | |||
1894 | fail1: | 1842 | fail1: |
1895 | i7core_put_devices(); | 1843 | i7core_put_devices(); |
1896 | fail0: | 1844 | fail0: |
@@ -1926,6 +1874,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) | |||
1926 | i7core_put_devices(); | 1874 | i7core_put_devices(); |
1927 | mutex_unlock(&i7core_edac_lock); | 1875 | mutex_unlock(&i7core_edac_lock); |
1928 | 1876 | ||
1877 | kfree(mci->ctl_name); | ||
1929 | edac_mc_free(mci); | 1878 | edac_mc_free(mci); |
1930 | } | 1879 | } |
1931 | 1880 | ||