diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 13:13:48 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-10-26 13:13:48 -0400 |
commit | da62aa69c181e3bd465a5c868ece166921a81e14 (patch) | |
tree | 5f1a3e234dd791099ba8761f79442b0ac6f664c0 /drivers/edac | |
parent | f1ebdd60cc73ed36fd977f7e719ce70d2f5cd1c0 (diff) | |
parent | 76a7bd81130646459dfded1845e0d511488a6afa (diff) |
Merge branch 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/i7core
* 'linux_next' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/i7core: (34 commits)
i7core_edac: return -ENODEV when devices were already probed
i7core_edac: properly terminate pci_dev_table
i7core_edac: Avoid PCI refcount to reach zero on successive load/reload
i7core_edac: Fix refcount error at PCI devices
i7core_edac: it is safe to i7core_unregister_mci() when mci=NULL
i7core_edac: Fix an oops at i7core probe
i7core_edac: Remove unused member channels in i7core_pvt
i7core_edac: Remove unused arg csrow from get_dimm_config
i7core_edac: Reduce args of i7core_register_mci
i7core_edac: Introduce i7core_unregister_mci
i7core_edac: Use saved pointers
i7core_edac: Check probe counter in i7core_remove
i7core_edac: Call pci_dev_put() when alloc_i7core_dev() failed
i7core_edac: Fix error path of i7core_register_mci
i7core_edac: Fix order of lines in i7core_register_mci
i7core_edac: Always do get/put for all devices
i7core_edac: Introduce i7core_pci_ctl_create/release
i7core_edac: Introduce free_i7core_dev
i7core_edac: Introduce alloc_i7core_dev
i7core_edac: Reduce args of i7core_get_onedevice
...
Diffstat (limited to 'drivers/edac')
-rw-r--r-- | drivers/edac/edac_core.h | 11 | ||||
-rw-r--r-- | drivers/edac/edac_mc.c | 12 | ||||
-rw-r--r-- | drivers/edac/edac_mc_sysfs.c | 82 | ||||
-rw-r--r-- | drivers/edac/i7core_edac.c | 432 |
4 files changed, 313 insertions, 224 deletions
diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index ce7146677e9b..d7ca43a828bd 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h | |||
@@ -42,8 +42,10 @@ | |||
42 | 42 | ||
43 | #if PAGE_SHIFT < 20 | 43 | #if PAGE_SHIFT < 20 |
44 | #define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) | 44 | #define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) |
45 | #define MiB_TO_PAGES(mb) ((mb) >> (20 - PAGE_SHIFT)) | ||
45 | #else /* PAGE_SHIFT > 20 */ | 46 | #else /* PAGE_SHIFT > 20 */ |
46 | #define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) ) | 47 | #define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) ) |
48 | #define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20)) | ||
47 | #endif | 49 | #endif |
48 | 50 | ||
49 | #define edac_printk(level, prefix, fmt, arg...) \ | 51 | #define edac_printk(level, prefix, fmt, arg...) \ |
@@ -328,7 +330,7 @@ struct csrow_info { | |||
328 | 330 | ||
329 | struct mcidev_sysfs_group { | 331 | struct mcidev_sysfs_group { |
330 | const char *name; /* group name */ | 332 | const char *name; /* group name */ |
331 | struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */ | 333 | const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */ |
332 | }; | 334 | }; |
333 | 335 | ||
334 | struct mcidev_sysfs_group_kobj { | 336 | struct mcidev_sysfs_group_kobj { |
@@ -336,7 +338,7 @@ struct mcidev_sysfs_group_kobj { | |||
336 | 338 | ||
337 | struct kobject kobj; /* kobj for the group */ | 339 | struct kobject kobj; /* kobj for the group */ |
338 | 340 | ||
339 | struct mcidev_sysfs_group *grp; /* group description table */ | 341 | const struct mcidev_sysfs_group *grp; /* group description table */ |
340 | struct mem_ctl_info *mci; /* the parent */ | 342 | struct mem_ctl_info *mci; /* the parent */ |
341 | }; | 343 | }; |
342 | 344 | ||
@@ -347,7 +349,7 @@ struct mcidev_sysfs_group_kobj { | |||
347 | struct mcidev_sysfs_attribute { | 349 | struct mcidev_sysfs_attribute { |
348 | /* It should use either attr or grp */ | 350 | /* It should use either attr or grp */ |
349 | struct attribute attr; | 351 | struct attribute attr; |
350 | struct mcidev_sysfs_group *grp; /* Points to a group of attributes */ | 352 | const struct mcidev_sysfs_group *grp; /* Points to a group of attributes */ |
351 | 353 | ||
352 | /* Ops for show/store values at the attribute - not used on group */ | 354 | /* Ops for show/store values at the attribute - not used on group */ |
353 | ssize_t (*show)(struct mem_ctl_info *,char *); | 355 | ssize_t (*show)(struct mem_ctl_info *,char *); |
@@ -440,7 +442,7 @@ struct mem_ctl_info { | |||
440 | * If attributes are desired, then set to array of attributes | 442 | * If attributes are desired, then set to array of attributes |
441 | * If no attributes are desired, leave NULL | 443 | * If no attributes are desired, leave NULL |
442 | */ | 444 | */ |
443 | struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; | 445 | const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; |
444 | 446 | ||
445 | /* work struct for this MC */ | 447 | /* work struct for this MC */ |
446 | struct delayed_work work; | 448 | struct delayed_work work; |
@@ -810,6 +812,7 @@ extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
810 | extern int edac_mc_add_mc(struct mem_ctl_info *mci); | 812 | extern int edac_mc_add_mc(struct mem_ctl_info *mci); |
811 | extern void edac_mc_free(struct mem_ctl_info *mci); | 813 | extern void edac_mc_free(struct mem_ctl_info *mci); |
812 | extern struct mem_ctl_info *edac_mc_find(int idx); | 814 | extern struct mem_ctl_info *edac_mc_find(int idx); |
815 | extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); | ||
813 | extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); | 816 | extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); |
814 | extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, | 817 | extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, |
815 | unsigned long page); | 818 | unsigned long page); |
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 6b21e25f7a84..ba6586a69ccc 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c | |||
@@ -207,6 +207,7 @@ struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, | |||
207 | } | 207 | } |
208 | 208 | ||
209 | mci->op_state = OP_ALLOC; | 209 | mci->op_state = OP_ALLOC; |
210 | INIT_LIST_HEAD(&mci->grp_kobj_list); | ||
210 | 211 | ||
211 | /* | 212 | /* |
212 | * Initialize the 'root' kobj for the edac_mc controller | 213 | * Initialize the 'root' kobj for the edac_mc controller |
@@ -234,18 +235,24 @@ EXPORT_SYMBOL_GPL(edac_mc_alloc); | |||
234 | */ | 235 | */ |
235 | void edac_mc_free(struct mem_ctl_info *mci) | 236 | void edac_mc_free(struct mem_ctl_info *mci) |
236 | { | 237 | { |
238 | debugf1("%s()\n", __func__); | ||
239 | |||
237 | edac_mc_unregister_sysfs_main_kobj(mci); | 240 | edac_mc_unregister_sysfs_main_kobj(mci); |
241 | |||
242 | /* free the mci instance memory here */ | ||
243 | kfree(mci); | ||
238 | } | 244 | } |
239 | EXPORT_SYMBOL_GPL(edac_mc_free); | 245 | EXPORT_SYMBOL_GPL(edac_mc_free); |
240 | 246 | ||
241 | 247 | ||
242 | /* | 248 | /** |
243 | * find_mci_by_dev | 249 | * find_mci_by_dev |
244 | * | 250 | * |
245 | * scan list of controllers looking for the one that manages | 251 | * scan list of controllers looking for the one that manages |
246 | * the 'dev' device | 252 | * the 'dev' device |
253 | * @dev: pointer to a struct device related with the MCI | ||
247 | */ | 254 | */ |
248 | static struct mem_ctl_info *find_mci_by_dev(struct device *dev) | 255 | struct mem_ctl_info *find_mci_by_dev(struct device *dev) |
249 | { | 256 | { |
250 | struct mem_ctl_info *mci; | 257 | struct mem_ctl_info *mci; |
251 | struct list_head *item; | 258 | struct list_head *item; |
@@ -261,6 +268,7 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev) | |||
261 | 268 | ||
262 | return NULL; | 269 | return NULL; |
263 | } | 270 | } |
271 | EXPORT_SYMBOL_GPL(find_mci_by_dev); | ||
264 | 272 | ||
265 | /* | 273 | /* |
266 | * handler for EDAC to check if NMI type handler has asserted interrupt | 274 | * handler for EDAC to check if NMI type handler has asserted interrupt |
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index a4135860149b..dce61f7ba38b 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c | |||
@@ -631,9 +631,6 @@ static void edac_mci_control_release(struct kobject *kobj) | |||
631 | 631 | ||
632 | /* decrement the module ref count */ | 632 | /* decrement the module ref count */ |
633 | module_put(mci->owner); | 633 | module_put(mci->owner); |
634 | |||
635 | /* free the mci instance memory here */ | ||
636 | kfree(mci); | ||
637 | } | 634 | } |
638 | 635 | ||
639 | static struct kobj_type ktype_mci = { | 636 | static struct kobj_type ktype_mci = { |
@@ -713,6 +710,8 @@ fail_out: | |||
713 | */ | 710 | */ |
714 | void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) | 711 | void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) |
715 | { | 712 | { |
713 | debugf1("%s()\n", __func__); | ||
714 | |||
716 | /* delete the kobj from the mc_kset */ | 715 | /* delete the kobj from the mc_kset */ |
717 | kobject_put(&mci->edac_mci_kobj); | 716 | kobject_put(&mci->edac_mci_kobj); |
718 | } | 717 | } |
@@ -760,8 +759,6 @@ static void edac_inst_grp_release(struct kobject *kobj) | |||
760 | 759 | ||
761 | grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj); | 760 | grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj); |
762 | mci = grp->mci; | 761 | mci = grp->mci; |
763 | |||
764 | kobject_put(&mci->edac_mci_kobj); | ||
765 | } | 762 | } |
766 | 763 | ||
767 | /* Intermediate show/store table */ | 764 | /* Intermediate show/store table */ |
@@ -784,7 +781,7 @@ static struct kobj_type ktype_inst_grp = { | |||
784 | * object tree. | 781 | * object tree. |
785 | */ | 782 | */ |
786 | static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, | 783 | static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, |
787 | struct mcidev_sysfs_attribute *sysfs_attrib, | 784 | const struct mcidev_sysfs_attribute *sysfs_attrib, |
788 | struct kobject *kobj) | 785 | struct kobject *kobj) |
789 | { | 786 | { |
790 | int err; | 787 | int err; |
@@ -792,6 +789,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, | |||
792 | debugf1("%s()\n", __func__); | 789 | debugf1("%s()\n", __func__); |
793 | 790 | ||
794 | while (sysfs_attrib) { | 791 | while (sysfs_attrib) { |
792 | debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); | ||
795 | if (sysfs_attrib->grp) { | 793 | if (sysfs_attrib->grp) { |
796 | struct mcidev_sysfs_group_kobj *grp_kobj; | 794 | struct mcidev_sysfs_group_kobj *grp_kobj; |
797 | 795 | ||
@@ -799,10 +797,9 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, | |||
799 | if (!grp_kobj) | 797 | if (!grp_kobj) |
800 | return -ENOMEM; | 798 | return -ENOMEM; |
801 | 799 | ||
802 | list_add_tail(&grp_kobj->list, &mci->grp_kobj_list); | ||
803 | |||
804 | grp_kobj->grp = sysfs_attrib->grp; | 800 | grp_kobj->grp = sysfs_attrib->grp; |
805 | grp_kobj->mci = mci; | 801 | grp_kobj->mci = mci; |
802 | list_add_tail(&grp_kobj->list, &mci->grp_kobj_list); | ||
806 | 803 | ||
807 | debugf0("%s() grp %s, mci %p\n", __func__, | 804 | debugf0("%s() grp %s, mci %p\n", __func__, |
808 | sysfs_attrib->grp->name, mci); | 805 | sysfs_attrib->grp->name, mci); |
@@ -811,26 +808,28 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, | |||
811 | &ktype_inst_grp, | 808 | &ktype_inst_grp, |
812 | &mci->edac_mci_kobj, | 809 | &mci->edac_mci_kobj, |
813 | sysfs_attrib->grp->name); | 810 | sysfs_attrib->grp->name); |
814 | if (err) | 811 | if (err < 0) { |
812 | printk(KERN_ERR "kobject_init_and_add failed: %d\n", err); | ||
815 | return err; | 813 | return err; |
816 | 814 | } | |
817 | err = edac_create_mci_instance_attributes(mci, | 815 | err = edac_create_mci_instance_attributes(mci, |
818 | grp_kobj->grp->mcidev_attr, | 816 | grp_kobj->grp->mcidev_attr, |
819 | &grp_kobj->kobj); | 817 | &grp_kobj->kobj); |
820 | 818 | ||
821 | if (err) | 819 | if (err < 0) |
822 | return err; | 820 | return err; |
823 | } else if (sysfs_attrib->attr.name) { | 821 | } else if (sysfs_attrib->attr.name) { |
824 | debugf0("%s() file %s\n", __func__, | 822 | debugf0("%s() file %s\n", __func__, |
825 | sysfs_attrib->attr.name); | 823 | sysfs_attrib->attr.name); |
826 | 824 | ||
827 | err = sysfs_create_file(kobj, &sysfs_attrib->attr); | 825 | err = sysfs_create_file(kobj, &sysfs_attrib->attr); |
826 | if (err < 0) { | ||
827 | printk(KERN_ERR "sysfs_create_file failed: %d\n", err); | ||
828 | return err; | ||
829 | } | ||
828 | } else | 830 | } else |
829 | break; | 831 | break; |
830 | 832 | ||
831 | if (err) { | ||
832 | return err; | ||
833 | } | ||
834 | sysfs_attrib++; | 833 | sysfs_attrib++; |
835 | } | 834 | } |
836 | 835 | ||
@@ -843,7 +842,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, | |||
843 | * directory of this mci instance. | 842 | * directory of this mci instance. |
844 | */ | 843 | */ |
845 | static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, | 844 | static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, |
846 | struct mcidev_sysfs_attribute *sysfs_attrib, | 845 | const struct mcidev_sysfs_attribute *sysfs_attrib, |
847 | struct kobject *kobj, int count) | 846 | struct kobject *kobj, int count) |
848 | { | 847 | { |
849 | struct mcidev_sysfs_group_kobj *grp_kobj, *tmp; | 848 | struct mcidev_sysfs_group_kobj *grp_kobj, *tmp; |
@@ -855,13 +854,24 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, | |||
855 | * Remove first all the atributes | 854 | * Remove first all the atributes |
856 | */ | 855 | */ |
857 | while (sysfs_attrib) { | 856 | while (sysfs_attrib) { |
857 | debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); | ||
858 | if (sysfs_attrib->grp) { | 858 | if (sysfs_attrib->grp) { |
859 | list_for_each_entry(grp_kobj, &mci->grp_kobj_list, | 859 | debugf1("%s() seeking for group %s\n", |
860 | list) | 860 | __func__, sysfs_attrib->grp->name); |
861 | if (grp_kobj->grp == sysfs_attrib->grp) | 861 | list_for_each_entry(grp_kobj, |
862 | &mci->grp_kobj_list, list) { | ||
863 | debugf1("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp); | ||
864 | if (grp_kobj->grp == sysfs_attrib->grp) { | ||
862 | edac_remove_mci_instance_attributes(mci, | 865 | edac_remove_mci_instance_attributes(mci, |
863 | grp_kobj->grp->mcidev_attr, | 866 | grp_kobj->grp->mcidev_attr, |
864 | &grp_kobj->kobj, count + 1); | 867 | &grp_kobj->kobj, count + 1); |
868 | debugf0("%s() group %s\n", __func__, | ||
869 | sysfs_attrib->grp->name); | ||
870 | kobject_put(&grp_kobj->kobj); | ||
871 | } | ||
872 | } | ||
873 | debugf1("%s() end of seeking for group %s\n", | ||
874 | __func__, sysfs_attrib->grp->name); | ||
865 | } else if (sysfs_attrib->attr.name) { | 875 | } else if (sysfs_attrib->attr.name) { |
866 | debugf0("%s() file %s\n", __func__, | 876 | debugf0("%s() file %s\n", __func__, |
867 | sysfs_attrib->attr.name); | 877 | sysfs_attrib->attr.name); |
@@ -871,15 +881,14 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, | |||
871 | sysfs_attrib++; | 881 | sysfs_attrib++; |
872 | } | 882 | } |
873 | 883 | ||
874 | /* | 884 | /* Remove the group objects */ |
875 | * Now that all attributes got removed, it is save to remove all groups | 885 | if (count) |
876 | */ | 886 | return; |
877 | if (!count) | 887 | list_for_each_entry_safe(grp_kobj, tmp, |
878 | list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list, | 888 | &mci->grp_kobj_list, list) { |
879 | list) { | 889 | list_del(&grp_kobj->list); |
880 | debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name); | 890 | kfree(grp_kobj); |
881 | kobject_put(&grp_kobj->kobj); | 891 | } |
882 | } | ||
883 | } | 892 | } |
884 | 893 | ||
885 | 894 | ||
@@ -971,6 +980,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | |||
971 | debugf0("%s()\n", __func__); | 980 | debugf0("%s()\n", __func__); |
972 | 981 | ||
973 | /* remove all csrow kobjects */ | 982 | /* remove all csrow kobjects */ |
983 | debugf0("%s() unregister this mci kobj\n", __func__); | ||
974 | for (i = 0; i < mci->nr_csrows; i++) { | 984 | for (i = 0; i < mci->nr_csrows; i++) { |
975 | if (mci->csrows[i].nr_pages > 0) { | 985 | if (mci->csrows[i].nr_pages > 0) { |
976 | debugf0("%s() unreg csrow-%d\n", __func__, i); | 986 | debugf0("%s() unreg csrow-%d\n", __func__, i); |
@@ -978,20 +988,20 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) | |||
978 | } | 988 | } |
979 | } | 989 | } |
980 | 990 | ||
981 | debugf0("%s() remove_link\n", __func__); | 991 | /* remove this mci instance's attribtes */ |
992 | if (mci->mc_driver_sysfs_attributes) { | ||
993 | debugf0("%s() unregister mci private attributes\n", __func__); | ||
994 | edac_remove_mci_instance_attributes(mci, | ||
995 | mci->mc_driver_sysfs_attributes, | ||
996 | &mci->edac_mci_kobj, 0); | ||
997 | } | ||
982 | 998 | ||
983 | /* remove the symlink */ | 999 | /* remove the symlink */ |
1000 | debugf0("%s() remove_link\n", __func__); | ||
984 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); | 1001 | sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); |
985 | 1002 | ||
986 | debugf0("%s() remove_mci_instance\n", __func__); | ||
987 | |||
988 | /* remove this mci instance's attribtes */ | ||
989 | edac_remove_mci_instance_attributes(mci, | ||
990 | mci->mc_driver_sysfs_attributes, | ||
991 | &mci->edac_mci_kobj, 0); | ||
992 | debugf0("%s() unregister this mci kobj\n", __func__); | ||
993 | |||
994 | /* unregister this instance's kobject */ | 1003 | /* unregister this instance's kobject */ |
1004 | debugf0("%s() remove_mci_instance\n", __func__); | ||
995 | kobject_put(&mci->edac_mci_kobj); | 1005 | kobject_put(&mci->edac_mci_kobj); |
996 | } | 1006 | } |
997 | 1007 | ||
diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0fd5b85a0f75..362861c15779 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c | |||
@@ -39,6 +39,14 @@ | |||
39 | 39 | ||
40 | #include "edac_core.h" | 40 | #include "edac_core.h" |
41 | 41 | ||
42 | /* Static vars */ | ||
43 | static LIST_HEAD(i7core_edac_list); | ||
44 | static DEFINE_MUTEX(i7core_edac_lock); | ||
45 | static int probed; | ||
46 | |||
47 | static int use_pci_fixup; | ||
48 | module_param(use_pci_fixup, int, 0444); | ||
49 | MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices"); | ||
42 | /* | 50 | /* |
43 | * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core | 51 | * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core |
44 | * registers start at bus 255, and are not reported by BIOS. | 52 | * registers start at bus 255, and are not reported by BIOS. |
@@ -212,8 +220,8 @@ struct pci_id_descr { | |||
212 | }; | 220 | }; |
213 | 221 | ||
214 | struct pci_id_table { | 222 | struct pci_id_table { |
215 | struct pci_id_descr *descr; | 223 | const struct pci_id_descr *descr; |
216 | int n_devs; | 224 | int n_devs; |
217 | }; | 225 | }; |
218 | 226 | ||
219 | struct i7core_dev { | 227 | struct i7core_dev { |
@@ -235,8 +243,6 @@ struct i7core_pvt { | |||
235 | struct i7core_inject inject; | 243 | struct i7core_inject inject; |
236 | struct i7core_channel channel[NUM_CHANS]; | 244 | struct i7core_channel channel[NUM_CHANS]; |
237 | 245 | ||
238 | int channels; /* Number of active channels */ | ||
239 | |||
240 | int ce_count_available; | 246 | int ce_count_available; |
241 | int csrow_map[NUM_CHANS][MAX_DIMMS]; | 247 | int csrow_map[NUM_CHANS][MAX_DIMMS]; |
242 | 248 | ||
@@ -261,22 +267,22 @@ struct i7core_pvt { | |||
261 | 267 | ||
262 | /* Count indicator to show errors not got */ | 268 | /* Count indicator to show errors not got */ |
263 | unsigned mce_overrun; | 269 | unsigned mce_overrun; |
264 | }; | ||
265 | 270 | ||
266 | /* Static vars */ | 271 | /* Struct to control EDAC polling */ |
267 | static LIST_HEAD(i7core_edac_list); | 272 | struct edac_pci_ctl_info *i7core_pci; |
268 | static DEFINE_MUTEX(i7core_edac_lock); | 273 | }; |
269 | 274 | ||
270 | #define PCI_DESCR(device, function, device_id) \ | 275 | #define PCI_DESCR(device, function, device_id) \ |
271 | .dev = (device), \ | 276 | .dev = (device), \ |
272 | .func = (function), \ | 277 | .func = (function), \ |
273 | .dev_id = (device_id) | 278 | .dev_id = (device_id) |
274 | 279 | ||
275 | struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { | 280 | static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { |
276 | /* Memory controller */ | 281 | /* Memory controller */ |
277 | { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, | 282 | { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, |
278 | { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, | 283 | { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, |
279 | /* Exists only for RDIMM */ | 284 | |
285 | /* Exists only for RDIMM */ | ||
280 | { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 }, | 286 | { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 }, |
281 | { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, | 287 | { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, |
282 | 288 | ||
@@ -297,19 +303,9 @@ struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { | |||
297 | { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, | 303 | { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, |
298 | { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, | 304 | { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, |
299 | { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, | 305 | { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, |
300 | |||
301 | /* Generic Non-core registers */ | ||
302 | /* | ||
303 | * This is the PCI device on i7core and on Xeon 35xx (8086:2c41) | ||
304 | * On Xeon 55xx, however, it has a different id (8086:2c40). So, | ||
305 | * the probing code needs to test for the other address in case of | ||
306 | * failure of this one | ||
307 | */ | ||
308 | { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) }, | ||
309 | |||
310 | }; | 306 | }; |
311 | 307 | ||
312 | struct pci_id_descr pci_dev_descr_lynnfield[] = { | 308 | static const struct pci_id_descr pci_dev_descr_lynnfield[] = { |
313 | { PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR) }, | 309 | { PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR) }, |
314 | { PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD) }, | 310 | { PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD) }, |
315 | { PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST) }, | 311 | { PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST) }, |
@@ -323,15 +319,9 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { | |||
323 | { PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, | 319 | { PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, |
324 | { PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, | 320 | { PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, |
325 | { PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, | 321 | { PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, |
326 | |||
327 | /* | ||
328 | * This is the PCI device has an alternate address on some | ||
329 | * processors like Core i7 860 | ||
330 | */ | ||
331 | { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, | ||
332 | }; | 322 | }; |
333 | 323 | ||
334 | struct pci_id_descr pci_dev_descr_i7core_westmere[] = { | 324 | static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = { |
335 | /* Memory controller */ | 325 | /* Memory controller */ |
336 | { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) }, | 326 | { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) }, |
337 | { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) }, | 327 | { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) }, |
@@ -356,17 +346,14 @@ struct pci_id_descr pci_dev_descr_i7core_westmere[] = { | |||
356 | { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) }, | 346 | { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) }, |
357 | { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) }, | 347 | { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) }, |
358 | { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) }, | 348 | { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) }, |
359 | |||
360 | /* Generic Non-core registers */ | ||
361 | { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) }, | ||
362 | |||
363 | }; | 349 | }; |
364 | 350 | ||
365 | #define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) } | 351 | #define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) } |
366 | struct pci_id_table pci_dev_table[] = { | 352 | static const struct pci_id_table pci_dev_table[] = { |
367 | PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem), | 353 | PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem), |
368 | PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield), | 354 | PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield), |
369 | PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere), | 355 | PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere), |
356 | {0,} /* 0 terminated list. */ | ||
370 | }; | 357 | }; |
371 | 358 | ||
372 | /* | 359 | /* |
@@ -378,8 +365,6 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { | |||
378 | {0,} /* 0 terminated list. */ | 365 | {0,} /* 0 terminated list. */ |
379 | }; | 366 | }; |
380 | 367 | ||
381 | static struct edac_pci_ctl_info *i7core_pci; | ||
382 | |||
383 | /**************************************************************************** | 368 | /**************************************************************************** |
384 | Anciliary status routines | 369 | Anciliary status routines |
385 | ****************************************************************************/ | 370 | ****************************************************************************/ |
@@ -442,6 +427,36 @@ static struct i7core_dev *get_i7core_dev(u8 socket) | |||
442 | return NULL; | 427 | return NULL; |
443 | } | 428 | } |
444 | 429 | ||
430 | static struct i7core_dev *alloc_i7core_dev(u8 socket, | ||
431 | const struct pci_id_table *table) | ||
432 | { | ||
433 | struct i7core_dev *i7core_dev; | ||
434 | |||
435 | i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); | ||
436 | if (!i7core_dev) | ||
437 | return NULL; | ||
438 | |||
439 | i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * table->n_devs, | ||
440 | GFP_KERNEL); | ||
441 | if (!i7core_dev->pdev) { | ||
442 | kfree(i7core_dev); | ||
443 | return NULL; | ||
444 | } | ||
445 | |||
446 | i7core_dev->socket = socket; | ||
447 | i7core_dev->n_devs = table->n_devs; | ||
448 | list_add_tail(&i7core_dev->list, &i7core_edac_list); | ||
449 | |||
450 | return i7core_dev; | ||
451 | } | ||
452 | |||
453 | static void free_i7core_dev(struct i7core_dev *i7core_dev) | ||
454 | { | ||
455 | list_del(&i7core_dev->list); | ||
456 | kfree(i7core_dev->pdev); | ||
457 | kfree(i7core_dev); | ||
458 | } | ||
459 | |||
445 | /**************************************************************************** | 460 | /**************************************************************************** |
446 | Memory check routines | 461 | Memory check routines |
447 | ****************************************************************************/ | 462 | ****************************************************************************/ |
@@ -484,7 +499,7 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, | |||
484 | * to add a fake description for csrows. | 499 | * to add a fake description for csrows. |
485 | * So, this driver is attributing one DIMM memory for one csrow. | 500 | * So, this driver is attributing one DIMM memory for one csrow. |
486 | */ | 501 | */ |
487 | static int i7core_get_active_channels(u8 socket, unsigned *channels, | 502 | static int i7core_get_active_channels(const u8 socket, unsigned *channels, |
488 | unsigned *csrows) | 503 | unsigned *csrows) |
489 | { | 504 | { |
490 | struct pci_dev *pdev = NULL; | 505 | struct pci_dev *pdev = NULL; |
@@ -545,12 +560,13 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, | |||
545 | return 0; | 560 | return 0; |
546 | } | 561 | } |
547 | 562 | ||
548 | static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) | 563 | static int get_dimm_config(const struct mem_ctl_info *mci) |
549 | { | 564 | { |
550 | struct i7core_pvt *pvt = mci->pvt_info; | 565 | struct i7core_pvt *pvt = mci->pvt_info; |
551 | struct csrow_info *csr; | 566 | struct csrow_info *csr; |
552 | struct pci_dev *pdev; | 567 | struct pci_dev *pdev; |
553 | int i, j; | 568 | int i, j; |
569 | int csrow = 0; | ||
554 | unsigned long last_page = 0; | 570 | unsigned long last_page = 0; |
555 | enum edac_type mode; | 571 | enum edac_type mode; |
556 | enum mem_type mtype; | 572 | enum mem_type mtype; |
@@ -664,13 +680,9 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) | |||
664 | RANKOFFSET(dimm_dod[j]), | 680 | RANKOFFSET(dimm_dod[j]), |
665 | banks, ranks, rows, cols); | 681 | banks, ranks, rows, cols); |
666 | 682 | ||
667 | #if PAGE_SHIFT > 20 | 683 | npages = MiB_TO_PAGES(size); |
668 | npages = size >> (PAGE_SHIFT - 20); | ||
669 | #else | ||
670 | npages = size << (20 - PAGE_SHIFT); | ||
671 | #endif | ||
672 | 684 | ||
673 | csr = &mci->csrows[*csrow]; | 685 | csr = &mci->csrows[csrow]; |
674 | csr->first_page = last_page + 1; | 686 | csr->first_page = last_page + 1; |
675 | last_page += npages; | 687 | last_page += npages; |
676 | csr->last_page = last_page; | 688 | csr->last_page = last_page; |
@@ -678,13 +690,13 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) | |||
678 | 690 | ||
679 | csr->page_mask = 0; | 691 | csr->page_mask = 0; |
680 | csr->grain = 8; | 692 | csr->grain = 8; |
681 | csr->csrow_idx = *csrow; | 693 | csr->csrow_idx = csrow; |
682 | csr->nr_channels = 1; | 694 | csr->nr_channels = 1; |
683 | 695 | ||
684 | csr->channels[0].chan_idx = i; | 696 | csr->channels[0].chan_idx = i; |
685 | csr->channels[0].ce_count = 0; | 697 | csr->channels[0].ce_count = 0; |
686 | 698 | ||
687 | pvt->csrow_map[i][j] = *csrow; | 699 | pvt->csrow_map[i][j] = csrow; |
688 | 700 | ||
689 | switch (banks) { | 701 | switch (banks) { |
690 | case 4: | 702 | case 4: |
@@ -703,7 +715,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) | |||
703 | csr->edac_mode = mode; | 715 | csr->edac_mode = mode; |
704 | csr->mtype = mtype; | 716 | csr->mtype = mtype; |
705 | 717 | ||
706 | (*csrow)++; | 718 | csrow++; |
707 | } | 719 | } |
708 | 720 | ||
709 | pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); | 721 | pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); |
@@ -736,7 +748,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) | |||
736 | we're disabling error injection on all write calls to the sysfs nodes that | 748 | we're disabling error injection on all write calls to the sysfs nodes that |
737 | controls the error code injection. | 749 | controls the error code injection. |
738 | */ | 750 | */ |
739 | static int disable_inject(struct mem_ctl_info *mci) | 751 | static int disable_inject(const struct mem_ctl_info *mci) |
740 | { | 752 | { |
741 | struct i7core_pvt *pvt = mci->pvt_info; | 753 | struct i7core_pvt *pvt = mci->pvt_info; |
742 | 754 | ||
@@ -921,7 +933,7 @@ DECLARE_ADDR_MATCH(bank, 32); | |||
921 | DECLARE_ADDR_MATCH(page, 0x10000); | 933 | DECLARE_ADDR_MATCH(page, 0x10000); |
922 | DECLARE_ADDR_MATCH(col, 0x4000); | 934 | DECLARE_ADDR_MATCH(col, 0x4000); |
923 | 935 | ||
924 | static int write_and_test(struct pci_dev *dev, int where, u32 val) | 936 | static int write_and_test(struct pci_dev *dev, const int where, const u32 val) |
925 | { | 937 | { |
926 | u32 read; | 938 | u32 read; |
927 | int count; | 939 | int count; |
@@ -1120,35 +1132,34 @@ DECLARE_COUNTER(2); | |||
1120 | * Sysfs struct | 1132 | * Sysfs struct |
1121 | */ | 1133 | */ |
1122 | 1134 | ||
1123 | 1135 | static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { | |
1124 | static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { | ||
1125 | ATTR_ADDR_MATCH(channel), | 1136 | ATTR_ADDR_MATCH(channel), |
1126 | ATTR_ADDR_MATCH(dimm), | 1137 | ATTR_ADDR_MATCH(dimm), |
1127 | ATTR_ADDR_MATCH(rank), | 1138 | ATTR_ADDR_MATCH(rank), |
1128 | ATTR_ADDR_MATCH(bank), | 1139 | ATTR_ADDR_MATCH(bank), |
1129 | ATTR_ADDR_MATCH(page), | 1140 | ATTR_ADDR_MATCH(page), |
1130 | ATTR_ADDR_MATCH(col), | 1141 | ATTR_ADDR_MATCH(col), |
1131 | { .attr = { .name = NULL } } | 1142 | { } /* End of list */ |
1132 | }; | 1143 | }; |
1133 | 1144 | ||
1134 | static struct mcidev_sysfs_group i7core_inject_addrmatch = { | 1145 | static const struct mcidev_sysfs_group i7core_inject_addrmatch = { |
1135 | .name = "inject_addrmatch", | 1146 | .name = "inject_addrmatch", |
1136 | .mcidev_attr = i7core_addrmatch_attrs, | 1147 | .mcidev_attr = i7core_addrmatch_attrs, |
1137 | }; | 1148 | }; |
1138 | 1149 | ||
1139 | static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = { | 1150 | static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = { |
1140 | ATTR_COUNTER(0), | 1151 | ATTR_COUNTER(0), |
1141 | ATTR_COUNTER(1), | 1152 | ATTR_COUNTER(1), |
1142 | ATTR_COUNTER(2), | 1153 | ATTR_COUNTER(2), |
1143 | { .attr = { .name = NULL } } | 1154 | { .attr = { .name = NULL } } |
1144 | }; | 1155 | }; |
1145 | 1156 | ||
1146 | static struct mcidev_sysfs_group i7core_udimm_counters = { | 1157 | static const struct mcidev_sysfs_group i7core_udimm_counters = { |
1147 | .name = "all_channel_counts", | 1158 | .name = "all_channel_counts", |
1148 | .mcidev_attr = i7core_udimm_counters_attrs, | 1159 | .mcidev_attr = i7core_udimm_counters_attrs, |
1149 | }; | 1160 | }; |
1150 | 1161 | ||
1151 | static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { | 1162 | static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = { |
1152 | { | 1163 | { |
1153 | .attr = { | 1164 | .attr = { |
1154 | .name = "inject_section", | 1165 | .name = "inject_section", |
@@ -1180,8 +1191,44 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { | |||
1180 | .show = i7core_inject_enable_show, | 1191 | .show = i7core_inject_enable_show, |
1181 | .store = i7core_inject_enable_store, | 1192 | .store = i7core_inject_enable_store, |
1182 | }, | 1193 | }, |
1183 | { .attr = { .name = NULL } }, /* Reserved for udimm counters */ | 1194 | { } /* End of list */ |
1184 | { .attr = { .name = NULL } } | 1195 | }; |
1196 | |||
1197 | static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = { | ||
1198 | { | ||
1199 | .attr = { | ||
1200 | .name = "inject_section", | ||
1201 | .mode = (S_IRUGO | S_IWUSR) | ||
1202 | }, | ||
1203 | .show = i7core_inject_section_show, | ||
1204 | .store = i7core_inject_section_store, | ||
1205 | }, { | ||
1206 | .attr = { | ||
1207 | .name = "inject_type", | ||
1208 | .mode = (S_IRUGO | S_IWUSR) | ||
1209 | }, | ||
1210 | .show = i7core_inject_type_show, | ||
1211 | .store = i7core_inject_type_store, | ||
1212 | }, { | ||
1213 | .attr = { | ||
1214 | .name = "inject_eccmask", | ||
1215 | .mode = (S_IRUGO | S_IWUSR) | ||
1216 | }, | ||
1217 | .show = i7core_inject_eccmask_show, | ||
1218 | .store = i7core_inject_eccmask_store, | ||
1219 | }, { | ||
1220 | .grp = &i7core_inject_addrmatch, | ||
1221 | }, { | ||
1222 | .attr = { | ||
1223 | .name = "inject_enable", | ||
1224 | .mode = (S_IRUGO | S_IWUSR) | ||
1225 | }, | ||
1226 | .show = i7core_inject_enable_show, | ||
1227 | .store = i7core_inject_enable_store, | ||
1228 | }, { | ||
1229 | .grp = &i7core_udimm_counters, | ||
1230 | }, | ||
1231 | { } /* End of list */ | ||
1185 | }; | 1232 | }; |
1186 | 1233 | ||
1187 | /**************************************************************************** | 1234 | /**************************************************************************** |
@@ -1189,7 +1236,7 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { | |||
1189 | ****************************************************************************/ | 1236 | ****************************************************************************/ |
1190 | 1237 | ||
1191 | /* | 1238 | /* |
1192 | * i7core_put_devices 'put' all the devices that we have | 1239 | * i7core_put_all_devices 'put' all the devices that we have |
1193 | * reserved via 'get' | 1240 | * reserved via 'get' |
1194 | */ | 1241 | */ |
1195 | static void i7core_put_devices(struct i7core_dev *i7core_dev) | 1242 | static void i7core_put_devices(struct i7core_dev *i7core_dev) |
@@ -1206,23 +1253,23 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) | |||
1206 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); | 1253 | PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); |
1207 | pci_dev_put(pdev); | 1254 | pci_dev_put(pdev); |
1208 | } | 1255 | } |
1209 | kfree(i7core_dev->pdev); | ||
1210 | list_del(&i7core_dev->list); | ||
1211 | kfree(i7core_dev); | ||
1212 | } | 1256 | } |
1213 | 1257 | ||
1214 | static void i7core_put_all_devices(void) | 1258 | static void i7core_put_all_devices(void) |
1215 | { | 1259 | { |
1216 | struct i7core_dev *i7core_dev, *tmp; | 1260 | struct i7core_dev *i7core_dev, *tmp; |
1217 | 1261 | ||
1218 | list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) | 1262 | list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { |
1219 | i7core_put_devices(i7core_dev); | 1263 | i7core_put_devices(i7core_dev); |
1264 | free_i7core_dev(i7core_dev); | ||
1265 | } | ||
1220 | } | 1266 | } |
1221 | 1267 | ||
1222 | static void __init i7core_xeon_pci_fixup(struct pci_id_table *table) | 1268 | static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table) |
1223 | { | 1269 | { |
1224 | struct pci_dev *pdev = NULL; | 1270 | struct pci_dev *pdev = NULL; |
1225 | int i; | 1271 | int i; |
1272 | |||
1226 | /* | 1273 | /* |
1227 | * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses | 1274 | * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses |
1228 | * aren't announced by acpi. So, we need to use a legacy scan probing | 1275 | * aren't announced by acpi. So, we need to use a legacy scan probing |
@@ -1257,16 +1304,18 @@ static unsigned i7core_pci_lastbus(void) | |||
1257 | } | 1304 | } |
1258 | 1305 | ||
1259 | /* | 1306 | /* |
1260 | * i7core_get_devices Find and perform 'get' operation on the MCH's | 1307 | * i7core_get_all_devices Find and perform 'get' operation on the MCH's |
1261 | * device/functions we want to reference for this driver | 1308 | * device/functions we want to reference for this driver |
1262 | * | 1309 | * |
1263 | * Need to 'get' device 16 func 1 and func 2 | 1310 | * Need to 'get' device 16 func 1 and func 2 |
1264 | */ | 1311 | */ |
1265 | int i7core_get_onedevice(struct pci_dev **prev, int devno, | 1312 | static int i7core_get_onedevice(struct pci_dev **prev, |
1266 | struct pci_id_descr *dev_descr, unsigned n_devs, | 1313 | const struct pci_id_table *table, |
1267 | unsigned last_bus) | 1314 | const unsigned devno, |
1315 | const unsigned last_bus) | ||
1268 | { | 1316 | { |
1269 | struct i7core_dev *i7core_dev; | 1317 | struct i7core_dev *i7core_dev; |
1318 | const struct pci_id_descr *dev_descr = &table->descr[devno]; | ||
1270 | 1319 | ||
1271 | struct pci_dev *pdev = NULL; | 1320 | struct pci_dev *pdev = NULL; |
1272 | u8 bus = 0; | 1321 | u8 bus = 0; |
@@ -1275,20 +1324,6 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, | |||
1275 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | 1324 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, |
1276 | dev_descr->dev_id, *prev); | 1325 | dev_descr->dev_id, *prev); |
1277 | 1326 | ||
1278 | /* | ||
1279 | * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs | ||
1280 | * is at addr 8086:2c40, instead of 8086:2c41. So, we need | ||
1281 | * to probe for the alternate address in case of failure | ||
1282 | */ | ||
1283 | if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) | ||
1284 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
1285 | PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); | ||
1286 | |||
1287 | if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) | ||
1288 | pdev = pci_get_device(PCI_VENDOR_ID_INTEL, | ||
1289 | PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, | ||
1290 | *prev); | ||
1291 | |||
1292 | if (!pdev) { | 1327 | if (!pdev) { |
1293 | if (*prev) { | 1328 | if (*prev) { |
1294 | *prev = pdev; | 1329 | *prev = pdev; |
@@ -1315,18 +1350,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, | |||
1315 | 1350 | ||
1316 | i7core_dev = get_i7core_dev(socket); | 1351 | i7core_dev = get_i7core_dev(socket); |
1317 | if (!i7core_dev) { | 1352 | if (!i7core_dev) { |
1318 | i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); | 1353 | i7core_dev = alloc_i7core_dev(socket, table); |
1319 | if (!i7core_dev) | 1354 | if (!i7core_dev) { |
1320 | return -ENOMEM; | 1355 | pci_dev_put(pdev); |
1321 | i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs, | ||
1322 | GFP_KERNEL); | ||
1323 | if (!i7core_dev->pdev) { | ||
1324 | kfree(i7core_dev); | ||
1325 | return -ENOMEM; | 1356 | return -ENOMEM; |
1326 | } | 1357 | } |
1327 | i7core_dev->socket = socket; | ||
1328 | i7core_dev->n_devs = n_devs; | ||
1329 | list_add_tail(&i7core_dev->list, &i7core_edac_list); | ||
1330 | } | 1358 | } |
1331 | 1359 | ||
1332 | if (i7core_dev->pdev[devno]) { | 1360 | if (i7core_dev->pdev[devno]) { |
@@ -1368,27 +1396,31 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, | |||
1368 | dev_descr->func, | 1396 | dev_descr->func, |
1369 | PCI_VENDOR_ID_INTEL, dev_descr->dev_id); | 1397 | PCI_VENDOR_ID_INTEL, dev_descr->dev_id); |
1370 | 1398 | ||
1399 | /* | ||
1400 | * As stated on drivers/pci/search.c, the reference count for | ||
1401 | * @from is always decremented if it is not %NULL. So, as we need | ||
1402 | * to get all devices up to null, we need to do a get for the device | ||
1403 | */ | ||
1404 | pci_dev_get(pdev); | ||
1405 | |||
1371 | *prev = pdev; | 1406 | *prev = pdev; |
1372 | 1407 | ||
1373 | return 0; | 1408 | return 0; |
1374 | } | 1409 | } |
1375 | 1410 | ||
1376 | static int i7core_get_devices(struct pci_id_table *table) | 1411 | static int i7core_get_all_devices(void) |
1377 | { | 1412 | { |
1378 | int i, rc, last_bus; | 1413 | int i, rc, last_bus; |
1379 | struct pci_dev *pdev = NULL; | 1414 | struct pci_dev *pdev = NULL; |
1380 | struct pci_id_descr *dev_descr; | 1415 | const struct pci_id_table *table = pci_dev_table; |
1381 | 1416 | ||
1382 | last_bus = i7core_pci_lastbus(); | 1417 | last_bus = i7core_pci_lastbus(); |
1383 | 1418 | ||
1384 | while (table && table->descr) { | 1419 | while (table && table->descr) { |
1385 | dev_descr = table->descr; | ||
1386 | for (i = 0; i < table->n_devs; i++) { | 1420 | for (i = 0; i < table->n_devs; i++) { |
1387 | pdev = NULL; | 1421 | pdev = NULL; |
1388 | do { | 1422 | do { |
1389 | rc = i7core_get_onedevice(&pdev, i, | 1423 | rc = i7core_get_onedevice(&pdev, table, i, |
1390 | &dev_descr[i], | ||
1391 | table->n_devs, | ||
1392 | last_bus); | 1424 | last_bus); |
1393 | if (rc < 0) { | 1425 | if (rc < 0) { |
1394 | if (i == 0) { | 1426 | if (i == 0) { |
@@ -1404,7 +1436,6 @@ static int i7core_get_devices(struct pci_id_table *table) | |||
1404 | } | 1436 | } |
1405 | 1437 | ||
1406 | return 0; | 1438 | return 0; |
1407 | return 0; | ||
1408 | } | 1439 | } |
1409 | 1440 | ||
1410 | static int mci_bind_devs(struct mem_ctl_info *mci, | 1441 | static int mci_bind_devs(struct mem_ctl_info *mci, |
@@ -1414,10 +1445,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci, | |||
1414 | struct pci_dev *pdev; | 1445 | struct pci_dev *pdev; |
1415 | int i, func, slot; | 1446 | int i, func, slot; |
1416 | 1447 | ||
1417 | /* Associates i7core_dev and mci for future usage */ | ||
1418 | pvt->i7core_dev = i7core_dev; | ||
1419 | i7core_dev->mci = mci; | ||
1420 | |||
1421 | pvt->is_registered = 0; | 1448 | pvt->is_registered = 0; |
1422 | for (i = 0; i < i7core_dev->n_devs; i++) { | 1449 | for (i = 0; i < i7core_dev->n_devs; i++) { |
1423 | pdev = i7core_dev->pdev[i]; | 1450 | pdev = i7core_dev->pdev[i]; |
@@ -1448,15 +1475,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci, | |||
1448 | pvt->is_registered = 1; | 1475 | pvt->is_registered = 1; |
1449 | } | 1476 | } |
1450 | 1477 | ||
1451 | /* | ||
1452 | * Add extra nodes to count errors on udimm | ||
1453 | * For registered memory, this is not needed, since the counters | ||
1454 | * are already displayed at the standard locations | ||
1455 | */ | ||
1456 | if (!pvt->is_registered) | ||
1457 | i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp = | ||
1458 | &i7core_udimm_counters; | ||
1459 | |||
1460 | return 0; | 1478 | return 0; |
1461 | 1479 | ||
1462 | error: | 1480 | error: |
@@ -1470,7 +1488,9 @@ error: | |||
1470 | Error check routines | 1488 | Error check routines |
1471 | ****************************************************************************/ | 1489 | ****************************************************************************/ |
1472 | static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, | 1490 | static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, |
1473 | int chan, int dimm, int add) | 1491 | const int chan, |
1492 | const int dimm, | ||
1493 | const int add) | ||
1474 | { | 1494 | { |
1475 | char *msg; | 1495 | char *msg; |
1476 | struct i7core_pvt *pvt = mci->pvt_info; | 1496 | struct i7core_pvt *pvt = mci->pvt_info; |
@@ -1487,7 +1507,10 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, | |||
1487 | } | 1507 | } |
1488 | 1508 | ||
1489 | static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, | 1509 | static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, |
1490 | int chan, int new0, int new1, int new2) | 1510 | const int chan, |
1511 | const int new0, | ||
1512 | const int new1, | ||
1513 | const int new2) | ||
1491 | { | 1514 | { |
1492 | struct i7core_pvt *pvt = mci->pvt_info; | 1515 | struct i7core_pvt *pvt = mci->pvt_info; |
1493 | int add0 = 0, add1 = 0, add2 = 0; | 1516 | int add0 = 0, add1 = 0, add2 = 0; |
@@ -1641,7 +1664,7 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci) | |||
1641 | * fields | 1664 | * fields |
1642 | */ | 1665 | */ |
1643 | static void i7core_mce_output_error(struct mem_ctl_info *mci, | 1666 | static void i7core_mce_output_error(struct mem_ctl_info *mci, |
1644 | struct mce *m) | 1667 | const struct mce *m) |
1645 | { | 1668 | { |
1646 | struct i7core_pvt *pvt = mci->pvt_info; | 1669 | struct i7core_pvt *pvt = mci->pvt_info; |
1647 | char *type, *optype, *err, *msg; | 1670 | char *type, *optype, *err, *msg; |
@@ -1845,28 +1868,85 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) | |||
1845 | return 1; | 1868 | return 1; |
1846 | } | 1869 | } |
1847 | 1870 | ||
1848 | static int i7core_register_mci(struct i7core_dev *i7core_dev, | 1871 | static void i7core_pci_ctl_create(struct i7core_pvt *pvt) |
1849 | int num_channels, int num_csrows) | 1872 | { |
1873 | pvt->i7core_pci = edac_pci_create_generic_ctl( | ||
1874 | &pvt->i7core_dev->pdev[0]->dev, | ||
1875 | EDAC_MOD_STR); | ||
1876 | if (unlikely(!pvt->i7core_pci)) | ||
1877 | pr_warn("Unable to setup PCI error report via EDAC\n"); | ||
1878 | } | ||
1879 | |||
1880 | static void i7core_pci_ctl_release(struct i7core_pvt *pvt) | ||
1881 | { | ||
1882 | if (likely(pvt->i7core_pci)) | ||
1883 | edac_pci_release_generic_ctl(pvt->i7core_pci); | ||
1884 | else | ||
1885 | i7core_printk(KERN_ERR, | ||
1886 | "Couldn't find mem_ctl_info for socket %d\n", | ||
1887 | pvt->i7core_dev->socket); | ||
1888 | pvt->i7core_pci = NULL; | ||
1889 | } | ||
1890 | |||
1891 | static void i7core_unregister_mci(struct i7core_dev *i7core_dev) | ||
1892 | { | ||
1893 | struct mem_ctl_info *mci = i7core_dev->mci; | ||
1894 | struct i7core_pvt *pvt; | ||
1895 | |||
1896 | if (unlikely(!mci || !mci->pvt_info)) { | ||
1897 | debugf0("MC: " __FILE__ ": %s(): dev = %p\n", | ||
1898 | __func__, &i7core_dev->pdev[0]->dev); | ||
1899 | |||
1900 | i7core_printk(KERN_ERR, "Couldn't find mci handler\n"); | ||
1901 | return; | ||
1902 | } | ||
1903 | |||
1904 | pvt = mci->pvt_info; | ||
1905 | |||
1906 | debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", | ||
1907 | __func__, mci, &i7core_dev->pdev[0]->dev); | ||
1908 | |||
1909 | /* Disable MCE NMI handler */ | ||
1910 | edac_mce_unregister(&pvt->edac_mce); | ||
1911 | |||
1912 | /* Disable EDAC polling */ | ||
1913 | i7core_pci_ctl_release(pvt); | ||
1914 | |||
1915 | /* Remove MC sysfs nodes */ | ||
1916 | edac_mc_del_mc(mci->dev); | ||
1917 | |||
1918 | debugf1("%s: free mci struct\n", mci->ctl_name); | ||
1919 | kfree(mci->ctl_name); | ||
1920 | edac_mc_free(mci); | ||
1921 | i7core_dev->mci = NULL; | ||
1922 | } | ||
1923 | |||
1924 | static int i7core_register_mci(struct i7core_dev *i7core_dev) | ||
1850 | { | 1925 | { |
1851 | struct mem_ctl_info *mci; | 1926 | struct mem_ctl_info *mci; |
1852 | struct i7core_pvt *pvt; | 1927 | struct i7core_pvt *pvt; |
1853 | int csrow = 0; | 1928 | int rc, channels, csrows; |
1854 | int rc; | 1929 | |
1930 | /* Check the number of active and not disabled channels */ | ||
1931 | rc = i7core_get_active_channels(i7core_dev->socket, &channels, &csrows); | ||
1932 | if (unlikely(rc < 0)) | ||
1933 | return rc; | ||
1855 | 1934 | ||
1856 | /* allocate a new MC control structure */ | 1935 | /* allocate a new MC control structure */ |
1857 | mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, | 1936 | mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, i7core_dev->socket); |
1858 | i7core_dev->socket); | ||
1859 | if (unlikely(!mci)) | 1937 | if (unlikely(!mci)) |
1860 | return -ENOMEM; | 1938 | return -ENOMEM; |
1861 | 1939 | ||
1862 | debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); | 1940 | debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", |
1863 | 1941 | __func__, mci, &i7core_dev->pdev[0]->dev); | |
1864 | /* record ptr to the generic device */ | ||
1865 | mci->dev = &i7core_dev->pdev[0]->dev; | ||
1866 | 1942 | ||
1867 | pvt = mci->pvt_info; | 1943 | pvt = mci->pvt_info; |
1868 | memset(pvt, 0, sizeof(*pvt)); | 1944 | memset(pvt, 0, sizeof(*pvt)); |
1869 | 1945 | ||
1946 | /* Associates i7core_dev and mci for future usage */ | ||
1947 | pvt->i7core_dev = i7core_dev; | ||
1948 | i7core_dev->mci = mci; | ||
1949 | |||
1870 | /* | 1950 | /* |
1871 | * FIXME: how to handle RDDR3 at MCI level? It is possible to have | 1951 | * FIXME: how to handle RDDR3 at MCI level? It is possible to have |
1872 | * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different | 1952 | * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different |
@@ -1881,17 +1961,23 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, | |||
1881 | i7core_dev->socket); | 1961 | i7core_dev->socket); |
1882 | mci->dev_name = pci_name(i7core_dev->pdev[0]); | 1962 | mci->dev_name = pci_name(i7core_dev->pdev[0]); |
1883 | mci->ctl_page_to_phys = NULL; | 1963 | mci->ctl_page_to_phys = NULL; |
1884 | mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs; | ||
1885 | /* Set the function pointer to an actual operation function */ | ||
1886 | mci->edac_check = i7core_check_error; | ||
1887 | 1964 | ||
1888 | /* Store pci devices at mci for faster access */ | 1965 | /* Store pci devices at mci for faster access */ |
1889 | rc = mci_bind_devs(mci, i7core_dev); | 1966 | rc = mci_bind_devs(mci, i7core_dev); |
1890 | if (unlikely(rc < 0)) | 1967 | if (unlikely(rc < 0)) |
1891 | goto fail; | 1968 | goto fail0; |
1969 | |||
1970 | if (pvt->is_registered) | ||
1971 | mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs; | ||
1972 | else | ||
1973 | mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs; | ||
1892 | 1974 | ||
1893 | /* Get dimm basic config */ | 1975 | /* Get dimm basic config */ |
1894 | get_dimm_config(mci, &csrow); | 1976 | get_dimm_config(mci); |
1977 | /* record ptr to the generic device */ | ||
1978 | mci->dev = &i7core_dev->pdev[0]->dev; | ||
1979 | /* Set the function pointer to an actual operation function */ | ||
1980 | mci->edac_check = i7core_check_error; | ||
1895 | 1981 | ||
1896 | /* add this new MC control structure to EDAC's list of MCs */ | 1982 | /* add this new MC control structure to EDAC's list of MCs */ |
1897 | if (unlikely(edac_mc_add_mc(mci))) { | 1983 | if (unlikely(edac_mc_add_mc(mci))) { |
@@ -1902,19 +1988,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, | |||
1902 | */ | 1988 | */ |
1903 | 1989 | ||
1904 | rc = -EINVAL; | 1990 | rc = -EINVAL; |
1905 | goto fail; | 1991 | goto fail0; |
1906 | } | ||
1907 | |||
1908 | /* allocating generic PCI control info */ | ||
1909 | i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, | ||
1910 | EDAC_MOD_STR); | ||
1911 | if (unlikely(!i7core_pci)) { | ||
1912 | printk(KERN_WARNING | ||
1913 | "%s(): Unable to create PCI control\n", | ||
1914 | __func__); | ||
1915 | printk(KERN_WARNING | ||
1916 | "%s(): PCI error report via EDAC not setup\n", | ||
1917 | __func__); | ||
1918 | } | 1992 | } |
1919 | 1993 | ||
1920 | /* Default error mask is any memory */ | 1994 | /* Default error mask is any memory */ |
@@ -1925,19 +1999,28 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, | |||
1925 | pvt->inject.page = -1; | 1999 | pvt->inject.page = -1; |
1926 | pvt->inject.col = -1; | 2000 | pvt->inject.col = -1; |
1927 | 2001 | ||
2002 | /* allocating generic PCI control info */ | ||
2003 | i7core_pci_ctl_create(pvt); | ||
2004 | |||
1928 | /* Registers on edac_mce in order to receive memory errors */ | 2005 | /* Registers on edac_mce in order to receive memory errors */ |
1929 | pvt->edac_mce.priv = mci; | 2006 | pvt->edac_mce.priv = mci; |
1930 | pvt->edac_mce.check_error = i7core_mce_check_error; | 2007 | pvt->edac_mce.check_error = i7core_mce_check_error; |
1931 | |||
1932 | rc = edac_mce_register(&pvt->edac_mce); | 2008 | rc = edac_mce_register(&pvt->edac_mce); |
1933 | if (unlikely(rc < 0)) { | 2009 | if (unlikely(rc < 0)) { |
1934 | debugf0("MC: " __FILE__ | 2010 | debugf0("MC: " __FILE__ |
1935 | ": %s(): failed edac_mce_register()\n", __func__); | 2011 | ": %s(): failed edac_mce_register()\n", __func__); |
2012 | goto fail1; | ||
1936 | } | 2013 | } |
1937 | 2014 | ||
1938 | fail: | 2015 | return 0; |
1939 | if (rc < 0) | 2016 | |
1940 | edac_mc_free(mci); | 2017 | fail1: |
2018 | i7core_pci_ctl_release(pvt); | ||
2019 | edac_mc_del_mc(mci->dev); | ||
2020 | fail0: | ||
2021 | kfree(mci->ctl_name); | ||
2022 | edac_mc_free(mci); | ||
2023 | i7core_dev->mci = NULL; | ||
1941 | return rc; | 2024 | return rc; |
1942 | } | 2025 | } |
1943 | 2026 | ||
@@ -1949,8 +2032,6 @@ fail: | |||
1949 | * < 0 for error code | 2032 | * < 0 for error code |
1950 | */ | 2033 | */ |
1951 | 2034 | ||
1952 | static int probed = 0; | ||
1953 | |||
1954 | static int __devinit i7core_probe(struct pci_dev *pdev, | 2035 | static int __devinit i7core_probe(struct pci_dev *pdev, |
1955 | const struct pci_device_id *id) | 2036 | const struct pci_device_id *id) |
1956 | { | 2037 | { |
@@ -1965,25 +2046,16 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1965 | */ | 2046 | */ |
1966 | if (unlikely(probed >= 1)) { | 2047 | if (unlikely(probed >= 1)) { |
1967 | mutex_unlock(&i7core_edac_lock); | 2048 | mutex_unlock(&i7core_edac_lock); |
1968 | return -EINVAL; | 2049 | return -ENODEV; |
1969 | } | 2050 | } |
1970 | probed++; | 2051 | probed++; |
1971 | 2052 | ||
1972 | rc = i7core_get_devices(pci_dev_table); | 2053 | rc = i7core_get_all_devices(); |
1973 | if (unlikely(rc < 0)) | 2054 | if (unlikely(rc < 0)) |
1974 | goto fail0; | 2055 | goto fail0; |
1975 | 2056 | ||
1976 | list_for_each_entry(i7core_dev, &i7core_edac_list, list) { | 2057 | list_for_each_entry(i7core_dev, &i7core_edac_list, list) { |
1977 | int channels; | 2058 | rc = i7core_register_mci(i7core_dev); |
1978 | int csrows; | ||
1979 | |||
1980 | /* Check the number of active and not disabled channels */ | ||
1981 | rc = i7core_get_active_channels(i7core_dev->socket, | ||
1982 | &channels, &csrows); | ||
1983 | if (unlikely(rc < 0)) | ||
1984 | goto fail1; | ||
1985 | |||
1986 | rc = i7core_register_mci(i7core_dev, channels, csrows); | ||
1987 | if (unlikely(rc < 0)) | 2059 | if (unlikely(rc < 0)) |
1988 | goto fail1; | 2060 | goto fail1; |
1989 | } | 2061 | } |
@@ -1994,6 +2066,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev, | |||
1994 | return 0; | 2066 | return 0; |
1995 | 2067 | ||
1996 | fail1: | 2068 | fail1: |
2069 | list_for_each_entry(i7core_dev, &i7core_edac_list, list) | ||
2070 | i7core_unregister_mci(i7core_dev); | ||
2071 | |||
1997 | i7core_put_all_devices(); | 2072 | i7core_put_all_devices(); |
1998 | fail0: | 2073 | fail0: |
1999 | mutex_unlock(&i7core_edac_lock); | 2074 | mutex_unlock(&i7core_edac_lock); |
@@ -2006,14 +2081,10 @@ fail0: | |||
2006 | */ | 2081 | */ |
2007 | static void __devexit i7core_remove(struct pci_dev *pdev) | 2082 | static void __devexit i7core_remove(struct pci_dev *pdev) |
2008 | { | 2083 | { |
2009 | struct mem_ctl_info *mci; | 2084 | struct i7core_dev *i7core_dev; |
2010 | struct i7core_dev *i7core_dev, *tmp; | ||
2011 | 2085 | ||
2012 | debugf0(__FILE__ ": %s()\n", __func__); | 2086 | debugf0(__FILE__ ": %s()\n", __func__); |
2013 | 2087 | ||
2014 | if (i7core_pci) | ||
2015 | edac_pci_release_generic_ctl(i7core_pci); | ||
2016 | |||
2017 | /* | 2088 | /* |
2018 | * we have a trouble here: pdev value for removal will be wrong, since | 2089 | * we have a trouble here: pdev value for removal will be wrong, since |
2019 | * it will point to the X58 register used to detect that the machine | 2090 | * it will point to the X58 register used to detect that the machine |
@@ -2023,22 +2094,18 @@ static void __devexit i7core_remove(struct pci_dev *pdev) | |||
2023 | */ | 2094 | */ |
2024 | 2095 | ||
2025 | mutex_lock(&i7core_edac_lock); | 2096 | mutex_lock(&i7core_edac_lock); |
2026 | list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { | 2097 | |
2027 | mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev); | 2098 | if (unlikely(!probed)) { |
2028 | if (mci) { | 2099 | mutex_unlock(&i7core_edac_lock); |
2029 | struct i7core_pvt *pvt = mci->pvt_info; | 2100 | return; |
2030 | |||
2031 | i7core_dev = pvt->i7core_dev; | ||
2032 | edac_mce_unregister(&pvt->edac_mce); | ||
2033 | kfree(mci->ctl_name); | ||
2034 | edac_mc_free(mci); | ||
2035 | i7core_put_devices(i7core_dev); | ||
2036 | } else { | ||
2037 | i7core_printk(KERN_ERR, | ||
2038 | "Couldn't find mci for socket %d\n", | ||
2039 | i7core_dev->socket); | ||
2040 | } | ||
2041 | } | 2101 | } |
2102 | |||
2103 | list_for_each_entry(i7core_dev, &i7core_edac_list, list) | ||
2104 | i7core_unregister_mci(i7core_dev); | ||
2105 | |||
2106 | /* Release PCI resources */ | ||
2107 | i7core_put_all_devices(); | ||
2108 | |||
2042 | probed--; | 2109 | probed--; |
2043 | 2110 | ||
2044 | mutex_unlock(&i7core_edac_lock); | 2111 | mutex_unlock(&i7core_edac_lock); |
@@ -2070,7 +2137,8 @@ static int __init i7core_init(void) | |||
2070 | /* Ensure that the OPSTATE is set correctly for POLL or NMI */ | 2137 | /* Ensure that the OPSTATE is set correctly for POLL or NMI */ |
2071 | opstate_init(); | 2138 | opstate_init(); |
2072 | 2139 | ||
2073 | i7core_xeon_pci_fixup(pci_dev_table); | 2140 | if (use_pci_fixup) |
2141 | i7core_xeon_pci_fixup(pci_dev_table); | ||
2074 | 2142 | ||
2075 | pci_rc = pci_register_driver(&i7core_driver); | 2143 | pci_rc = pci_register_driver(&i7core_driver); |
2076 | 2144 | ||