diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2009-06-22 21:48:29 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2010-05-10 10:44:45 -0400 |
commit | 8f331907578623f90a134261a559fa3249142caa (patch) | |
tree | dc73b3736a8214f2bafcbfea0edd9ed96e140505 | |
parent | 0b2b7b7ec06ce615acd11374bf9a512e166dabb0 (diff) |
i7core_edac: Registers all supported MC functions
Now, it will try to register on all supported Memory Controller
functions.
It should be noticed that dev3, function 2 is present only on chips with
Registered DIMM's, according to the datasheet. So, the driver doesn't
return -ENODEV is all functions but this one were successfully
registered and enabled:
EDAC i7core: Registered device 8086:2c18 fn=3 0
EDAC i7core: Registered device 8086:2c19 fn=3 1
EDAC i7core: Device not found: PCI ID 8086:2c1a (dev 3, func 2)
EDAC i7core: Registered device 8086:2c1c fn=3 4
EDAC i7core: Registered device 8086:2c20 fn=4 0
EDAC i7core: Registered device 8086:2c21 fn=4 1
EDAC i7core: Registered device 8086:2c22 fn=4 2
EDAC i7core: Registered device 8086:2c23 fn=4 3
EDAC i7core: Registered device 8086:2c28 fn=5 0
EDAC i7core: Registered device 8086:2c29 fn=5 1
EDAC i7core: Registered device 8086:2c2a fn=5 2
EDAC i7core: Registered device 8086:2c2b fn=5 3
EDAC i7core: Registered device 8086:2c30 fn=6 0
EDAC i7core: Registered device 8086:2c31 fn=6 1
EDAC i7core: Registered device 8086:2c32 fn=6 2
EDAC i7core: Registered device 8086:2c33 fn=6 3
EDAC i7core: Driver loaded.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r-- | drivers/edac/i7core_edac.c | 217 |
1 files changed, 131 insertions, 86 deletions
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index da40730bf9c..79aa84eaa12 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c | |||
@@ -128,7 +128,8 @@ | |||
128 | */ | 128 | */ |
129 | 129 | ||
130 | #define NUM_CHANS 3 | 130 | #define NUM_CHANS 3 |
131 | #define NUM_FUNCS 1 | 131 | #define NUM_MCR_FUNCS 4 |
132 | #define NUM_CHAN_FUNCS 3 | ||
132 | 133 | ||
133 | struct i7core_info { | 134 | struct i7core_info { |
134 | u32 mc_control; | 135 | u32 mc_control; |
@@ -153,9 +154,16 @@ struct i7core_channel { | |||
153 | u32 dimms; | 154 | u32 dimms; |
154 | }; | 155 | }; |
155 | 156 | ||
157 | struct pci_id_descr { | ||
158 | int dev; | ||
159 | int func; | ||
160 | int dev_id; | ||
161 | struct pci_dev *pdev; | ||
162 | }; | ||
163 | |||
156 | struct i7core_pvt { | 164 | struct i7core_pvt { |
157 | struct pci_dev *pci_mcr; /* Dev 3:0 */ | 165 | struct pci_dev *pci_mcr[NUM_MCR_FUNCS]; |
158 | struct pci_dev *pci_ch[NUM_CHANS][NUM_FUNCS]; | 166 | struct pci_dev *pci_ch[NUM_CHANS][NUM_CHAN_FUNCS]; |
159 | struct i7core_info info; | 167 | struct i7core_info info; |
160 | struct i7core_inject inject; | 168 | struct i7core_inject inject; |
161 | struct i7core_channel channel[NUM_CHANS]; | 169 | struct i7core_channel channel[NUM_CHANS]; |
@@ -167,11 +175,47 @@ struct i7core_dev_info { | |||
167 | u16 fsb_mapping_errors; /* DID for the branchmap,control */ | 175 | u16 fsb_mapping_errors; /* DID for the branchmap,control */ |
168 | }; | 176 | }; |
169 | 177 | ||
170 | static int chan_pci_ids[NUM_CHANS] = { | 178 | #define PCI_DESCR(device, function, device_id) \ |
171 | PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL, /* Dev 4 */ | 179 | .dev = (device), \ |
172 | PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL, /* Dev 5 */ | 180 | .func = (function), \ |
173 | PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL, /* Dev 6 */ | 181 | .dev_id = (device_id) |
182 | |||
183 | struct pci_id_descr pci_devs[] = { | ||
184 | /* Memory controller */ | ||
185 | { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, | ||
186 | { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, | ||
187 | { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS) }, /* if RDIMM is supported */ | ||
188 | { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, | ||
189 | |||
190 | /* Channel 0 */ | ||
191 | { PCI_DESCR(4, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH0_CTRL) }, | ||
192 | { PCI_DESCR(4, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH0_ADDR) }, | ||
193 | { PCI_DESCR(4, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH0_RANK) }, | ||
194 | { PCI_DESCR(4, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH0_TC) }, | ||
195 | |||
196 | /* Channel 1 */ | ||
197 | { PCI_DESCR(5, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH1_CTRL) }, | ||
198 | { PCI_DESCR(5, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH1_ADDR) }, | ||
199 | { PCI_DESCR(5, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH1_RANK) }, | ||
200 | { PCI_DESCR(5, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH1_TC) }, | ||
201 | |||
202 | /* Channel 2 */ | ||
203 | { PCI_DESCR(6, 0, PCI_DEVICE_ID_INTEL_I7_MC_CH2_CTRL) }, | ||
204 | { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, | ||
205 | { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, | ||
206 | { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, | ||
174 | }; | 207 | }; |
208 | #define N_DEVS ARRAY_SIZE(pci_devs) | ||
209 | |||
210 | /* | ||
211 | * pci_device_id table for which devices we are looking for | ||
212 | * This should match the first device at pci_devs table | ||
213 | */ | ||
214 | static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { | ||
215 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, | ||
216 | {0,} /* 0 terminated list. */ | ||
217 | }; | ||
218 | |||
175 | 219 | ||
176 | /* Table of devices attributes supported by this driver */ | 220 | /* Table of devices attributes supported by this driver */ |
177 | static const struct i7core_dev_info i7core_devs[] = { | 221 | static const struct i7core_dev_info i7core_devs[] = { |
@@ -242,9 +286,12 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
242 | struct i7core_pvt *pvt = mci->pvt_info; | 286 | struct i7core_pvt *pvt = mci->pvt_info; |
243 | int i; | 287 | int i; |
244 | 288 | ||
245 | pci_read_config_dword(pvt->pci_mcr, MC_CONTROL, &pvt->info.mc_control); | 289 | if (!pvt->pci_mcr[0]) |
246 | pci_read_config_dword(pvt->pci_mcr, MC_STATUS, &pvt->info.mc_status); | 290 | return -ENODEV; |
247 | pci_read_config_dword(pvt->pci_mcr, MC_MAX_DOD, &pvt->info.max_dod); | 291 | |
292 | pci_read_config_dword(pvt->pci_mcr[0], MC_CONTROL, &pvt->info.mc_control); | ||
293 | pci_read_config_dword(pvt->pci_mcr[0], MC_STATUS, &pvt->info.mc_status); | ||
294 | pci_read_config_dword(pvt->pci_mcr[0], MC_MAX_DOD, &pvt->info.max_dod); | ||
248 | 295 | ||
249 | if (ECC_ENABLED(pvt)) | 296 | if (ECC_ENABLED(pvt)) |
250 | debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); | 297 | debugf0("ECC enabled with x%d SDCC\n", ECCx8(pvt)?8:4); |
@@ -303,14 +350,19 @@ static int get_dimm_config(struct mem_ctl_info *mci) | |||
303 | we're disabling error injection on all write calls to the sysfs nodes that | 350 | we're disabling error injection on all write calls to the sysfs nodes that |
304 | controls the error code injection. | 351 | controls the error code injection. |
305 | */ | 352 | */ |
306 | static void disable_inject(struct mem_ctl_info *mci) | 353 | static int disable_inject(struct mem_ctl_info *mci) |
307 | { | 354 | { |
308 | struct i7core_pvt *pvt = mci->pvt_info; | 355 | struct i7core_pvt *pvt = mci->pvt_info; |
309 | 356 | ||
310 | pvt->inject.enable = 0; | 357 | pvt->inject.enable = 0; |
311 | 358 | ||
359 | if (!pvt->pci_ch[pvt->inject.channel][0]) | ||
360 | return -ENODEV; | ||
361 | |||
312 | pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], | 362 | pci_write_config_dword(pvt->pci_ch[pvt->inject.channel][0], |
313 | MC_CHANNEL_ERROR_MASK, 0); | 363 | MC_CHANNEL_ERROR_MASK, 0); |
364 | |||
365 | return 0; | ||
314 | } | 366 | } |
315 | 367 | ||
316 | /* | 368 | /* |
@@ -550,6 +602,9 @@ static ssize_t i7core_inject_enable_store(struct mem_ctl_info *mci, | |||
550 | int rc; | 602 | int rc; |
551 | long enable; | 603 | long enable; |
552 | 604 | ||
605 | if (!pvt->pci_ch[pvt->inject.channel][0]) | ||
606 | return 0; | ||
607 | |||
553 | rc = strict_strtoul(data, 10, &enable); | 608 | rc = strict_strtoul(data, 10, &enable); |
554 | if ((rc < 0)) | 609 | if ((rc < 0)) |
555 | return 0; | 610 | return 0; |
@@ -684,17 +739,12 @@ static struct mcidev_sysfs_attribute i7core_inj_attrs[] = { | |||
684 | * i7core_put_devices 'put' all the devices that we have | 739 | * i7core_put_devices 'put' all the devices that we have |
685 | * reserved via 'get' | 740 | * reserved via 'get' |
686 | */ | 741 | */ |
687 | static void i7core_put_devices(struct mem_ctl_info *mci) | 742 | static void i7core_put_devices(void) |
688 | { | 743 | { |
689 | struct i7core_pvt *pvt = mci->pvt_info; | 744 | int i; |
690 | int i, n; | ||
691 | |||
692 | pci_dev_put(pvt->pci_mcr); | ||
693 | 745 | ||
694 | /* Release all PCI device functions at MTR channel controllers */ | 746 | for (i = 0; i < N_DEVS; i++) |
695 | for (i = 0; i < NUM_CHANS; i++) | 747 | pci_dev_put(pci_devs[i].pdev); |
696 | for (n = 0; n < NUM_FUNCS; n++) | ||
697 | pci_dev_put(pvt->pci_ch[i][n]); | ||
698 | } | 748 | } |
699 | 749 | ||
700 | /* | 750 | /* |
@@ -703,50 +753,67 @@ static void i7core_put_devices(struct mem_ctl_info *mci) | |||
703 | * | 753 | * |
704 | * Need to 'get' device 16 func 1 and func 2 | 754 | * Need to 'get' device 16 func 1 and func 2 |
705 | */ | 755 | */ |
706 | static int i7core_get_devices(struct mem_ctl_info *mci, int dev_idx) | 756 | static int i7core_get_devices(struct mem_ctl_info *mci, struct pci_dev *mcidev) |
707 | { | 757 | { |
708 | struct i7core_pvt *pvt; | 758 | struct i7core_pvt *pvt = mci->pvt_info; |
709 | struct pci_dev *pdev; | 759 | int rc, i,func; |
710 | int i, n, func; | 760 | struct pci_dev *pdev = NULL; |
711 | 761 | ||
712 | pvt = mci->pvt_info; | 762 | pvt = mci->pvt_info; |
713 | memset(pvt, 0, sizeof(*pvt)); | 763 | memset(pvt, 0, sizeof(*pvt)); |
714 | 764 | ||
715 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR, | 765 | for (i = 0; i < N_DEVS; i++) { |
716 | NULL); | 766 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
717 | if (!pdev) { | 767 | pci_devs[i].dev_id, NULL); |
718 | i7core_printk(KERN_ERR, | 768 | if (!pdev) { |
719 | "Couldn't get PCI ID %04x:%04x function 0\n", | 769 | /* End of list, leave */ |
720 | PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR); | 770 | i7core_printk(KERN_ERR, |
721 | return -ENODEV; | 771 | "Device not found: PCI ID %04x:%04x " |
722 | } | 772 | "(dev %d, func %d)\n", |
723 | pvt->pci_mcr=pdev; | 773 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, |
774 | pci_devs[i].dev,pci_devs[i].func); | ||
775 | if ((pci_devs[i].dev == 3) && (pci_devs[i].func == 2)) | ||
776 | continue; /* Only on chips with RDIMMs */ | ||
777 | else | ||
778 | i7core_put_devices(); | ||
779 | } | ||
780 | pci_devs[i].pdev = pdev; | ||
781 | |||
782 | rc = pci_enable_device(pdev); | ||
783 | if (rc < 0) { | ||
784 | i7core_printk(KERN_ERR, | ||
785 | "Couldn't enable PCI ID %04x:%04x " | ||
786 | "(dev %d, func %d)\n", | ||
787 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, | ||
788 | pci_devs[i].dev, pci_devs[i].func); | ||
789 | i7core_put_devices(); | ||
790 | return rc; | ||
791 | } | ||
792 | /* Sanity check */ | ||
793 | if (PCI_FUNC(pdev->devfn) != pci_devs[i].func) { | ||
794 | i7core_printk(KERN_ERR, | ||
795 | "Device PCI ID %04x:%04x " | ||
796 | "has function %d instead of %d\n", | ||
797 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, | ||
798 | PCI_FUNC(pdev->devfn), pci_devs[i].func); | ||
799 | i7core_put_devices(); | ||
800 | return -EINVAL; | ||
801 | } | ||
724 | 802 | ||
725 | /* Retrieve all needed functions at MTR channel controllers */ | 803 | i7core_printk(KERN_INFO, |
726 | for (i = 0; i < NUM_CHANS; i++) { | 804 | "Registered device %0x:%0x fn=%0x %0x\n", |
727 | pdev = NULL; | 805 | PCI_VENDOR_ID_INTEL, pci_devs[i].dev_id, |
728 | for (n = 0; n < NUM_FUNCS; n++) { | 806 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); |
729 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | 807 | |
730 | chan_pci_ids[i], pdev); | 808 | func = PCI_FUNC(pdev->devfn); |
731 | if (!pdev) { | 809 | if (pci_devs[i].dev < 4) { |
732 | /* End of list, leave */ | 810 | pvt->pci_mcr[func] = pdev; |
733 | i7core_printk(KERN_ERR, | 811 | } else { |
734 | "Device not found: PCI ID %04x:%04x " | 812 | pvt->pci_ch[pci_devs[i].dev - 4][func] = pdev; |
735 | "found only %d functions " | ||
736 | "(broken BIOS?)\n", | ||
737 | PCI_VENDOR_ID_INTEL, | ||
738 | chan_pci_ids[i], n); | ||
739 | i7core_put_devices(mci); | ||
740 | return -ENODEV; | ||
741 | } | ||
742 | func = PCI_FUNC(pdev->devfn); | ||
743 | pvt->pci_ch[i][func] = pdev; | ||
744 | } | 813 | } |
745 | } | 814 | } |
746 | i7core_printk(KERN_INFO, "Driver loaded.\n"); | ||
747 | 815 | ||
748 | /* Get dimm basic config */ | 816 | i7core_printk(KERN_INFO, "Driver loaded.\n"); |
749 | get_dimm_config(mci); | ||
750 | 817 | ||
751 | return 0; | 818 | return 0; |
752 | } | 819 | } |
@@ -763,7 +830,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
763 | { | 830 | { |
764 | struct mem_ctl_info *mci; | 831 | struct mem_ctl_info *mci; |
765 | struct i7core_pvt *pvt; | 832 | struct i7core_pvt *pvt; |
766 | int rc; | ||
767 | int num_channels; | 833 | int num_channels; |
768 | int num_csrows; | 834 | int num_csrows; |
769 | int num_dimms_per_channel; | 835 | int num_dimms_per_channel; |
@@ -772,20 +838,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
772 | if (dev_idx >= ARRAY_SIZE(i7core_devs)) | 838 | if (dev_idx >= ARRAY_SIZE(i7core_devs)) |
773 | return -EINVAL; | 839 | return -EINVAL; |
774 | 840 | ||
775 | /* wake up device */ | ||
776 | rc = pci_enable_device(pdev); | ||
777 | if (rc == -EIO) | ||
778 | return rc; | ||
779 | |||
780 | debugf0("MC: " __FILE__ ": %s(), pdev bus %u dev=0x%x fn=0x%x\n", | ||
781 | __func__, | ||
782 | pdev->bus->number, | ||
783 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); | ||
784 | |||
785 | /* We only are looking for func 0 of the set */ | ||
786 | if (PCI_FUNC(pdev->devfn) != 0) | ||
787 | return -ENODEV; | ||
788 | |||
789 | num_channels = NUM_CHANS; | 841 | num_channels = NUM_CHANS; |
790 | 842 | ||
791 | /* FIXME: FAKE data, since we currently don't now how to get this */ | 843 | /* FIXME: FAKE data, since we currently don't now how to get this */ |
@@ -808,10 +860,6 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
808 | // pvt->maxch = num_channels; | 860 | // pvt->maxch = num_channels; |
809 | // pvt->maxdimmperch = num_dimms_per_channel; | 861 | // pvt->maxdimmperch = num_dimms_per_channel; |
810 | 862 | ||
811 | /* 'get' the pci devices we want to reserve for our use */ | ||
812 | if (i7core_get_devices(mci, dev_idx)) | ||
813 | goto fail0; | ||
814 | |||
815 | mci->mc_idx = 0; | 863 | mci->mc_idx = 0; |
816 | mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ | 864 | mci->mtype_cap = MEM_FLAG_FB_DDR2; /* FIXME: it uses DDR3 */ |
817 | mci->edac_ctl_cap = EDAC_FLAG_NONE; | 865 | mci->edac_ctl_cap = EDAC_FLAG_NONE; |
@@ -823,6 +871,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
823 | mci->ctl_page_to_phys = NULL; | 871 | mci->ctl_page_to_phys = NULL; |
824 | mci->mc_driver_sysfs_attributes = i7core_inj_attrs; | 872 | mci->mc_driver_sysfs_attributes = i7core_inj_attrs; |
825 | 873 | ||
874 | /* 'get' the pci devices we want to reserve for our use */ | ||
875 | if (i7core_get_devices(mci, pdev)) | ||
876 | goto fail0; | ||
877 | |||
826 | /* add this new MC control structure to EDAC's list of MCs */ | 878 | /* add this new MC control structure to EDAC's list of MCs */ |
827 | if (edac_mc_add_mc(mci)) { | 879 | if (edac_mc_add_mc(mci)) { |
828 | debugf0("MC: " __FILE__ | 880 | debugf0("MC: " __FILE__ |
@@ -852,10 +904,13 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
852 | pvt->inject.page = -1; | 904 | pvt->inject.page = -1; |
853 | pvt->inject.col = -1; | 905 | pvt->inject.col = -1; |
854 | 906 | ||
907 | /* Get dimm basic config */ | ||
908 | get_dimm_config(mci); | ||
909 | |||
855 | return 0; | 910 | return 0; |
856 | 911 | ||
857 | fail1: | 912 | fail1: |
858 | i7core_put_devices(mci); | 913 | i7core_put_devices(); |
859 | 914 | ||
860 | fail0: | 915 | fail0: |
861 | edac_mc_free(mci); | 916 | edac_mc_free(mci); |
@@ -880,21 +935,11 @@ static void __devexit i7core_remove(struct pci_dev *pdev) | |||
880 | return; | 935 | return; |
881 | 936 | ||
882 | /* retrieve references to resources, and free those resources */ | 937 | /* retrieve references to resources, and free those resources */ |
883 | i7core_put_devices(mci); | 938 | i7core_put_devices(); |
884 | 939 | ||
885 | edac_mc_free(mci); | 940 | edac_mc_free(mci); |
886 | } | 941 | } |
887 | 942 | ||
888 | /* | ||
889 | * pci_device_id table for which devices we are looking for | ||
890 | * | ||
891 | * The "E500P" device is the first device supported. | ||
892 | */ | ||
893 | static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { | ||
894 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_I7_MCR)}, | ||
895 | {0,} /* 0 terminated list. */ | ||
896 | }; | ||
897 | |||
898 | MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); | 943 | MODULE_DEVICE_TABLE(pci, i7core_pci_tbl); |
899 | 944 | ||
900 | /* | 945 | /* |