diff options
-rw-r--r-- | drivers/edac/Kconfig | 2 | ||||
-rw-r--r-- | drivers/edac/e752x_edac.c | 165 |
2 files changed, 154 insertions, 13 deletions
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 2b382990fe58..6e6c3c4aea6b 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig | |||
@@ -67,7 +67,7 @@ config EDAC_E7XXX | |||
67 | E7205, E7500, E7501 and E7505 server chipsets. | 67 | E7205, E7500, E7501 and E7505 server chipsets. |
68 | 68 | ||
69 | config EDAC_E752X | 69 | config EDAC_E752X |
70 | tristate "Intel e752x (e7520, e7525, e7320)" | 70 | tristate "Intel e752x (e7520, e7525, e7320) and 3100" |
71 | depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG | 71 | depends on EDAC_MM_EDAC && PCI && X86 && HOTPLUG |
72 | help | 72 | help |
73 | Support for error detection and correction on the Intel | 73 | Support for error detection and correction on the Intel |
diff --git a/drivers/edac/e752x_edac.c b/drivers/edac/e752x_edac.c index 6eb434749cd5..4fbc5892bc2b 100644 --- a/drivers/edac/e752x_edac.c +++ b/drivers/edac/e752x_edac.c | |||
@@ -62,6 +62,14 @@ static struct edac_pci_ctl_info *e752x_pci; | |||
62 | #define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 | 62 | #define PCI_DEVICE_ID_INTEL_7320_1_ERR 0x3593 |
63 | #endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ | 63 | #endif /* PCI_DEVICE_ID_INTEL_7320_1_ERR */ |
64 | 64 | ||
65 | #ifndef PCI_DEVICE_ID_INTEL_3100_0 | ||
66 | #define PCI_DEVICE_ID_INTEL_3100_0 0x35B0 | ||
67 | #endif /* PCI_DEVICE_ID_INTEL_3100_0 */ | ||
68 | |||
69 | #ifndef PCI_DEVICE_ID_INTEL_3100_1_ERR | ||
70 | #define PCI_DEVICE_ID_INTEL_3100_1_ERR 0x35B1 | ||
71 | #endif /* PCI_DEVICE_ID_INTEL_3100_1_ERR */ | ||
72 | |||
65 | #define E752X_NR_CSROWS 8 /* number of csrows */ | 73 | #define E752X_NR_CSROWS 8 /* number of csrows */ |
66 | 74 | ||
67 | /* E752X register addresses - device 0 function 0 */ | 75 | /* E752X register addresses - device 0 function 0 */ |
@@ -152,6 +160,12 @@ static struct edac_pci_ctl_info *e752x_pci; | |||
152 | /* error syndrome register (16b) */ | 160 | /* error syndrome register (16b) */ |
153 | #define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ | 161 | #define E752X_DEVPRES1 0xF4 /* Device Present 1 register (8b) */ |
154 | 162 | ||
163 | /* 3100 IMCH specific register addresses - device 0 function 1 */ | ||
164 | #define I3100_NSI_FERR 0x48 /* NSI first error reg (32b) */ | ||
165 | #define I3100_NSI_NERR 0x4C /* NSI next error reg (32b) */ | ||
166 | #define I3100_NSI_SMICMD 0x54 /* NSI SMI command register (32b) */ | ||
167 | #define I3100_NSI_EMASK 0x90 /* NSI error mask register (32b) */ | ||
168 | |||
155 | /* ICH5R register addresses - device 30 function 0 */ | 169 | /* ICH5R register addresses - device 30 function 0 */ |
156 | #define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ | 170 | #define ICH5R_PCI_STAT 0x06 /* PCI status register (16b) */ |
157 | #define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ | 171 | #define ICH5R_PCI_2ND_STAT 0x1E /* PCI status secondary reg (16b) */ |
@@ -160,7 +174,8 @@ static struct edac_pci_ctl_info *e752x_pci; | |||
160 | enum e752x_chips { | 174 | enum e752x_chips { |
161 | E7520 = 0, | 175 | E7520 = 0, |
162 | E7525 = 1, | 176 | E7525 = 1, |
163 | E7320 = 2 | 177 | E7320 = 2, |
178 | I3100 = 3 | ||
164 | }; | 179 | }; |
165 | 180 | ||
166 | struct e752x_pvt { | 181 | struct e752x_pvt { |
@@ -185,8 +200,10 @@ struct e752x_dev_info { | |||
185 | struct e752x_error_info { | 200 | struct e752x_error_info { |
186 | u32 ferr_global; | 201 | u32 ferr_global; |
187 | u32 nerr_global; | 202 | u32 nerr_global; |
188 | u8 hi_ferr; | 203 | u32 nsi_ferr; /* 3100 only */ |
189 | u8 hi_nerr; | 204 | u32 nsi_nerr; /* 3100 only */ |
205 | u8 hi_ferr; /* all but 3100 */ | ||
206 | u8 hi_nerr; /* all but 3100 */ | ||
190 | u16 sysbus_ferr; | 207 | u16 sysbus_ferr; |
191 | u16 sysbus_nerr; | 208 | u16 sysbus_nerr; |
192 | u8 buf_ferr; | 209 | u8 buf_ferr; |
@@ -215,6 +232,10 @@ static const struct e752x_dev_info e752x_devs[] = { | |||
215 | .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, | 232 | .err_dev = PCI_DEVICE_ID_INTEL_7320_1_ERR, |
216 | .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, | 233 | .ctl_dev = PCI_DEVICE_ID_INTEL_7320_0, |
217 | .ctl_name = "E7320"}, | 234 | .ctl_name = "E7320"}, |
235 | [I3100] = { | ||
236 | .err_dev = PCI_DEVICE_ID_INTEL_3100_1_ERR, | ||
237 | .ctl_dev = PCI_DEVICE_ID_INTEL_3100_0, | ||
238 | .ctl_name = "3100"}, | ||
218 | }; | 239 | }; |
219 | 240 | ||
220 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, | 241 | static unsigned long ctl_page_to_phys(struct mem_ctl_info *mci, |
@@ -402,7 +423,7 @@ static inline void process_threshold_ce(struct mem_ctl_info *mci, u16 error, | |||
402 | static char *global_message[11] = { | 423 | static char *global_message[11] = { |
403 | "PCI Express C1", "PCI Express C", "PCI Express B1", | 424 | "PCI Express C1", "PCI Express C", "PCI Express B1", |
404 | "PCI Express B", "PCI Express A1", "PCI Express A", | 425 | "PCI Express B", "PCI Express A1", "PCI Express A", |
405 | "DMA Controler", "HUB Interface", "System Bus", | 426 | "DMA Controler", "HUB or NS Interface", "System Bus", |
406 | "DRAM Controler", "Internal Buffer" | 427 | "DRAM Controler", "Internal Buffer" |
407 | }; | 428 | }; |
408 | 429 | ||
@@ -455,6 +476,63 @@ static inline void hub_error(int fatal, u8 errors, int *error_found, | |||
455 | do_hub_error(fatal, errors); | 476 | do_hub_error(fatal, errors); |
456 | } | 477 | } |
457 | 478 | ||
479 | #define NSI_FATAL_MASK 0x0c080081 | ||
480 | #define NSI_NON_FATAL_MASK 0x23a0ba64 | ||
481 | #define NSI_ERR_MASK (NSI_FATAL_MASK | NSI_NON_FATAL_MASK) | ||
482 | |||
483 | static char *nsi_message[30] = { | ||
484 | "NSI Link Down", /* NSI_FERR/NSI_NERR bit 0, fatal error */ | ||
485 | "", /* reserved */ | ||
486 | "NSI Parity Error", /* bit 2, non-fatal */ | ||
487 | "", /* reserved */ | ||
488 | "", /* reserved */ | ||
489 | "Correctable Error Message", /* bit 5, non-fatal */ | ||
490 | "Non-Fatal Error Message", /* bit 6, non-fatal */ | ||
491 | "Fatal Error Message", /* bit 7, fatal */ | ||
492 | "", /* reserved */ | ||
493 | "Receiver Error", /* bit 9, non-fatal */ | ||
494 | "", /* reserved */ | ||
495 | "Bad TLP", /* bit 11, non-fatal */ | ||
496 | "Bad DLLP", /* bit 12, non-fatal */ | ||
497 | "REPLAY_NUM Rollover", /* bit 13, non-fatal */ | ||
498 | "", /* reserved */ | ||
499 | "Replay Timer Timeout", /* bit 15, non-fatal */ | ||
500 | "", /* reserved */ | ||
501 | "", /* reserved */ | ||
502 | "", /* reserved */ | ||
503 | "Data Link Protocol Error", /* bit 19, fatal */ | ||
504 | "", /* reserved */ | ||
505 | "Poisoned TLP", /* bit 21, non-fatal */ | ||
506 | "", /* reserved */ | ||
507 | "Completion Timeout", /* bit 23, non-fatal */ | ||
508 | "Completer Abort", /* bit 24, non-fatal */ | ||
509 | "Unexpected Completion", /* bit 25, non-fatal */ | ||
510 | "Receiver Overflow", /* bit 26, fatal */ | ||
511 | "Malformed TLP", /* bit 27, fatal */ | ||
512 | "", /* reserved */ | ||
513 | "Unsupported Request" /* bit 29, non-fatal */ | ||
514 | }; | ||
515 | |||
516 | static void do_nsi_error(int fatal, u32 errors) | ||
517 | { | ||
518 | int i; | ||
519 | |||
520 | for (i = 0; i < 30; i++) { | ||
521 | if (errors & (1 << i)) | ||
522 | printk(KERN_WARNING "%sError %s\n", | ||
523 | fatal_message[fatal], nsi_message[i]); | ||
524 | } | ||
525 | } | ||
526 | |||
527 | static inline void nsi_error(int fatal, u32 errors, int *error_found, | ||
528 | int handle_error) | ||
529 | { | ||
530 | *error_found = 1; | ||
531 | |||
532 | if (handle_error) | ||
533 | do_nsi_error(fatal, errors); | ||
534 | } | ||
535 | |||
458 | static char *membuf_message[4] = { | 536 | static char *membuf_message[4] = { |
459 | "Internal PMWB to DRAM parity", | 537 | "Internal PMWB to DRAM parity", |
460 | "Internal PMWB to System Bus Parity", | 538 | "Internal PMWB to System Bus Parity", |
@@ -546,6 +624,31 @@ static void e752x_check_hub_interface(struct e752x_error_info *info, | |||
546 | } | 624 | } |
547 | } | 625 | } |
548 | 626 | ||
627 | static void e752x_check_ns_interface(struct e752x_error_info *info, | ||
628 | int *error_found, int handle_error) | ||
629 | { | ||
630 | u32 stat32; | ||
631 | |||
632 | stat32 = info->nsi_ferr; | ||
633 | if (stat32 & NSI_ERR_MASK) { /* Error, so process */ | ||
634 | if (stat32 & NSI_FATAL_MASK) /* check for fatal errors */ | ||
635 | nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, | ||
636 | handle_error); | ||
637 | if (stat32 & NSI_NON_FATAL_MASK) /* check for non-fatal ones */ | ||
638 | nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, | ||
639 | handle_error); | ||
640 | } | ||
641 | stat32 = info->nsi_nerr; | ||
642 | if (stat32 & NSI_ERR_MASK) { | ||
643 | if (stat32 & NSI_FATAL_MASK) | ||
644 | nsi_error(1, stat32 & NSI_FATAL_MASK, error_found, | ||
645 | handle_error); | ||
646 | if (stat32 & NSI_NON_FATAL_MASK) | ||
647 | nsi_error(0, stat32 & NSI_NON_FATAL_MASK, error_found, | ||
648 | handle_error); | ||
649 | } | ||
650 | } | ||
651 | |||
549 | static void e752x_check_sysbus(struct e752x_error_info *info, | 652 | static void e752x_check_sysbus(struct e752x_error_info *info, |
550 | int *error_found, int handle_error) | 653 | int *error_found, int handle_error) |
551 | { | 654 | { |
@@ -653,7 +756,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, | |||
653 | pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); | 756 | pci_read_config_dword(dev, E752X_FERR_GLOBAL, &info->ferr_global); |
654 | 757 | ||
655 | if (info->ferr_global) { | 758 | if (info->ferr_global) { |
656 | pci_read_config_byte(dev, E752X_HI_FERR, &info->hi_ferr); | 759 | if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { |
760 | pci_read_config_dword(dev, I3100_NSI_FERR, | ||
761 | &info->nsi_ferr); | ||
762 | info->hi_ferr = 0; | ||
763 | } else { | ||
764 | pci_read_config_byte(dev, E752X_HI_FERR, | ||
765 | &info->hi_ferr); | ||
766 | info->nsi_ferr = 0; | ||
767 | } | ||
657 | pci_read_config_word(dev, E752X_SYSBUS_FERR, | 768 | pci_read_config_word(dev, E752X_SYSBUS_FERR, |
658 | &info->sysbus_ferr); | 769 | &info->sysbus_ferr); |
659 | pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); | 770 | pci_read_config_byte(dev, E752X_BUF_FERR, &info->buf_ferr); |
@@ -669,10 +780,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, | |||
669 | pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, | 780 | pci_read_config_dword(dev, E752X_DRAM_RETR_ADD, |
670 | &info->dram_retr_add); | 781 | &info->dram_retr_add); |
671 | 782 | ||
783 | /* ignore the reserved bits just in case */ | ||
672 | if (info->hi_ferr & 0x7f) | 784 | if (info->hi_ferr & 0x7f) |
673 | pci_write_config_byte(dev, E752X_HI_FERR, | 785 | pci_write_config_byte(dev, E752X_HI_FERR, |
674 | info->hi_ferr); | 786 | info->hi_ferr); |
675 | 787 | ||
788 | if (info->nsi_ferr & NSI_ERR_MASK) | ||
789 | pci_write_config_dword(dev, I3100_NSI_FERR, | ||
790 | info->nsi_ferr); | ||
791 | |||
676 | if (info->sysbus_ferr) | 792 | if (info->sysbus_ferr) |
677 | pci_write_config_word(dev, E752X_SYSBUS_FERR, | 793 | pci_write_config_word(dev, E752X_SYSBUS_FERR, |
678 | info->sysbus_ferr); | 794 | info->sysbus_ferr); |
@@ -692,7 +808,15 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, | |||
692 | pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); | 808 | pci_read_config_dword(dev, E752X_NERR_GLOBAL, &info->nerr_global); |
693 | 809 | ||
694 | if (info->nerr_global) { | 810 | if (info->nerr_global) { |
695 | pci_read_config_byte(dev, E752X_HI_NERR, &info->hi_nerr); | 811 | if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { |
812 | pci_read_config_dword(dev, I3100_NSI_NERR, | ||
813 | &info->nsi_nerr); | ||
814 | info->hi_nerr = 0; | ||
815 | } else { | ||
816 | pci_read_config_byte(dev, E752X_HI_NERR, | ||
817 | &info->hi_nerr); | ||
818 | info->nsi_nerr = 0; | ||
819 | } | ||
696 | pci_read_config_word(dev, E752X_SYSBUS_NERR, | 820 | pci_read_config_word(dev, E752X_SYSBUS_NERR, |
697 | &info->sysbus_nerr); | 821 | &info->sysbus_nerr); |
698 | pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); | 822 | pci_read_config_byte(dev, E752X_BUF_NERR, &info->buf_nerr); |
@@ -706,6 +830,10 @@ static void e752x_get_error_info(struct mem_ctl_info *mci, | |||
706 | pci_write_config_byte(dev, E752X_HI_NERR, | 830 | pci_write_config_byte(dev, E752X_HI_NERR, |
707 | info->hi_nerr); | 831 | info->hi_nerr); |
708 | 832 | ||
833 | if (info->nsi_nerr & NSI_ERR_MASK) | ||
834 | pci_write_config_dword(dev, I3100_NSI_NERR, | ||
835 | info->nsi_nerr); | ||
836 | |||
709 | if (info->sysbus_nerr) | 837 | if (info->sysbus_nerr) |
710 | pci_write_config_word(dev, E752X_SYSBUS_NERR, | 838 | pci_write_config_word(dev, E752X_SYSBUS_NERR, |
711 | info->sysbus_nerr); | 839 | info->sysbus_nerr); |
@@ -750,6 +878,7 @@ static int e752x_process_error_info(struct mem_ctl_info *mci, | |||
750 | global_error(0, stat32, &error_found, handle_errors); | 878 | global_error(0, stat32, &error_found, handle_errors); |
751 | 879 | ||
752 | e752x_check_hub_interface(info, &error_found, handle_errors); | 880 | e752x_check_hub_interface(info, &error_found, handle_errors); |
881 | e752x_check_ns_interface(info, &error_found, handle_errors); | ||
753 | e752x_check_sysbus(info, &error_found, handle_errors); | 882 | e752x_check_sysbus(info, &error_found, handle_errors); |
754 | e752x_check_membuf(info, &error_found, handle_errors); | 883 | e752x_check_membuf(info, &error_found, handle_errors); |
755 | e752x_check_dram(mci, info, &error_found, handle_errors); | 884 | e752x_check_dram(mci, info, &error_found, handle_errors); |
@@ -926,8 +1055,13 @@ static void e752x_init_error_reporting_regs(struct e752x_pvt *pvt) | |||
926 | 1055 | ||
927 | dev = pvt->dev_d0f1; | 1056 | dev = pvt->dev_d0f1; |
928 | /* Turn off error disable & SMI in case the BIOS turned it on */ | 1057 | /* Turn off error disable & SMI in case the BIOS turned it on */ |
929 | pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); | 1058 | if (pvt->dev_info->err_dev == PCI_DEVICE_ID_INTEL_3100_1_ERR) { |
930 | pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); | 1059 | pci_write_config_dword(dev, I3100_NSI_EMASK, 0); |
1060 | pci_write_config_dword(dev, I3100_NSI_SMICMD, 0); | ||
1061 | } else { | ||
1062 | pci_write_config_byte(dev, E752X_HI_ERRMASK, 0x00); | ||
1063 | pci_write_config_byte(dev, E752X_HI_SMICMD, 0x00); | ||
1064 | } | ||
931 | pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); | 1065 | pci_write_config_word(dev, E752X_SYSBUS_ERRMASK, 0x00); |
932 | pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); | 1066 | pci_write_config_word(dev, E752X_SYSBUS_SMICMD, 0x00); |
933 | pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); | 1067 | pci_write_config_byte(dev, E752X_BUF_ERRMASK, 0x00); |
@@ -985,8 +1119,9 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
985 | 1119 | ||
986 | debugf3("%s(): init mci\n", __func__); | 1120 | debugf3("%s(): init mci\n", __func__); |
987 | mci->mtype_cap = MEM_FLAG_RDDR; | 1121 | mci->mtype_cap = MEM_FLAG_RDDR; |
988 | mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED | | 1122 | /* 3100 IMCH supports SECDEC only */ |
989 | EDAC_FLAG_S4ECD4ED; | 1123 | mci->edac_ctl_cap = (dev_idx == I3100) ? EDAC_FLAG_SECDED : |
1124 | (EDAC_FLAG_NONE | EDAC_FLAG_SECDED | EDAC_FLAG_S4ECD4ED); | ||
990 | /* FIXME - what if different memory types are in different csrows? */ | 1125 | /* FIXME - what if different memory types are in different csrows? */ |
991 | mci->mod_name = EDAC_MOD_STR; | 1126 | mci->mod_name = EDAC_MOD_STR; |
992 | mci->mod_ver = E752X_REVISION; | 1127 | mci->mod_ver = E752X_REVISION; |
@@ -1018,7 +1153,10 @@ static int e752x_probe1(struct pci_dev *pdev, int dev_idx) | |||
1018 | e752x_init_csrows(mci, pdev, ddrcsr); | 1153 | e752x_init_csrows(mci, pdev, ddrcsr); |
1019 | e752x_init_mem_map_table(pdev, pvt); | 1154 | e752x_init_mem_map_table(pdev, pvt); |
1020 | 1155 | ||
1021 | mci->edac_cap |= EDAC_FLAG_NONE; | 1156 | if (dev_idx == I3100) |
1157 | mci->edac_cap = EDAC_FLAG_SECDED; /* the only mode supported */ | ||
1158 | else | ||
1159 | mci->edac_cap |= EDAC_FLAG_NONE; | ||
1022 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); | 1160 | debugf3("%s(): tolm, remapbase, remaplimit\n", __func__); |
1023 | 1161 | ||
1024 | /* load the top of low memory, remap base, and remap limit vars */ | 1162 | /* load the top of low memory, remap base, and remap limit vars */ |
@@ -1110,6 +1248,9 @@ static const struct pci_device_id e752x_pci_tbl[] __devinitdata = { | |||
1110 | PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | 1248 | PCI_VEND_DEV(INTEL, 7320_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, |
1111 | E7320}, | 1249 | E7320}, |
1112 | { | 1250 | { |
1251 | PCI_VEND_DEV(INTEL, 3100_0), PCI_ANY_ID, PCI_ANY_ID, 0, 0, | ||
1252 | I3100}, | ||
1253 | { | ||
1113 | 0, | 1254 | 0, |
1114 | } /* 0 terminated list. */ | 1255 | } /* 0 terminated list. */ |
1115 | }; | 1256 | }; |
@@ -1143,7 +1284,7 @@ module_exit(e752x_exit); | |||
1143 | 1284 | ||
1144 | MODULE_LICENSE("GPL"); | 1285 | MODULE_LICENSE("GPL"); |
1145 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); | 1286 | MODULE_AUTHOR("Linux Networx (http://lnxi.com) Tom Zimmerman\n"); |
1146 | MODULE_DESCRIPTION("MC support for Intel e752x memory controllers"); | 1287 | MODULE_DESCRIPTION("MC support for Intel e752x/3100 memory controllers"); |
1147 | 1288 | ||
1148 | module_param(force_function_unhide, int, 0444); | 1289 | module_param(force_function_unhide, int, 0444); |
1149 | MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" | 1290 | MODULE_PARM_DESC(force_function_unhide, "if BIOS sets Dev0:Fun1 up as hidden:" |