diff options
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/i7core_edac.c | 199 |
1 files changed, 139 insertions, 60 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b5dbc2b83961..bfa462f6fa0e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c | |||
@@ -189,6 +189,7 @@ struct i7core_pvt { | |||
189 | struct i7core_info info; | 189 | struct i7core_info info; |
190 | struct i7core_inject inject; | 190 | struct i7core_inject inject; |
191 | struct i7core_channel channel[NUM_CHANS]; | 191 | struct i7core_channel channel[NUM_CHANS]; |
192 | int channels; /* Number of active channels */ | ||
192 | 193 | ||
193 | int ce_count_available; | 194 | int ce_count_available; |
194 | unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ | 195 | unsigned long ce_count[MAX_DIMMS]; /* ECC corrected errors counts per dimm */ |
@@ -259,12 +260,12 @@ static struct edac_pci_ctl_info *i7core_pci; | |||
259 | ****************************************************************************/ | 260 | ****************************************************************************/ |
260 | 261 | ||
261 | /* MC_CONTROL bits */ | 262 | /* MC_CONTROL bits */ |
262 | #define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & 1 << (8 + ch)) | 263 | #define CH_ACTIVE(pvt, ch) ((pvt)->info.mc_control & (1 << (8 + ch))) |
263 | #define ECCx8(pvt) ((pvt)->info.mc_control & 1 << 1) | 264 | #define ECCx8(pvt) ((pvt)->info.mc_control & (1 << 1)) |
264 | 265 | ||
265 | /* MC_STATUS bits */ | 266 | /* MC_STATUS bits */ |
266 | #define ECC_ENABLED(pvt) ((pvt)->info.mc_status & 1 << 3) | 267 | #define ECC_ENABLED(pvt) ((pvt)->info.mc_status & (1 << 3)) |
267 | #define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & 1 << ch) | 268 | #define CH_DISABLED(pvt, ch) ((pvt)->info.mc_status & (1 << ch)) |
268 | 269 | ||
269 | /* MC_MAX_DOD read functions */ | 270 | /* MC_MAX_DOD read functions */ |
270 | static inline int maxnumdimms(struct i7core_pvt *pvt) | 271 | static inline int maxnumdimms(struct i7core_pvt *pvt) |
@@ -308,6 +309,48 @@ static inline int maxnumcol(struct i7core_pvt *pvt) | |||
308 | /**************************************************************************** | 309 | /**************************************************************************** |
309 | Memory check routines | 310 | Memory check routines |
310 | ****************************************************************************/ | 311 | ****************************************************************************/ |
312 | static int i7core_get_active_channels(int *channels) | ||
313 | { | ||
314 | struct pci_dev *pdev = NULL; | ||
315 | int i; | ||
316 | u32 status, control; | ||
317 | |||
318 | *channels = 0; | ||
319 | |||
320 | for (i = 0; i < N_DEVS; i++) { | ||
321 | if (!pci_devs[i].pdev) | ||
322 | continue; | ||
323 | |||
324 | if (PCI_SLOT(pci_devs[i].pdev->devfn) == 3 && | ||
325 | PCI_FUNC(pci_devs[i].pdev->devfn) == 0) { | ||
326 | pdev = pci_devs[i].pdev; | ||
327 | break; | ||
328 | } | ||
329 | } | ||
330 | |||
331 | if (!pdev) | ||
332 | return -ENODEV; | ||
333 | |||
334 | /* Device 3 function 0 reads */ | ||
335 | pci_read_config_dword(pdev, MC_STATUS, &status); | ||
336 | pci_read_config_dword(pdev, MC_CONTROL, &control); | ||
337 | |||
338 | for (i = 0; i < NUM_CHANS; i++) { | ||
339 | /* Check if the channel is active */ | ||
340 | if (!(control & (1 << (8 + i)))) | ||
341 | continue; | ||
342 | |||
343 | /* Check if the channel is disabled */ | ||
344 | if (status & (1 << i)) { | ||
345 | continue; | ||
346 | } | ||
347 | |||
348 | (*channels)++; | ||
349 | } | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
311 | static int get_dimm_config(struct mem_ctl_info *mci) | 354 | static int get_dimm_config(struct mem_ctl_info *mci) |
312 | { | 355 | { |
313 | struct i7core_pvt *pvt = mci->pvt_info; | 356 | struct i7core_pvt *pvt = mci->pvt_info; |
@@ -852,69 +895,103 @@ static void i7core_put_devices(void) | |||
852 | * | 895 | * |
853 | * Need to 'get' device 16 func 1 and func 2 | 896 | * Need to 'get' device 16 func 1 and func 2 |
854 | */ | 897 | */ |
855 | static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) | 898 | static int i7core_get_devices(void) |
856 | { | 899 | { |
857 | struct i7core_pvt *pvt = mci->pvt_info; | 900 | int rc, i; |
858 | int rc, i,func; | ||
859 | struct pci_dev *pdev = NULL; | 901 | struct pci_dev *pdev = NULL; |
860 | 902 | ||
861 | pvt = mci->pvt_info; | ||
862 | memset(pvt, 0, sizeof(*pvt)); | ||
863 | |||
864 | for (i = 0; i < N_DEVS; i++) { | 903 | for (i = 0; i < N_DEVS; i++) { |
865 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | 904 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
866 | pci_devs[i].dev_id, NULL); | 905 | pci_devs[i].dev_id, NULL); |
867 | if (!pdev) { | 906 | if (likely(pdev)) |
868 | /* End of list, leave */ | 907 | pci_devs[i].pdev = pdev; |
908 | else { | ||
869 | i7core_printk(KERN_ERR, | 909 | i7core_printk(KERN_ERR, |
870 | "Device not found: PCI ID %04x:%04x " | 910 | "Device not found: PCI ID %04x:%04x " |
871 | "(dev %d, func %d)\n", | 911 | "(dev %d, func %d)\n", |
872 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, | 912 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, |
873 | pci_devs[i].dev,pci_devs[i].func); | 913 | pci_devs[i].dev,pci_devs[i].func); |
914 | |||
915 | /* Dev 3 function 2 only exists on chips with RDIMMs */ | ||
874 | if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) | 916 | if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) |
875 | continue; /* Only on chips with RDIMMs */ | 917 | continue; |
876 | else | 918 | |
877 | i7core_put_devices(); | 919 | /* End of list, leave */ |
920 | rc = -ENODEV; | ||
921 | goto error; | ||
878 | } | 922 | } |
879 | pci_devs[i].pdev = pdev; | ||
880 | 923 | ||
881 | rc = pci_enable_device(pdev); | 924 | /* Sanity check */ |
882 | if (rc < 0) { | 925 | if (unlikely(PCI_SLOT(pdev->devfn) != pci_devs[i].dev || |
926 | PCI_FUNC(pdev->devfn) != pci_devs[i].func)) { | ||
883 | i7core_printk(KERN_ERR, | 927 | i7core_printk(KERN_ERR, |
884 | "Couldn't enable PCI ID %04x:%04x " | 928 | "Device PCI ID %04x:%04x " |
885 | "(dev %d, func %d)\n", | 929 | "has fn %d.%d instead of fn %d.%d\n", |
886 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, | 930 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, |
931 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), | ||
887 | pci_devs[i].dev, pci_devs[i].func); | 932 | pci_devs[i].dev, pci_devs[i].func); |
888 | i7core_put_devices(); | 933 | rc = -EINVAL; |
889 | return rc; | 934 | goto error; |
890 | } | 935 | } |
891 | /* Sanity check */ | 936 | |
892 | if (PCI_FUNC(pdev->devfn) != pci_devs[i].func) { | 937 | /* Be sure that the device is enabled */ |
938 | rc = pci_enable_device(pdev); | ||
939 | if (unlikely(rc < 0)) { | ||
893 | i7core_printk(KERN_ERR, | 940 | i7core_printk(KERN_ERR, |
894 | "Device PCI ID %04x:%04x " | 941 | "Couldn't enable PCI ID %04x:%04x " |
895 | "has function %d instead of %d\n", | 942 | "fn %d.%d\n", |
896 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, | 943 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, |
897 | PCI_FUNC(pdev->devfn), pci_devs[i].func); | 944 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); |
898 | i7core_put_devices(); | 945 | goto error; |
899 | return -EINVAL; | ||
900 | } | 946 | } |
901 | 947 | ||
902 | i7core_printk(KERN_INFO, | 948 | i7core_printk(KERN_INFO, |
903 | "Registered device %0x:%0x fn=%0x %0x\n", | 949 | "Registered device %0x:%0x fn %d.%d\n", |
904 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, | 950 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, |
905 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); | 951 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); |
952 | } | ||
953 | |||
954 | return 0; | ||
955 | |||
956 | error: | ||
957 | i7core_put_devices(); | ||
958 | return -EINVAL; | ||
959 | } | ||
960 | |||
961 | static int mci_bind_devs(struct mem_ctl_info *mci) | ||
962 | { | ||
963 | struct i7core_pvt *pvt = mci->pvt_info; | ||
964 | struct pci_dev *pdev; | ||
965 | int i, func, slot; | ||
966 | |||
967 | for (i = 0; i < N_DEVS; i++) { | ||
968 | pdev = pci_devs[i].pdev; | ||
969 | if (!pdev) | ||
970 | continue; | ||
906 | 971 | ||
907 | func = PCI_FUNC(pdev->devfn); | 972 | func = PCI_FUNC(pdev->devfn); |
908 | if (pci_devs[i].dev < 4) { | 973 | slot = PCI_SLOT(pdev->devfn); |
974 | if (slot == 3) { | ||
975 | if (unlikely(func > MAX_MCR_FUNC)) | ||
976 | goto error; | ||
909 | pvt->pci_mcr[func] = pdev; | 977 | pvt->pci_mcr[func] = pdev; |
910 | } else { | 978 | } else if (likely(slot >= 4 && slot < 4 + NUM_CHANS)) { |
911 | pvt->pci_ch[pci_devs[i].dev - 4][func] = pdev; | 979 | if (unlikely(func > MAX_CHAN_FUNC)) |
912 | } | 980 | goto error; |
981 | pvt->pci_ch[slot - 4][func] = pdev; | ||
982 | } else | ||
983 | goto error; | ||
984 | |||
985 | debugf0("Associated fn %d.%d, dev = %p\n", | ||
986 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn), pdev); | ||
913 | } | 987 | } |
914 | |||
915 | i7core_printk(KERN_INFO, "Driver loaded.\n"); | ||
916 | |||
917 | return 0; | 988 | return 0; |
989 | |||
990 | error: | ||
991 | i7core_printk(KERN_ERR, "Device %d, function %d " | ||
992 | "is out of the expected range\n", | ||
993 | slot, func); | ||
994 | return -EINVAL; | ||
918 | } | 995 | } |
919 | 996 | ||
920 | /**************************************************************************** | 997 | /**************************************************************************** |
@@ -1001,41 +1078,38 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1001 | { | 1078 | { |
1002 | struct mem_ctl_info *mci; | 1079 | struct mem_ctl_info *mci; |
1003 | struct i7core_pvt *pvt; | 1080 | struct i7core_pvt *pvt; |
1004 | int num_channels; | 1081 | int num_channels = 0; |
1005 | int num_csrows; | 1082 | int num_csrows; |
1006 | int num_dimms_per_channel; | ||
1007 | int dev_idx = id->driver_data; | 1083 | int dev_idx = id->driver_data; |
1008 | 1084 | ||
1009 | if (dev_idx >= ARRAY_SIZE(i7core_devs)) | 1085 | if (unlikely(dev_idx >= ARRAY_SIZE(i7core_devs))) |
1010 | return -EINVAL; | 1086 | return -EINVAL; |
1011 | 1087 | ||
1012 | num_channels = NUM_CHANS; | 1088 | /* get the pci devices we want to reserve for our use */ |
1089 | if (unlikely(i7core_get_devices() < 0)) | ||
1090 | return -ENODEV; | ||
1091 | |||
1092 | /* Check the number of active and not disabled channels */ | ||
1093 | if (unlikely (i7core_get_active_channels(&num_channels)) < 0) | ||
1094 | goto fail0; | ||
1013 | 1095 | ||
1014 | /* FIXME: FAKE data, since we currently don't now how to get this */ | 1096 | /* FIXME: we currently don't know the number of csrows */ |
1015 | num_dimms_per_channel = 4; | 1097 | num_csrows = num_channels; |
1016 | num_csrows = num_dimms_per_channel; | ||
1017 | 1098 | ||
1018 | /* allocate a new MC control structure */ | 1099 | /* allocate a new MC control structure */ |
1019 | mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); | 1100 | mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, 0); |
1020 | if (mci == NULL) | 1101 | if (unlikely (!mci)) |
1021 | return -ENOMEM; | 1102 | return -ENOMEM; |
1022 | 1103 | ||
1023 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); | 1104 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); |
1024 | 1105 | ||
1025 | /* 'get' the pci devices we want to reserve for our use */ | ||
1026 | if (i7core_get_devices(mci, pdev)) | ||
1027 | goto fail0; | ||
1028 | |||
1029 | mci->dev = &pdev->dev; /* record ptr to the generic device */ | 1106 | mci->dev = &pdev->dev; /* record ptr to the generic device */ |
1030 | 1107 | ||
1031 | pvt = mci->pvt_info; | 1108 | pvt = mci->pvt_info; |
1032 | 1109 | memset(pvt, 0, sizeof(*pvt)); | |
1033 | // pvt->system_address = pdev; /* Record this device in our private */ | ||
1034 | // pvt->maxch = num_channels; | ||
1035 | // pvt->maxdimmperch = num_dimms_per_channel; | ||
1036 | 1110 | ||
1037 | mci->mc_idx = 0; | 1111 | mci->mc_idx = 0; |
1038 | mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ | 1112 | mci->mtype_cap = MEM_FLAG_DDR3; /* FIXME: how to handle RDDR3? */ |
1039 | mci->edac_ctl_cap = EDAC_FLAG_NONE; | 1113 | mci->edac_ctl_cap = EDAC_FLAG_NONE; |
1040 | mci->edac_cap = EDAC_FLAG_NONE; | 1114 | mci->edac_cap = EDAC_FLAG_NONE; |
1041 | mci->mod_name = "i7core_edac.c"; | 1115 | mci->mod_name = "i7core_edac.c"; |
@@ -1044,12 +1118,18 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1044 | mci->dev_name = pci_name(pdev); | 1118 | mci->dev_name = pci_name(pdev); |
1045 | mci->ctl_page_to_phys = NULL; | 1119 | mci->ctl_page_to_phys = NULL; |
1046 | mci->mc_driver_sysfs_attributes = i7core_inj_attrs; | 1120 | mci->mc_driver_sysfs_attributes = i7core_inj_attrs; |
1047 | |||
1048 | /* Set the function pointer to an actual operation function */ | 1121 | /* Set the function pointer to an actual operation function */ |
1049 | mci->edac_check = i7core_check_error; | 1122 | mci->edac_check = i7core_check_error; |
1050 | 1123 | ||
1124 | /* Store pci devices at mci for faster access */ | ||
1125 | if (unlikely (mci_bind_devs(mci)) < 0) | ||
1126 | goto fail1; | ||
1127 | |||
1128 | /* Get dimm basic config */ | ||
1129 | get_dimm_config(mci); | ||
1130 | |||
1051 | /* add this new MC control structure to EDAC's list of MCs */ | 1131 | /* add this new MC control structure to EDAC's list of MCs */ |
1052 | if (edac_mc_add_mc(mci)) { | 1132 | if (unlikely(edac_mc_add_mc(mci)) < 0) { |
1053 | debugf0("MC: " __FILE__ | 1133 | debugf0("MC: " __FILE__ |
1054 | ": %s(): failed edac_mc_add_mc()\n", __func__); | 1134 | ": %s(): failed edac_mc_add_mc()\n", __func__); |
1055 | /* FIXME: perhaps some code should go here that disables error | 1135 | /* FIXME: perhaps some code should go here that disables error |
@@ -1060,7 +1140,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1060 | 1140 | ||
1061 | /* allocating generic PCI control info */ | 1141 | /* allocating generic PCI control info */ |
1062 | i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); | 1142 | i7core_pci = edac_pci_create_generic_ctl(&pdev->dev, EDAC_MOD_STR); |
1063 | if (!i7core_pci) { | 1143 | if (unlikely (!i7core_pci)) { |
1064 | printk(KERN_WARNING | 1144 | printk(KERN_WARNING |
1065 | "%s(): Unable to create PCI control\n", | 1145 | "%s(): Unable to create PCI control\n", |
1066 | __func__); | 1146 | __func__); |
@@ -1070,15 +1150,14 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1070 | } | 1150 | } |
1071 | 1151 | ||
1072 | /* Default error mask is any memory */ | 1152 | /* Default error mask is any memory */ |
1073 | pvt->inject.channel = -1; | 1153 | pvt->inject.channel = 0; |
1074 | pvt->inject.dimm = -1; | 1154 | pvt->inject.dimm = -1; |
1075 | pvt->inject.rank = -1; | 1155 | pvt->inject.rank = -1; |
1076 | pvt->inject.bank = -1; | 1156 | pvt->inject.bank = -1; |
1077 | pvt->inject.page = -1; | 1157 | pvt->inject.page = -1; |
1078 | pvt->inject.col = -1; | 1158 | pvt->inject.col = -1; |
1079 | 1159 | ||
1080 | /* Get dimm basic config */ | 1160 | i7core_printk(KERN_INFO, "Driver loaded.\n"); |
1081 | get_dimm_config(mci); | ||
1082 | 1161 | ||
1083 | return 0; | 1162 | return 0; |
1084 | 1163 | ||