diff options
-rw-r--r-- | drivers/edac/i7300_edac.c | 220 |
1 files changed, 104 insertions, 116 deletions
diff --git a/drivers/edac/i7300_edac.c b/drivers/edac/i7300_edac.c index 6278209fec07..a2a9ad499b6b 100644 --- a/drivers/edac/i7300_edac.c +++ b/drivers/edac/i7300_edac.c | |||
@@ -122,14 +122,6 @@ static struct edac_pci_ctl_info *i7300_pci; | |||
122 | ***************************************************/ | 122 | ***************************************************/ |
123 | 123 | ||
124 | /* | 124 | /* |
125 | * I7300 devices: | ||
126 | * All 3 functions of Device 16 (0,1,2) share the SAME DID and | ||
127 | * uses PCI_DEVICE_ID_INTEL_I7300_MCH_ERR for device 16 (0,1,2). | ||
128 | * PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 is used for device 21 (0,1) | ||
129 | * and PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 is used for device 21 (0,1). | ||
130 | */ | ||
131 | |||
132 | /* | ||
133 | * Device 16, | 125 | * Device 16, |
134 | * Function 0: System Address (not documented) | 126 | * Function 0: System Address (not documented) |
135 | * Function 1: Memory Branch Map, Control, Errors Register | 127 | * Function 1: Memory Branch Map, Control, Errors Register |
@@ -345,9 +337,24 @@ static const char *ferr_global_lo_name[] = { | |||
345 | * i7300 Functions related to error detection | 337 | * i7300 Functions related to error detection |
346 | ********************************************/ | 338 | ********************************************/ |
347 | 339 | ||
348 | const char *get_err_from_table(const char *table[], int size, int pos) | 340 | /** |
341 | * get_err_from_table() - Gets the error message from a table | ||
342 | * @table: table name (array of char *) | ||
343 | * @size: number of elements at the table | ||
344 | * @pos: position of the element to be returned | ||
345 | * | ||
346 | * This is a small routine that gets the pos-th element of a table. If the | ||
347 | * element doesn't exist (or it is empty), it returns "reserved". | ||
348 | * Instead of calling it directly, the better is to call via the macro | ||
349 | * GET_ERR_FROM_TABLE(), that automatically checks the table size via | ||
350 | * ARRAY_SIZE() macro | ||
351 | */ | ||
352 | static const char *get_err_from_table(const char *table[], int size, int pos) | ||
349 | { | 353 | { |
350 | if (pos >= size) | 354 | if (unlikely(pos >= size)) |
355 | return "Reserved"; | ||
356 | |||
357 | if (unlikely(!table[pos])) | ||
351 | return "Reserved"; | 358 | return "Reserved"; |
352 | 359 | ||
353 | return table[pos]; | 360 | return table[pos]; |
@@ -356,10 +363,11 @@ const char *get_err_from_table(const char *table[], int size, int pos) | |||
356 | #define GET_ERR_FROM_TABLE(table, pos) \ | 363 | #define GET_ERR_FROM_TABLE(table, pos) \ |
357 | get_err_from_table(table, ARRAY_SIZE(table), pos) | 364 | get_err_from_table(table, ARRAY_SIZE(table), pos) |
358 | 365 | ||
359 | /* | 366 | /** |
360 | * i7300_process_error_global Retrieve the hardware error information from | 367 | * i7300_process_error_global() - Retrieve the hardware error information from |
361 | * the hardware and cache it in the 'info' | 368 | * the hardware global error registers and |
362 | * structure | 369 | * sends it to dmesg |
370 | * @mci: struct mem_ctl_info pointer | ||
363 | */ | 371 | */ |
364 | static void i7300_process_error_global(struct mem_ctl_info *mci) | 372 | static void i7300_process_error_global(struct mem_ctl_info *mci) |
365 | { | 373 | { |
@@ -410,10 +418,11 @@ error_global: | |||
410 | is_fatal ? "Fatal" : "NOT fatal", specific); | 418 | is_fatal ? "Fatal" : "NOT fatal", specific); |
411 | } | 419 | } |
412 | 420 | ||
413 | /* | 421 | /** |
414 | * i7300_process_fbd_error Retrieve the hardware error information from | 422 | * i7300_process_fbd_error() - Retrieve the hardware error information from |
415 | * the hardware and cache it in the 'info' | 423 | * the FBD error registers and sends it via |
416 | * structure | 424 | * EDAC error API calls |
425 | * @mci: struct mem_ctl_info pointer | ||
417 | */ | 426 | */ |
418 | static void i7300_process_fbd_error(struct mem_ctl_info *mci) | 427 | static void i7300_process_fbd_error(struct mem_ctl_info *mci) |
419 | { | 428 | { |
@@ -524,10 +533,9 @@ static void i7300_process_fbd_error(struct mem_ctl_info *mci) | |||
524 | return; | 533 | return; |
525 | } | 534 | } |
526 | 535 | ||
527 | /* | 536 | /** |
528 | * i7300_check_error Retrieve the hardware error information from | 537 | * i7300_check_error() - Calls the error checking subroutines |
529 | * the hardware and cache it in the 'info' | 538 | * @mci: struct mem_ctl_info pointer |
530 | * structure | ||
531 | */ | 539 | */ |
532 | static void i7300_check_error(struct mem_ctl_info *mci) | 540 | static void i7300_check_error(struct mem_ctl_info *mci) |
533 | { | 541 | { |
@@ -535,11 +543,9 @@ static void i7300_check_error(struct mem_ctl_info *mci) | |||
535 | i7300_process_fbd_error(mci); | 543 | i7300_process_fbd_error(mci); |
536 | }; | 544 | }; |
537 | 545 | ||
538 | /* | 546 | /** |
539 | * i7300_clear_error Retrieve any error from the hardware | 547 | * i7300_clear_error() - Clears the error registers |
540 | * but do NOT process that error. | 548 | * @mci: struct mem_ctl_info pointer |
541 | * Used for 'clearing' out of previous errors | ||
542 | * Called by the Core module. | ||
543 | */ | 549 | */ |
544 | static void i7300_clear_error(struct mem_ctl_info *mci) | 550 | static void i7300_clear_error(struct mem_ctl_info *mci) |
545 | { | 551 | { |
@@ -573,9 +579,10 @@ static void i7300_clear_error(struct mem_ctl_info *mci) | |||
573 | FERR_NF_FBD, value); | 579 | FERR_NF_FBD, value); |
574 | } | 580 | } |
575 | 581 | ||
576 | /* | 582 | /** |
577 | * i7300_enable_error_reporting | 583 | * i7300_enable_error_reporting() - Enable the memory reporting logic at the |
578 | * Turn on the memory reporting features of the hardware | 584 | * hardware |
585 | * @mci: struct mem_ctl_info pointer | ||
579 | */ | 586 | */ |
580 | static void i7300_enable_error_reporting(struct mem_ctl_info *mci) | 587 | static void i7300_enable_error_reporting(struct mem_ctl_info *mci) |
581 | { | 588 | { |
@@ -597,10 +604,14 @@ static void i7300_enable_error_reporting(struct mem_ctl_info *mci) | |||
597 | * i7300 Functions related to memory enumberation | 604 | * i7300 Functions related to memory enumberation |
598 | ************************************************/ | 605 | ************************************************/ |
599 | 606 | ||
600 | /* | 607 | /** |
601 | * determine_mtr(pvt, csrow, channel) | 608 | * decode_mtr() - Decodes the MTR descriptor, filling the edac structs |
602 | * | 609 | * @pvt: pointer to the private data struct used by i7300 driver |
603 | * return the proper MTR register as determine by the csrow and desired channel | 610 | * @slot: DIMM slot (0 to 7) |
611 | * @ch: Channel number within the branch (0 or 1) | ||
612 | * @branch: Branch number (0 or 1) | ||
613 | * @dinfo: Pointer to DIMM info where dimm size is stored | ||
614 | * @p_csrow: Pointer to the struct csrow_info that corresponds to that element | ||
604 | */ | 615 | */ |
605 | static int decode_mtr(struct i7300_pvt *pvt, | 616 | static int decode_mtr(struct i7300_pvt *pvt, |
606 | int slot, int ch, int branch, | 617 | int slot, int ch, int branch, |
@@ -619,14 +630,8 @@ static int decode_mtr(struct i7300_pvt *pvt, | |||
619 | ans ? "Present" : "NOT Present"); | 630 | ans ? "Present" : "NOT Present"); |
620 | 631 | ||
621 | /* Determine if there is a DIMM present in this DIMM slot */ | 632 | /* Determine if there is a DIMM present in this DIMM slot */ |
622 | |||
623 | #if 0 | ||
624 | if (!amb_present || !ans) | ||
625 | return 0; | ||
626 | #else | ||
627 | if (!ans) | 633 | if (!ans) |
628 | return 0; | 634 | return 0; |
629 | #endif | ||
630 | 635 | ||
631 | /* Start with the number of bits for a Bank | 636 | /* Start with the number of bits for a Bank |
632 | * on the DRAM */ | 637 | * on the DRAM */ |
@@ -692,14 +697,15 @@ static int decode_mtr(struct i7300_pvt *pvt, | |||
692 | return mtr; | 697 | return mtr; |
693 | } | 698 | } |
694 | 699 | ||
695 | /* | 700 | /** |
696 | * print_dimm_size | 701 | * print_dimm_size() - Prints dump of the memory organization |
702 | * @pvt: pointer to the private data struct used by i7300 driver | ||
697 | * | 703 | * |
698 | * also will output a DIMM matrix map, if debug is enabled, for viewing | 704 | * Useful for debug. If debug is disabled, this routine do nothing |
699 | * how the DIMMs are populated | ||
700 | */ | 705 | */ |
701 | static void print_dimm_size(struct i7300_pvt *pvt) | 706 | static void print_dimm_size(struct i7300_pvt *pvt) |
702 | { | 707 | { |
708 | #ifdef CONFIG_EDAC_DEBUG | ||
703 | struct i7300_dimm_info *dinfo; | 709 | struct i7300_dimm_info *dinfo; |
704 | char *p; | 710 | char *p; |
705 | int space, n; | 711 | int space, n; |
@@ -751,30 +757,26 @@ static void print_dimm_size(struct i7300_pvt *pvt) | |||
751 | debugf2("%s\n", pvt->tmp_prt_buffer); | 757 | debugf2("%s\n", pvt->tmp_prt_buffer); |
752 | p = pvt->tmp_prt_buffer; | 758 | p = pvt->tmp_prt_buffer; |
753 | space = PAGE_SIZE; | 759 | space = PAGE_SIZE; |
760 | #endif | ||
754 | } | 761 | } |
755 | 762 | ||
756 | /* | 763 | /** |
757 | * i7300_init_csrows Initialize the 'csrows' table within | 764 | * i7300_init_csrows() - Initialize the 'csrows' table within |
758 | * the mci control structure with the | 765 | * the mci control structure with the |
759 | * addressing of memory. | 766 | * addressing of memory. |
760 | * | 767 | * @mci: struct mem_ctl_info pointer |
761 | * return: | ||
762 | * 0 success | ||
763 | * 1 no actual memory found on this MC | ||
764 | */ | 768 | */ |
765 | static int i7300_init_csrows(struct mem_ctl_info *mci) | 769 | static int i7300_init_csrows(struct mem_ctl_info *mci) |
766 | { | 770 | { |
767 | struct i7300_pvt *pvt; | 771 | struct i7300_pvt *pvt; |
768 | struct i7300_dimm_info *dinfo; | 772 | struct i7300_dimm_info *dinfo; |
769 | struct csrow_info *p_csrow; | 773 | struct csrow_info *p_csrow; |
770 | int empty; | 774 | int rc = -ENODEV; |
771 | int mtr; | 775 | int mtr; |
772 | int ch, branch, slot, channel; | 776 | int ch, branch, slot, channel; |
773 | 777 | ||
774 | pvt = mci->pvt_info; | 778 | pvt = mci->pvt_info; |
775 | 779 | ||
776 | empty = 1; /* Assume NO memory */ | ||
777 | |||
778 | debugf2("Memory Technology Registers:\n"); | 780 | debugf2("Memory Technology Registers:\n"); |
779 | 781 | ||
780 | /* Get the AMB present registers for the four channels */ | 782 | /* Get the AMB present registers for the four channels */ |
@@ -819,14 +821,19 @@ static int i7300_init_csrows(struct mem_ctl_info *mci) | |||
819 | p_csrow->last_page = 9 + slot * 20; | 821 | p_csrow->last_page = 9 + slot * 20; |
820 | p_csrow->page_mask = 0xfff; | 822 | p_csrow->page_mask = 0xfff; |
821 | 823 | ||
822 | empty = 0; | 824 | rc = 0; |
823 | } | 825 | } |
824 | } | 826 | } |
825 | } | 827 | } |
826 | 828 | ||
827 | return empty; | 829 | return rc; |
828 | } | 830 | } |
829 | 831 | ||
832 | /** | ||
833 | * decode_mir() - Decodes Memory Interleave Register (MIR) info | ||
834 | * @int mir_no: number of the MIR register to decode | ||
835 | * @mir: array with the MIR data cached on the driver | ||
836 | */ | ||
830 | static void decode_mir(int mir_no, u16 mir[MAX_MIR]) | 837 | static void decode_mir(int mir_no, u16 mir[MAX_MIR]) |
831 | { | 838 | { |
832 | if (mir[mir_no] & 3) | 839 | if (mir[mir_no] & 3) |
@@ -837,11 +844,11 @@ static void decode_mir(int mir_no, u16 mir[MAX_MIR]) | |||
837 | (mir[mir_no] & 2) ? "B1": ""); | 844 | (mir[mir_no] & 2) ? "B1": ""); |
838 | } | 845 | } |
839 | 846 | ||
840 | /* | 847 | /** |
841 | * i7300_get_mc_regs read in the necessary registers and | 848 | * i7300_get_mc_regs() - Get the contents of the MC enumeration registers |
842 | * cache locally | 849 | * @mci: struct mem_ctl_info pointer |
843 | * | 850 | * |
844 | * Fills in the private data members | 851 | * Data read is cached internally for its usage when needed |
845 | */ | 852 | */ |
846 | static int i7300_get_mc_regs(struct mem_ctl_info *mci) | 853 | static int i7300_get_mc_regs(struct mem_ctl_info *mci) |
847 | { | 854 | { |
@@ -907,9 +914,9 @@ static int i7300_get_mc_regs(struct mem_ctl_info *mci) | |||
907 | * i7300 Functions related to device probe/release | 914 | * i7300 Functions related to device probe/release |
908 | *************************************************/ | 915 | *************************************************/ |
909 | 916 | ||
910 | /* | 917 | /** |
911 | * i7300_put_devices 'put' all the devices that we have | 918 | * i7300_put_devices() - Release the PCI devices |
912 | * reserved via 'get' | 919 | * @mci: struct mem_ctl_info pointer |
913 | */ | 920 | */ |
914 | static void i7300_put_devices(struct mem_ctl_info *mci) | 921 | static void i7300_put_devices(struct mem_ctl_info *mci) |
915 | { | 922 | { |
@@ -925,13 +932,18 @@ static void i7300_put_devices(struct mem_ctl_info *mci) | |||
925 | pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map); | 932 | pci_dev_put(pvt->pci_dev_16_1_fsb_addr_map); |
926 | } | 933 | } |
927 | 934 | ||
928 | /* | 935 | /** |
929 | * i7300_get_devices Find and perform 'get' operation on the MCH's | 936 | * i7300_get_devices() - Find and perform 'get' operation on the MCH's |
930 | * device/functions we want to reference for this driver | 937 | * device/functions we want to reference for this driver |
938 | * @mci: struct mem_ctl_info pointer | ||
931 | * | 939 | * |
932 | * Need to 'get' device 16 func 1 and func 2 | 940 | * Access and prepare the several devices for usage: |
941 | * I7300 devices used by this driver: | ||
942 | * Device 16, functions 0,1 and 2: PCI_DEVICE_ID_INTEL_I7300_MCH_ERR | ||
943 | * Device 21 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB0 | ||
944 | * Device 22 function 0: PCI_DEVICE_ID_INTEL_I7300_MCH_FB1 | ||
933 | */ | 945 | */ |
934 | static int i7300_get_devices(struct mem_ctl_info *mci, int dev_idx) | 946 | static int __devinit i7300_get_devices(struct mem_ctl_info *mci) |
935 | { | 947 | { |
936 | struct i7300_pvt *pvt; | 948 | struct i7300_pvt *pvt; |
937 | struct pci_dev *pdev; | 949 | struct pci_dev *pdev; |
@@ -1007,23 +1019,25 @@ error: | |||
1007 | return -ENODEV; | 1019 | return -ENODEV; |
1008 | } | 1020 | } |
1009 | 1021 | ||
1010 | /* | 1022 | /** |
1011 | * i7300_probe1 Probe for ONE instance of device to see if it is | 1023 | * i7300_init_one() - Probe for one instance of the device |
1012 | * present. | 1024 | * @pdev: struct pci_dev pointer |
1013 | * return: | 1025 | * @id: struct pci_device_id pointer - currently unused |
1014 | * 0 for FOUND a device | ||
1015 | * < 0 for error code | ||
1016 | */ | 1026 | */ |
1017 | static int i7300_probe1(struct pci_dev *pdev, int dev_idx) | 1027 | static int __devinit i7300_init_one(struct pci_dev *pdev, |
1028 | const struct pci_device_id *id) | ||
1018 | { | 1029 | { |
1019 | struct mem_ctl_info *mci; | 1030 | struct mem_ctl_info *mci; |
1020 | struct i7300_pvt *pvt; | 1031 | struct i7300_pvt *pvt; |
1021 | int num_channels; | 1032 | int num_channels; |
1022 | int num_dimms_per_channel; | 1033 | int num_dimms_per_channel; |
1023 | int num_csrows; | 1034 | int num_csrows; |
1035 | int rc; | ||
1024 | 1036 | ||
1025 | if (dev_idx >= ARRAY_SIZE(i7300_devs)) | 1037 | /* wake up device */ |
1026 | return -EINVAL; | 1038 | rc = pci_enable_device(pdev); |
1039 | if (rc == -EIO) | ||
1040 | return rc; | ||
1027 | 1041 | ||
1028 | debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", | 1042 | debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", |
1029 | __func__, | 1043 | __func__, |
@@ -1068,7 +1082,7 @@ static int i7300_probe1(struct pci_dev *pdev, int dev_idx) | |||
1068 | } | 1082 | } |
1069 | 1083 | ||
1070 | /* 'get' the pci devices we want to reserve for our use */ | 1084 | /* 'get' the pci devices we want to reserve for our use */ |
1071 | if (i7300_get_devices(mci, dev_idx)) | 1085 | if (i7300_get_devices(mci)) |
1072 | goto fail0; | 1086 | goto fail0; |
1073 | 1087 | ||
1074 | mci->mc_idx = 0; | 1088 | mci->mc_idx = 0; |
@@ -1077,7 +1091,7 @@ static int i7300_probe1(struct pci_dev *pdev, int dev_idx) | |||
1077 | mci->edac_cap = EDAC_FLAG_NONE; | 1091 | mci->edac_cap = EDAC_FLAG_NONE; |
1078 | mci->mod_name = "i7300_edac.c"; | 1092 | mci->mod_name = "i7300_edac.c"; |
1079 | mci->mod_ver = I7300_REVISION; | 1093 | mci->mod_ver = I7300_REVISION; |
1080 | mci->ctl_name = i7300_devs[dev_idx].ctl_name; | 1094 | mci->ctl_name = i7300_devs[0].ctl_name; |
1081 | mci->dev_name = pci_name(pdev); | 1095 | mci->dev_name = pci_name(pdev); |
1082 | mci->ctl_page_to_phys = NULL; | 1096 | mci->ctl_page_to_phys = NULL; |
1083 | 1097 | ||
@@ -1132,32 +1146,9 @@ fail0: | |||
1132 | return -ENODEV; | 1146 | return -ENODEV; |
1133 | } | 1147 | } |
1134 | 1148 | ||
1135 | /* | 1149 | /** |
1136 | * i7300_init_one constructor for one instance of device | 1150 | * i7300_remove_one() - Remove the driver |
1137 | * | 1151 | * @pdev: struct pci_dev pointer |
1138 | * returns: | ||
1139 | * negative on error | ||
1140 | * count (>= 0) | ||
1141 | */ | ||
1142 | static int __devinit i7300_init_one(struct pci_dev *pdev, | ||
1143 | const struct pci_device_id *id) | ||
1144 | { | ||
1145 | int rc; | ||
1146 | |||
1147 | debugf0("MC: " __FILE__ ": %s()\n", __func__); | ||
1148 | |||
1149 | /* wake up device */ | ||
1150 | rc = pci_enable_device(pdev); | ||
1151 | if (rc == -EIO) | ||
1152 | return rc; | ||
1153 | |||
1154 | /* now probe and enable the device */ | ||
1155 | return i7300_probe1(pdev, id->driver_data); | ||
1156 | } | ||
1157 | |||
1158 | /* | ||
1159 | * i7300_remove_one destructor for one instance of device | ||
1160 | * | ||
1161 | */ | 1152 | */ |
1162 | static void __devexit i7300_remove_one(struct pci_dev *pdev) | 1153 | static void __devexit i7300_remove_one(struct pci_dev *pdev) |
1163 | { | 1154 | { |
@@ -1183,9 +1174,9 @@ static void __devexit i7300_remove_one(struct pci_dev *pdev) | |||
1183 | } | 1174 | } |
1184 | 1175 | ||
1185 | /* | 1176 | /* |
1186 | * pci_device_id table for which devices we are looking for | 1177 | * pci_device_id: table for which devices we are looking for |
1187 | * | 1178 | * |
1188 | * The "E500P" device is the first device supported. | 1179 | * Has only 8086:360c PCI ID |
1189 | */ | 1180 | */ |
1190 | static const struct pci_device_id i7300_pci_tbl[] __devinitdata = { | 1181 | static const struct pci_device_id i7300_pci_tbl[] __devinitdata = { |
1191 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)}, | 1182 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7300_MCH_ERR)}, |
@@ -1195,8 +1186,7 @@ static const struct pci_device_id i7300_pci_tbl[] __devinitdata = { | |||
1195 | MODULE_DEVICE_TABLE(pci, i7300_pci_tbl); | 1186 | MODULE_DEVICE_TABLE(pci, i7300_pci_tbl); |
1196 | 1187 | ||
1197 | /* | 1188 | /* |
1198 | * i7300_driver pci_driver structure for this module | 1189 | * i7300_driver: pci_driver structure for this module |
1199 | * | ||
1200 | */ | 1190 | */ |
1201 | static struct pci_driver i7300_driver = { | 1191 | static struct pci_driver i7300_driver = { |
1202 | .name = "i7300_edac", | 1192 | .name = "i7300_edac", |
@@ -1205,9 +1195,8 @@ static struct pci_driver i7300_driver = { | |||
1205 | .id_table = i7300_pci_tbl, | 1195 | .id_table = i7300_pci_tbl, |
1206 | }; | 1196 | }; |
1207 | 1197 | ||
1208 | /* | 1198 | /** |
1209 | * i7300_init Module entry function | 1199 | * i7300_init() - Registers the driver |
1210 | * Try to initialize this module for its devices | ||
1211 | */ | 1200 | */ |
1212 | static int __init i7300_init(void) | 1201 | static int __init i7300_init(void) |
1213 | { | 1202 | { |
@@ -1223,9 +1212,8 @@ static int __init i7300_init(void) | |||
1223 | return (pci_rc < 0) ? pci_rc : 0; | 1212 | return (pci_rc < 0) ? pci_rc : 0; |
1224 | } | 1213 | } |
1225 | 1214 | ||
1226 | /* | 1215 | /** |
1227 | * i7300_exit() Module exit function | 1216 | * i7300_init() - Unregisters the driver |
1228 | * Unregister the driver | ||
1229 | */ | 1217 | */ |
1230 | static void __exit i7300_exit(void) | 1218 | static void __exit i7300_exit(void) |
1231 | { | 1219 | { |