aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/edac
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/i7core_edac.c199
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 */
270static inline int maxnumdimms(struct i7core_pvt *pvt) 271static 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 ****************************************************************************/
312static 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
311static int get_dimm_config(struct mem_ctl_info *mci) 354static 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 */
855static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) 898static 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
956error:
957 i7core_put_devices();
958 return -EINVAL;
959}
960
961static 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
990error:
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