diff options
| -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 | ||
