From 939747bd680eb09bb98792b17a5bfd2f525afe9d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Aug 2010 11:22:01 -0300 Subject: [PATCH 01/34] i7core_edac: Be sure that the edac pci handler will be properly released With multi-sockets, more than one edac pci handler is enabled. Be sure to un-register all instances. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 1 + drivers/edac/edac_mc.c | 6 ++++-- drivers/edac/i7core_edac.c | 38 +++++++++++++++++++++++--------------- 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index ce7146677e9b..7450fd3bdf0b 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -810,6 +810,7 @@ extern struct mem_ctl_info *edac_mc_alloc(unsigned sz_pvt, unsigned nr_csrows, extern int edac_mc_add_mc(struct mem_ctl_info *mci); extern void edac_mc_free(struct mem_ctl_info *mci); extern struct mem_ctl_info *edac_mc_find(int idx); +extern struct mem_ctl_info *find_mci_by_dev(struct device *dev); extern struct mem_ctl_info *edac_mc_del_mc(struct device *dev); extern int edac_mc_find_csrow_by_page(struct mem_ctl_info *mci, unsigned long page); diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 6b21e25f7a84..6b7e723e46be 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -239,13 +239,14 @@ void edac_mc_free(struct mem_ctl_info *mci) EXPORT_SYMBOL_GPL(edac_mc_free); -/* +/** * find_mci_by_dev * * scan list of controllers looking for the one that manages * the 'dev' device + * @dev: pointer to a struct device related with the MCI */ -static struct mem_ctl_info *find_mci_by_dev(struct device *dev) +struct mem_ctl_info *find_mci_by_dev(struct device *dev) { struct mem_ctl_info *mci; struct list_head *item; @@ -261,6 +262,7 @@ static struct mem_ctl_info *find_mci_by_dev(struct device *dev) return NULL; } +EXPORT_SYMBOL_GPL(find_mci_by_dev); /* * handler for EDAC to check if NMI type handler has asserted interrupt diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0fd5b85a0f75..414182719640 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -261,6 +261,9 @@ struct i7core_pvt { /* Count indicator to show errors not got */ unsigned mce_overrun; + + /* Struct to control EDAC polling */ + struct edac_pci_ctl_info *i7core_pci; }; /* Static vars */ @@ -378,8 +381,6 @@ static const struct pci_device_id i7core_pci_tbl[] __devinitdata = { {0,} /* 0 terminated list. */ }; -static struct edac_pci_ctl_info *i7core_pci; - /**************************************************************************** Anciliary status routines ****************************************************************************/ @@ -1906,9 +1907,9 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, } /* allocating generic PCI control info */ - i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, + pvt->i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, EDAC_MOD_STR); - if (unlikely(!i7core_pci)) { + if (unlikely(!pvt->i7core_pci)) { printk(KERN_WARNING "%s(): Unable to create PCI control\n", __func__); @@ -2008,12 +2009,10 @@ static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; struct i7core_dev *i7core_dev, *tmp; + struct i7core_pvt *pvt; debugf0(__FILE__ ": %s()\n", __func__); - if (i7core_pci) - edac_pci_release_generic_ctl(i7core_pci); - /* * we have a trouble here: pdev value for removal will be wrong, since * it will point to the X58 register used to detect that the machine @@ -2024,19 +2023,28 @@ static void __devexit i7core_remove(struct pci_dev *pdev) mutex_lock(&i7core_edac_lock); list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { - mci = edac_mc_del_mc(&i7core_dev->pdev[0]->dev); - if (mci) { - struct i7core_pvt *pvt = mci->pvt_info; - + mci = find_mci_by_dev(&i7core_dev->pdev[0]->dev); + if (unlikely(!mci || !mci->pvt_info)) { + i7core_printk(KERN_ERR, + "Couldn't find mci hanler\n"); + } else { + pvt = mci->pvt_info; i7core_dev = pvt->i7core_dev; + + if (likely(pvt->i7core_pci)) + edac_pci_release_generic_ctl(pvt->i7core_pci); + else + i7core_printk(KERN_ERR, + "Couldn't find mem_ctl_info for socket %d\n", + i7core_dev->socket); + pvt->i7core_pci = NULL; + + edac_mc_del_mc(&i7core_dev->pdev[0]->dev); + edac_mce_unregister(&pvt->edac_mce); kfree(mci->ctl_name); edac_mc_free(mci); i7core_put_devices(i7core_dev); - } else { - i7core_printk(KERN_ERR, - "Couldn't find mci for socket %d\n", - i7core_dev->socket); } } probed--; From 18c29002f95bc2f67c1c78d7fc7932843aa66657 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Aug 2010 18:33:27 -0300 Subject: [PATCH 02/34] i7core_edac: move static vars to the beginning of the file While here, don't initialize probed with 0. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 414182719640..4c1dcc1f562e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -39,6 +39,11 @@ #include "edac_core.h" +/* Static vars */ +static LIST_HEAD(i7core_edac_list); +static DEFINE_MUTEX(i7core_edac_lock); +static int probed; + /* * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core * registers start at bus 255, and are not reported by BIOS. @@ -266,10 +271,6 @@ struct i7core_pvt { struct edac_pci_ctl_info *i7core_pci; }; -/* Static vars */ -static LIST_HEAD(i7core_edac_list); -static DEFINE_MUTEX(i7core_edac_lock); - #define PCI_DESCR(device, function, device_id) \ .dev = (device), \ .func = (function), \ @@ -1950,8 +1951,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, * < 0 for error code */ -static int probed = 0; - static int __devinit i7core_probe(struct pci_dev *pdev, const struct pci_device_id *id) { From 1288c18f48d9bf373dbed6b688cde36dc970b1ed Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Aug 2010 18:57:01 -0300 Subject: [PATCH 03/34] i7core_edac: Properly mark const static vars as such There are two groups of sysfs attributes: one for rdimm and another for udimm. Instead of changing dynamically the unique static struct for handling udimm's, declare two vars and make them constant. This avoids the risk of having two or more memory controllers, each needing a different set of attributes. While here, use const on all places where it is applicable. Signed-off-by: Mauro Carvalho Chehab edac_core: use const for constant sysfs arguments Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 8 +-- drivers/edac/edac_mc_sysfs.c | 4 +- drivers/edac/i7core_edac.c | 117 +++++++++++++++++++++++------------ 3 files changed, 83 insertions(+), 46 deletions(-) diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 7450fd3bdf0b..69eb1c268f9f 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -328,7 +328,7 @@ struct csrow_info { struct mcidev_sysfs_group { const char *name; /* group name */ - struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */ + const struct mcidev_sysfs_attribute *mcidev_attr; /* group attributes */ }; struct mcidev_sysfs_group_kobj { @@ -336,7 +336,7 @@ struct mcidev_sysfs_group_kobj { struct kobject kobj; /* kobj for the group */ - struct mcidev_sysfs_group *grp; /* group description table */ + const struct mcidev_sysfs_group *grp; /* group description table */ struct mem_ctl_info *mci; /* the parent */ }; @@ -347,7 +347,7 @@ struct mcidev_sysfs_group_kobj { struct mcidev_sysfs_attribute { /* It should use either attr or grp */ struct attribute attr; - struct mcidev_sysfs_group *grp; /* Points to a group of attributes */ + const struct mcidev_sysfs_group *grp; /* Points to a group of attributes */ /* Ops for show/store values at the attribute - not used on group */ ssize_t (*show)(struct mem_ctl_info *,char *); @@ -440,7 +440,7 @@ struct mem_ctl_info { * If attributes are desired, then set to array of attributes * If no attributes are desired, leave NULL */ - struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; + const struct mcidev_sysfs_attribute *mc_driver_sysfs_attributes; /* work struct for this MC */ struct delayed_work work; diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 8aad94d10c0c..aacffe5d0f33 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -783,7 +783,7 @@ static struct kobj_type ktype_inst_grp = { * object tree. */ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, - struct mcidev_sysfs_attribute *sysfs_attrib, + const struct mcidev_sysfs_attribute *sysfs_attrib, struct kobject *kobj) { int err; @@ -842,7 +842,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, * directory of this mci instance. */ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, - struct mcidev_sysfs_attribute *sysfs_attrib, + const struct mcidev_sysfs_attribute *sysfs_attrib, struct kobject *kobj, int count) { struct mcidev_sysfs_group_kobj *grp_kobj, *tmp; diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4c1dcc1f562e..5d15daaec8b8 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -217,8 +217,8 @@ struct pci_id_descr { }; struct pci_id_table { - struct pci_id_descr *descr; - int n_devs; + const struct pci_id_descr *descr; + int n_devs; }; struct i7core_dev { @@ -276,7 +276,7 @@ struct i7core_pvt { .func = (function), \ .dev_id = (device_id) -struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { +static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, @@ -313,7 +313,7 @@ struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { }; -struct pci_id_descr pci_dev_descr_lynnfield[] = { +static const struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR) }, { PCI_DESCR( 3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD) }, { PCI_DESCR( 3, 4, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TEST) }, @@ -335,7 +335,7 @@ struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, }; -struct pci_id_descr pci_dev_descr_i7core_westmere[] = { +static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_MCR_REV2) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_TAD_REV2) }, @@ -366,8 +366,8 @@ struct pci_id_descr pci_dev_descr_i7core_westmere[] = { }; -#define PCI_ID_TABLE_ENTRY(A) { A, ARRAY_SIZE(A) } -struct pci_id_table pci_dev_table[] = { +#define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) } +static const struct pci_id_table pci_dev_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem), PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield), PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere), @@ -486,7 +486,7 @@ static struct pci_dev *get_pdev_slot_func(u8 socket, unsigned slot, * to add a fake description for csrows. * So, this driver is attributing one DIMM memory for one csrow. */ -static int i7core_get_active_channels(u8 socket, unsigned *channels, +static int i7core_get_active_channels(const u8 socket, unsigned *channels, unsigned *csrows) { struct pci_dev *pdev = NULL; @@ -547,7 +547,7 @@ static int i7core_get_active_channels(u8 socket, unsigned *channels, return 0; } -static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) +static int get_dimm_config(const struct mem_ctl_info *mci, int *csrow) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; @@ -738,7 +738,7 @@ static int get_dimm_config(struct mem_ctl_info *mci, int *csrow) we're disabling error injection on all write calls to the sysfs nodes that controls the error code injection. */ -static int disable_inject(struct mem_ctl_info *mci) +static int disable_inject(const struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; @@ -923,7 +923,7 @@ DECLARE_ADDR_MATCH(bank, 32); DECLARE_ADDR_MATCH(page, 0x10000); DECLARE_ADDR_MATCH(col, 0x4000); -static int write_and_test(struct pci_dev *dev, int where, u32 val) +static int write_and_test(struct pci_dev *dev, const int where, const u32 val) { u32 read; int count; @@ -1122,35 +1122,34 @@ DECLARE_COUNTER(2); * Sysfs struct */ - -static struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { +static const struct mcidev_sysfs_attribute i7core_addrmatch_attrs[] = { ATTR_ADDR_MATCH(channel), ATTR_ADDR_MATCH(dimm), ATTR_ADDR_MATCH(rank), ATTR_ADDR_MATCH(bank), ATTR_ADDR_MATCH(page), ATTR_ADDR_MATCH(col), - { .attr = { .name = NULL } } + { } /* End of list */ }; -static struct mcidev_sysfs_group i7core_inject_addrmatch = { +static const struct mcidev_sysfs_group i7core_inject_addrmatch = { .name = "inject_addrmatch", .mcidev_attr = i7core_addrmatch_attrs, }; -static struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = { +static const struct mcidev_sysfs_attribute i7core_udimm_counters_attrs[] = { ATTR_COUNTER(0), ATTR_COUNTER(1), ATTR_COUNTER(2), { .attr = { .name = NULL } } }; -static struct mcidev_sysfs_group i7core_udimm_counters = { +static const struct mcidev_sysfs_group i7core_udimm_counters = { .name = "all_channel_counts", .mcidev_attr = i7core_udimm_counters_attrs, }; -static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { +static const struct mcidev_sysfs_attribute i7core_sysfs_rdimm_attrs[] = { { .attr = { .name = "inject_section", @@ -1182,8 +1181,44 @@ static struct mcidev_sysfs_attribute i7core_sysfs_attrs[] = { .show = i7core_inject_enable_show, .store = i7core_inject_enable_store, }, - { .attr = { .name = NULL } }, /* Reserved for udimm counters */ - { .attr = { .name = NULL } } + { } /* End of list */ +}; + +static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = { + { + .attr = { + .name = "inject_section", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_section_show, + .store = i7core_inject_section_store, + }, { + .attr = { + .name = "inject_type", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_type_show, + .store = i7core_inject_type_store, + }, { + .attr = { + .name = "inject_eccmask", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_eccmask_show, + .store = i7core_inject_eccmask_store, + }, { + .grp = &i7core_inject_addrmatch, + }, { + .attr = { + .name = "inject_enable", + .mode = (S_IRUGO | S_IWUSR) + }, + .show = i7core_inject_enable_show, + .store = i7core_inject_enable_store, + }, { + .grp = &i7core_udimm_counters, + }, + { } /* End of list */ }; /**************************************************************************** @@ -1221,7 +1256,7 @@ static void i7core_put_all_devices(void) i7core_put_devices(i7core_dev); } -static void __init i7core_xeon_pci_fixup(struct pci_id_table *table) +static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table) { struct pci_dev *pdev = NULL; int i; @@ -1264,9 +1299,10 @@ static unsigned i7core_pci_lastbus(void) * * Need to 'get' device 16 func 1 and func 2 */ -int i7core_get_onedevice(struct pci_dev **prev, int devno, - struct pci_id_descr *dev_descr, unsigned n_devs, - unsigned last_bus) +int i7core_get_onedevice(struct pci_dev **prev, const int devno, + const struct pci_id_descr *dev_descr, + const unsigned n_devs, + const unsigned last_bus) { struct i7core_dev *i7core_dev; @@ -1375,11 +1411,11 @@ int i7core_get_onedevice(struct pci_dev **prev, int devno, return 0; } -static int i7core_get_devices(struct pci_id_table *table) +static int i7core_get_devices(const struct pci_id_table *table) { int i, rc, last_bus; struct pci_dev *pdev = NULL; - struct pci_id_descr *dev_descr; + const struct pci_id_descr *dev_descr; last_bus = i7core_pci_lastbus(); @@ -1450,15 +1486,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci, pvt->is_registered = 1; } - /* - * Add extra nodes to count errors on udimm - * For registered memory, this is not needed, since the counters - * are already displayed at the standard locations - */ - if (!pvt->is_registered) - i7core_sysfs_attrs[ARRAY_SIZE(i7core_sysfs_attrs)-2].grp = - &i7core_udimm_counters; - return 0; error: @@ -1472,7 +1499,9 @@ static int mci_bind_devs(struct mem_ctl_info *mci, Error check routines ****************************************************************************/ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, - int chan, int dimm, int add) + const int chan, + const int dimm, + const int add) { char *msg; struct i7core_pvt *pvt = mci->pvt_info; @@ -1489,7 +1518,10 @@ static void i7core_rdimm_update_csrow(struct mem_ctl_info *mci, } static void i7core_rdimm_update_ce_count(struct mem_ctl_info *mci, - int chan, int new0, int new1, int new2) + const int chan, + const int new0, + const int new1, + const int new2) { struct i7core_pvt *pvt = mci->pvt_info; int add0 = 0, add1 = 0, add2 = 0; @@ -1643,7 +1675,7 @@ static void i7core_udimm_check_mc_ecc_err(struct mem_ctl_info *mci) * fields */ static void i7core_mce_output_error(struct mem_ctl_info *mci, - struct mce *m) + const struct mce *m) { struct i7core_pvt *pvt = mci->pvt_info; char *type, *optype, *err, *msg; @@ -1848,7 +1880,7 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) } static int i7core_register_mci(struct i7core_dev *i7core_dev, - int num_channels, int num_csrows) + const int num_channels, const int num_csrows) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; @@ -1883,7 +1915,12 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, i7core_dev->socket); mci->dev_name = pci_name(i7core_dev->pdev[0]); mci->ctl_page_to_phys = NULL; - mci->mc_driver_sysfs_attributes = i7core_sysfs_attrs; + + if (pvt->is_registered) + mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs; + else + mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs; + /* Set the function pointer to an actual operation function */ mci->edac_check = i7core_check_error; From e9144601d364d5b81f3e63949337f8507eb58dca Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Aug 2010 20:26:35 -0300 Subject: [PATCH 04/34] i7core_edac: move #if PAGE_SHIFT to edac_core.h Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_core.h | 2 ++ drivers/edac/i7core_edac.c | 6 +----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/edac/edac_core.h b/drivers/edac/edac_core.h index 69eb1c268f9f..d7ca43a828bd 100644 --- a/drivers/edac/edac_core.h +++ b/drivers/edac/edac_core.h @@ -42,8 +42,10 @@ #if PAGE_SHIFT < 20 #define PAGES_TO_MiB( pages ) ( ( pages ) >> ( 20 - PAGE_SHIFT ) ) +#define MiB_TO_PAGES(mb) ((mb) >> (20 - PAGE_SHIFT)) #else /* PAGE_SHIFT > 20 */ #define PAGES_TO_MiB( pages ) ( ( pages ) << ( PAGE_SHIFT - 20 ) ) +#define MiB_TO_PAGES(mb) ((mb) >> (PAGE_SHIFT - 20)) #endif #define edac_printk(level, prefix, fmt, arg...) \ diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 5d15daaec8b8..36b4e1422838 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -666,11 +666,7 @@ static int get_dimm_config(const struct mem_ctl_info *mci, int *csrow) RANKOFFSET(dimm_dod[j]), banks, ranks, rows, cols); -#if PAGE_SHIFT > 20 - npages = size >> (PAGE_SHIFT - 20); -#else - npages = size << (20 - PAGE_SHIFT); -#endif + npages = MiB_TO_PAGES(size); csr = &mci->csrows[*csrow]; csr->first_page = last_page + 1; From 3cfd01468b98360ede8cc8849d14e586253d290c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Aug 2010 23:23:46 -0300 Subject: [PATCH 05/34] i7core_edac: Improve debug to seek for register/remove errors Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 36b4e1422838..a05f166d8917 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1889,7 +1889,8 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, if (unlikely(!mci)) return -ENOMEM; - debugf0("MC: " __FILE__ ": %s(): mci = %p\n", __func__, mci); + debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", + __func__, mci, &i7core_dev->pdev[0]->dev); /* record ptr to the generic device */ mci->dev = &i7core_dev->pdev[0]->dev; @@ -2057,12 +2058,18 @@ static void __devexit i7core_remove(struct pci_dev *pdev) list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { mci = find_mci_by_dev(&i7core_dev->pdev[0]->dev); if (unlikely(!mci || !mci->pvt_info)) { - i7core_printk(KERN_ERR, + debugf0("MC: " __FILE__ ": %s(): dev = %p\n", + __func__, &i7core_dev->pdev[0]->dev); + + i7core_printk(KERN_ERR, "Couldn't find mci hanler\n"); } else { pvt = mci->pvt_info; i7core_dev = pvt->i7core_dev; + debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", + __func__, mci, &i7core_dev->pdev[0]->dev); + if (likely(pvt->i7core_pci)) edac_pci_release_generic_ctl(pvt->i7core_pci); else From 6ee7dd504490f3dc25cfe1c9be5b6e8895f89a92 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 10 Aug 2010 23:24:16 -0300 Subject: [PATCH 06/34] i7core_edac: Initialize all priv vars before start polling Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index a05f166d8917..d2b2ed8915fd 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1941,18 +1941,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, goto fail; } - /* allocating generic PCI control info */ - pvt->i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, - EDAC_MOD_STR); - if (unlikely(!pvt->i7core_pci)) { - printk(KERN_WARNING - "%s(): Unable to create PCI control\n", - __func__); - printk(KERN_WARNING - "%s(): PCI error report via EDAC not setup\n", - __func__); - } - /* Default error mask is any memory */ pvt->inject.channel = 0; pvt->inject.dimm = -1; @@ -1965,6 +1953,18 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, pvt->edac_mce.priv = mci; pvt->edac_mce.check_error = i7core_mce_check_error; + /* allocating generic PCI control info */ + pvt->i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, + EDAC_MOD_STR); + if (unlikely(!pvt->i7core_pci)) { + printk(KERN_WARNING + "%s(): Unable to create PCI control\n", + __func__); + printk(KERN_WARNING + "%s(): PCI error report via EDAC not setup\n", + __func__); + } + rc = edac_mce_register(&pvt->edac_mce); if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ From 41ba6c10586dfab632725cd532677ae5ae460e3e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Aug 2010 00:58:11 -0300 Subject: [PATCH 07/34] i7core_edac: MCE NMI handling should stop first Otherwise, a NMI may happen causing a race condition and a panic. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index d2b2ed8915fd..e5aa06e6389e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2070,6 +2070,10 @@ static void __devexit i7core_remove(struct pci_dev *pdev) debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", __func__, mci, &i7core_dev->pdev[0]->dev); + /* Disable MCE NMI handler */ + edac_mce_unregister(&pvt->edac_mce); + + /* Disable EDAC polling */ if (likely(pvt->i7core_pci)) edac_pci_release_generic_ctl(pvt->i7core_pci); else @@ -2078,11 +2082,14 @@ static void __devexit i7core_remove(struct pci_dev *pdev) i7core_dev->socket); pvt->i7core_pci = NULL; + /* Remove MC sysfs nodes */ edac_mc_del_mc(&i7core_dev->pdev[0]->dev); - edac_mce_unregister(&pvt->edac_mce); + /* Free data */ kfree(mci->ctl_name); edac_mc_free(mci); + + /* Release PCI resources */ i7core_put_devices(i7core_dev); } } From 39300e7143f8ef81b07cee3d8b86880bc4311ea0 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 11 Aug 2010 23:40:15 -0300 Subject: [PATCH 08/34] i7core_edac: explicitly remove PCI devices from the devices list Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e5aa06e6389e..11c61b4d8149 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1240,16 +1240,17 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) pci_dev_put(pdev); } kfree(i7core_dev->pdev); - list_del(&i7core_dev->list); - kfree(i7core_dev); } static void i7core_put_all_devices(void) { struct i7core_dev *i7core_dev, *tmp; - list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) + list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { i7core_put_devices(i7core_dev); + list_del(&i7core_dev->list); + kfree(i7core_dev); + } } static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table) @@ -1438,7 +1439,6 @@ static int i7core_get_devices(const struct pci_id_table *table) } return 0; - return 0; } static int mci_bind_devs(struct mem_ctl_info *mci, @@ -2092,6 +2092,8 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* Release PCI resources */ i7core_put_devices(i7core_dev); } + list_del(&i7core_dev->list); + kfree(i7core_dev); } probed--; From 6fe1108f14f4f9581af97cab752f37dc8fa9fdec Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Aug 2010 00:30:25 -0300 Subject: [PATCH 09/34] edac_core: Do a better job with node removal Make sure we remove groups at the right order Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_mc.c | 1 + drivers/edac/edac_mc_sysfs.c | 71 +++++++++++++++++++++--------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 6b7e723e46be..b10b45cc7870 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, } mci->op_state = OP_ALLOC; + INIT_LIST_HEAD(&mci->grp_kobj_list); /* * Initialize the 'root' kobj for the edac_mc controller diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index aacffe5d0f33..5a5734c1f6a5 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -791,6 +791,7 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, debugf1("%s()\n", __func__); while (sysfs_attrib) { + debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); if (sysfs_attrib->grp) { struct mcidev_sysfs_group_kobj *grp_kobj; @@ -798,10 +799,9 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, if (!grp_kobj) return -ENOMEM; - list_add_tail(&grp_kobj->list, &mci->grp_kobj_list); - grp_kobj->grp = sysfs_attrib->grp; grp_kobj->mci = mci; + list_add_tail(&grp_kobj->list, &mci->grp_kobj_list); debugf0("%s() grp %s, mci %p\n", __func__, sysfs_attrib->grp->name, mci); @@ -810,26 +810,28 @@ static int edac_create_mci_instance_attributes(struct mem_ctl_info *mci, &ktype_inst_grp, &mci->edac_mci_kobj, sysfs_attrib->grp->name); - if (err) + if (err < 0) { + printk(KERN_ERR "kobject_init_and_add failed: %d\n", err); return err; - + } err = edac_create_mci_instance_attributes(mci, grp_kobj->grp->mcidev_attr, &grp_kobj->kobj); - if (err) + if (err < 0) return err; } else if (sysfs_attrib->attr.name) { debugf0("%s() file %s\n", __func__, sysfs_attrib->attr.name); err = sysfs_create_file(kobj, &sysfs_attrib->attr); + if (err < 0) { + printk(KERN_ERR "sysfs_create_file failed: %d\n", err); + return err; + } } else break; - if (err) { - return err; - } sysfs_attrib++; } @@ -854,13 +856,24 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, * Remove first all the atributes */ while (sysfs_attrib) { + debugf1("%s() sysfs_attrib = %p\n",__func__, sysfs_attrib); if (sysfs_attrib->grp) { - list_for_each_entry(grp_kobj, &mci->grp_kobj_list, - list) - if (grp_kobj->grp == sysfs_attrib->grp) + debugf1("%s() seeking for group %s\n", + __func__, sysfs_attrib->grp->name); + list_for_each_entry(grp_kobj, + &mci->grp_kobj_list, list) { + debugf1("%s() grp_kobj->grp = %p\n",__func__, grp_kobj->grp); + if (grp_kobj->grp == sysfs_attrib->grp) { edac_remove_mci_instance_attributes(mci, grp_kobj->grp->mcidev_attr, &grp_kobj->kobj, count + 1); + debugf0("%s() group %s\n", __func__, + sysfs_attrib->grp->name); + kobject_put(&grp_kobj->kobj); + } + } + debugf1("%s() end of seeking for group %s\n", + __func__, sysfs_attrib->grp->name); } else if (sysfs_attrib->attr.name) { debugf0("%s() file %s\n", __func__, sysfs_attrib->attr.name); @@ -870,15 +883,14 @@ static void edac_remove_mci_instance_attributes(struct mem_ctl_info *mci, sysfs_attrib++; } - /* - * Now that all attributes got removed, it is save to remove all groups - */ - if (!count) - list_for_each_entry_safe(grp_kobj, tmp, &mci->grp_kobj_list, - list) { - debugf0("%s() grp %s\n", __func__, grp_kobj->grp->name); - kobject_put(&grp_kobj->kobj); - } + /* Remove the group objects */ + if (count) + return; + list_for_each_entry_safe(grp_kobj, tmp, + &mci->grp_kobj_list, list) { + list_del(&grp_kobj->list); + kfree(grp_kobj); + } } @@ -970,6 +982,7 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) debugf0("%s()\n", __func__); /* remove all csrow kobjects */ + debugf0("%s() unregister this mci kobj\n", __func__); for (i = 0; i < mci->nr_csrows; i++) { if (mci->csrows[i].nr_pages > 0) { debugf0("%s() unreg csrow-%d\n", __func__, i); @@ -977,20 +990,20 @@ void edac_remove_sysfs_mci_device(struct mem_ctl_info *mci) } } - debugf0("%s() remove_link\n", __func__); + /* remove this mci instance's attribtes */ + if (mci->mc_driver_sysfs_attributes) { + debugf0("%s() unregister mci private attributes\n", __func__); + edac_remove_mci_instance_attributes(mci, + mci->mc_driver_sysfs_attributes, + &mci->edac_mci_kobj, 0); + } /* remove the symlink */ + debugf0("%s() remove_link\n", __func__); sysfs_remove_link(&mci->edac_mci_kobj, EDAC_DEVICE_SYMLINK); - debugf0("%s() remove_mci_instance\n", __func__); - - /* remove this mci instance's attribtes */ - edac_remove_mci_instance_attributes(mci, - mci->mc_driver_sysfs_attributes, - &mci->edac_mci_kobj, 0); - debugf0("%s() unregister this mci kobj\n", __func__); - /* unregister this instance's kobject */ + debugf0("%s() remove_mci_instance\n", __func__); kobject_put(&mci->edac_mci_kobj); } From ac99768c534ebde637b506ce9a6f5638d2049a5d Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 12 Aug 2010 13:09:21 -0300 Subject: [PATCH 10/34] edac_core: Don't let free(mci) happen while using it A very nasty bug were happening on edac core, due to the way mci objects are freed. mci memory is freed when kobject count reaches zero, by edac_mci_control_release(). However, from the logs, this is clearly happening before the final usage of mci struct: [15799.607454] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 640: edac_mci_control_release() mci instance idx=0 releasing [15799.618773] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 769: edac_inst_grp_release() [15799.627326] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 894: edac_remove_mci_instance_attributes() end of seeking for group all_channel_counts [15799.640887] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 877: edac_remove_mci_instance_attributes() sysfs_attrib = ffffffffa01d7240 [15799.653412] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 1020: edac_remove_sysfs_mci_device() remove_link [15799.663753] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 1024: edac_remove_sysfs_mci_device() remove_mci_instance Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_mc_sysfs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 5a5734c1f6a5..7024b873a3b9 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -759,8 +759,6 @@ static void edac_inst_grp_release(struct kobject *kobj) grp = container_of(kobj, struct mcidev_sysfs_group_kobj, kobj); mci = grp->mci; - - kobject_put(&mci->edac_mci_kobj); } /* Intermediate show/store table */ From bbc560ae677c0f4d7ff8404a21409c99f35b297b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 16 Aug 2010 18:22:43 -0300 Subject: [PATCH 11/34] edac_core: Print debug messages at release calls This is important to track a nasty bug at the free logic. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_mc.c | 2 ++ drivers/edac/edac_mc_sysfs.c | 2 ++ drivers/edac/i7core_edac.c | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index b10b45cc7870..889ce7566b56 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -235,6 +235,8 @@ EXPORT_SYMBOL_GPL(edac_mc_alloc); */ void edac_mc_free(struct mem_ctl_info *mci) { + debugf1("%s()\n", __func__); + edac_mc_unregister_sysfs_main_kobj(mci); } EXPORT_SYMBOL_GPL(edac_mc_free); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index 7024b873a3b9..ddd765253630 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -712,6 +712,8 @@ int edac_mc_register_sysfs_main_kobj(struct mem_ctl_info *mci) */ void edac_mc_unregister_sysfs_main_kobj(struct mem_ctl_info *mci) { + debugf1("%s()\n", __func__); + /* delete the kobj from the mc_kset */ kobject_put(&mci->edac_mci_kobj); } diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 11c61b4d8149..b0559973c66f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2086,6 +2086,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) edac_mc_del_mc(&i7core_dev->pdev[0]->dev); /* Free data */ + debugf1("%s: free structs\n"); kfree(mci->ctl_name); edac_mc_free(mci); From accf74fff36315a31dc7319dae2927af06e9296f Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 16 Aug 2010 18:34:37 -0300 Subject: [PATCH 12/34] i7core_edac: don't use a freed mci struct This is a nasty bug. Since kobject count will be reduced by zero by edac_mc_del_mc(), and this triggers the kobj release method, the mci memory will be freed automatically. So, all we have left is ctl_name, as shown by enabling debug: [ 80.822186] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 1020: edac_remove_sysfs_mci_device() remove_link [ 80.832590] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 1024: edac_remove_sysfs_mci_device() remove_mci_instance [ 80.843776] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 640: edac_mci_control_release() mci instance idx=0 releasing [ 80.855163] EDAC MC: Removed device 0 for i7core_edac.c i7 core #0: DEV 0000:3f:03.0 [ 80.862936] EDAC DEBUG: in drivers/edac/i7core_edac.c, line at 2089: (null): free structs [ 80.871134] EDAC DEBUG: in drivers/edac/edac_mc.c, line at 238: edac_mc_free() [ 80.878379] EDAC DEBUG: in drivers/edac/edac_mc_sysfs.c, line at 726: edac_mc_unregister_sysfs_main_kobj() [ 80.888043] EDAC DEBUG: in drivers/edac/i7core_edac.c, line at 1232: drivers/edac/i7core_edac.c: i7core_put_devices() Also, kfree(mci) shouldn't happen at the kobj.release, as it happens when edac_remove_sysfs_mci_device() is called, but the logic is: edac_remove_sysfs_mci_device(mci); edac_printk(KERN_INFO, EDAC_MC, "Removed device %d for %s %s: DEV %s\n", mci->mc_idx, mci->mod_name, mci->ctl_name, edac_dev_name(mci)); So, as the edac_printk() needs the mci struct, this generates an OOPS. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/edac_mc.c | 3 +++ drivers/edac/edac_mc_sysfs.c | 3 --- drivers/edac/i7core_edac.c | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c index 889ce7566b56..ba6586a69ccc 100644 --- a/drivers/edac/edac_mc.c +++ b/drivers/edac/edac_mc.c @@ -238,6 +238,9 @@ void edac_mc_free(struct mem_ctl_info *mci) debugf1("%s()\n", __func__); edac_mc_unregister_sysfs_main_kobj(mci); + + /* free the mci instance memory here */ + kfree(mci); } EXPORT_SYMBOL_GPL(edac_mc_free); diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c index ddd765253630..2905dc103393 100644 --- a/drivers/edac/edac_mc_sysfs.c +++ b/drivers/edac/edac_mc_sysfs.c @@ -630,9 +630,6 @@ static void edac_mci_control_release(struct kobject *kobj) /* decrement the module ref count */ module_put(mci->owner); - - /* free the mci instance memory here */ - kfree(mci); } static struct kobj_type ktype_mci = { diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b0559973c66f..8e789a2e35d6 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2085,8 +2085,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* Remove MC sysfs nodes */ edac_mc_del_mc(&i7core_dev->pdev[0]->dev); - /* Free data */ - debugf1("%s: free structs\n"); + debugf1("%s: free mci struct\n", mci->ctl_name); kfree(mci->ctl_name); edac_mc_free(mci); From 54a08ab153cf38a08ccce7544d58c819ad02dd18 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Thu, 19 Aug 2010 15:51:00 -0300 Subject: [PATCH 13/34] i7core_edac: Don't do the legacy PCI probe by default The legacy PCI probe sometimes cause hangs. Better to have it disabled by default, and have a parameter to enable it. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 8e789a2e35d6..a76a4c067858 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -44,6 +44,9 @@ static LIST_HEAD(i7core_edac_list); static DEFINE_MUTEX(i7core_edac_lock); static int probed; +static int use_pci_fixup; +module_param(use_pci_fixup, int, 0444); +MODULE_PARM_DESC(use_pci_fixup, "Enable PCI fixup to seek for hidden devices"); /* * This is used for Nehalem-EP and Nehalem-EX devices, where the non-core * registers start at bus 255, and are not reported by BIOS. @@ -1257,6 +1260,7 @@ static void __init i7core_xeon_pci_fixup(const struct pci_id_table *table) { struct pci_dev *pdev = NULL; int i; + /* * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core pci buses * aren't announced by acpi. So, we need to use a legacy scan probing @@ -2126,7 +2130,8 @@ static int __init i7core_init(void) /* Ensure that the OPSTATE is set correctly for POLL or NMI */ opstate_init(); - i7core_xeon_pci_fixup(pci_dev_table); + if (use_pci_fixup) + i7core_xeon_pci_fixup(pci_dev_table); pci_rc = pci_register_driver(&i7core_driver); From 45b7c981aeeb456d4b0c04f15d551f3e515bf20e Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:24:18 -0300 Subject: [PATCH 14/34] i7core_edac: Fix the logic in i7core_remove() commit 47251b4d960bdfa648b0d06dbc6d445f41cb3906 have changed the logic for unexplained reasons. It looks strange that it can release i7core_dev without calling i7core_put_devices() that releases i7core_dev->pdev. Fix the part. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index a76a4c067858..d64ac2ccc0bc 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2095,9 +2095,9 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* Release PCI resources */ i7core_put_devices(i7core_dev); + list_del(&i7core_dev->list); + kfree(i7core_dev); } - list_del(&i7core_dev->list); - kfree(i7core_dev); } probed--; From b197cba071ec8a171fbaaaf82d119315a6f6cb0b Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:24:31 -0300 Subject: [PATCH 15/34] i7core_edac: Reduce args of i7core_get_onedevice Since we need to pass the index of the entry, pass the table itself instead of passing individual members of the table. While here make it static. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index d64ac2ccc0bc..567ee18d9d3f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1300,12 +1300,13 @@ static unsigned i7core_pci_lastbus(void) * * Need to 'get' device 16 func 1 and func 2 */ -int i7core_get_onedevice(struct pci_dev **prev, const int devno, - const struct pci_id_descr *dev_descr, - const unsigned n_devs, - const unsigned last_bus) +static int i7core_get_onedevice(struct pci_dev **prev, + const struct pci_id_table *table, + const unsigned devno, + const unsigned last_bus) { struct i7core_dev *i7core_dev; + const struct pci_id_descr *dev_descr = &table->descr[devno]; struct pci_dev *pdev = NULL; u8 bus = 0; @@ -1357,14 +1358,14 @@ int i7core_get_onedevice(struct pci_dev **prev, const int devno, i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); if (!i7core_dev) return -ENOMEM; - i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * n_devs, - GFP_KERNEL); + i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) + * table->n_devs, GFP_KERNEL); if (!i7core_dev->pdev) { kfree(i7core_dev); return -ENOMEM; } i7core_dev->socket = socket; - i7core_dev->n_devs = n_devs; + i7core_dev->n_devs = table->n_devs; list_add_tail(&i7core_dev->list, &i7core_edac_list); } @@ -1416,18 +1417,14 @@ static int i7core_get_devices(const struct pci_id_table *table) { int i, rc, last_bus; struct pci_dev *pdev = NULL; - const struct pci_id_descr *dev_descr; last_bus = i7core_pci_lastbus(); while (table && table->descr) { - dev_descr = table->descr; for (i = 0; i < table->n_devs; i++) { pdev = NULL; do { - rc = i7core_get_onedevice(&pdev, i, - &dev_descr[i], - table->n_devs, + rc = i7core_get_onedevice(&pdev, table, i, last_bus); if (rc < 0) { if (i == 0) { From 848b2f7ed6db4d3a83201187159665cc57725d9f Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:24:44 -0300 Subject: [PATCH 16/34] i7core_edac: Introduce alloc_i7core_dev It's nice to have a method for a single purpose. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 567ee18d9d3f..c4fa112271e5 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -447,6 +447,29 @@ static struct i7core_dev *get_i7core_dev(u8 socket) return NULL; } +static struct i7core_dev *alloc_i7core_dev(u8 socket, + const struct pci_id_table *table) +{ + struct i7core_dev *i7core_dev; + + i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); + if (!i7core_dev) + return NULL; + + i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) * table->n_devs, + GFP_KERNEL); + if (!i7core_dev->pdev) { + kfree(i7core_dev); + return NULL; + } + + i7core_dev->socket = socket; + i7core_dev->n_devs = table->n_devs; + list_add_tail(&i7core_dev->list, &i7core_edac_list); + + return i7core_dev; +} + /**************************************************************************** Memory check routines ****************************************************************************/ @@ -1355,18 +1378,9 @@ static int i7core_get_onedevice(struct pci_dev **prev, i7core_dev = get_i7core_dev(socket); if (!i7core_dev) { - i7core_dev = kzalloc(sizeof(*i7core_dev), GFP_KERNEL); + i7core_dev = alloc_i7core_dev(socket, table); if (!i7core_dev) return -ENOMEM; - i7core_dev->pdev = kzalloc(sizeof(*i7core_dev->pdev) - * table->n_devs, GFP_KERNEL); - if (!i7core_dev->pdev) { - kfree(i7core_dev); - return -ENOMEM; - } - i7core_dev->socket = socket; - i7core_dev->n_devs = table->n_devs; - list_add_tail(&i7core_dev->list, &i7core_edac_list); } if (i7core_dev->pdev[devno]) { From 2aa9be448dab7433c685b634a4049289cb1913d3 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:25:00 -0300 Subject: [PATCH 17/34] i7core_edac: Introduce free_i7core_dev Have a method to make a couple with alloc_i7core_dev() previously introduced. Using in pair will help proper resource handling. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index c4fa112271e5..e1cbbbad466e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -470,6 +470,13 @@ static struct i7core_dev *alloc_i7core_dev(u8 socket, return i7core_dev; } +static void free_i7core_dev(struct i7core_dev *i7core_dev) +{ + list_del(&i7core_dev->list); + kfree(i7core_dev->pdev); + kfree(i7core_dev); +} + /**************************************************************************** Memory check routines ****************************************************************************/ @@ -1265,7 +1272,6 @@ static void i7core_put_devices(struct i7core_dev *i7core_dev) PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn)); pci_dev_put(pdev); } - kfree(i7core_dev->pdev); } static void i7core_put_all_devices(void) @@ -1274,8 +1280,7 @@ static void i7core_put_all_devices(void) list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { i7core_put_devices(i7core_dev); - list_del(&i7core_dev->list); - kfree(i7core_dev); + free_i7core_dev(i7core_dev); } } @@ -2106,8 +2111,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) /* Release PCI resources */ i7core_put_devices(i7core_dev); - list_del(&i7core_dev->list); - kfree(i7core_dev); + free_i7core_dev(i7core_dev); } } probed--; From a3aa0a4ab56e825e2ec236974d478d1dcebf41a9 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:25:18 -0300 Subject: [PATCH 18/34] i7core_edac: Introduce i7core_pci_ctl_create/release Have a couple of method. while here sort out lines in the i7core_register_mci() a bit. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 44 +++++++++++++++++++++----------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e1cbbbad466e..a5cbea5abd62 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1895,6 +1895,26 @@ static int i7core_mce_check_error(void *priv, struct mce *mce) return 1; } +static void i7core_pci_ctl_create(struct i7core_pvt *pvt) +{ + pvt->i7core_pci = edac_pci_create_generic_ctl( + &pvt->i7core_dev->pdev[0]->dev, + EDAC_MOD_STR); + if (unlikely(!pvt->i7core_pci)) + pr_warn("Unable to setup PCI error report via EDAC\n"); +} + +static void i7core_pci_ctl_release(struct i7core_pvt *pvt) +{ + if (likely(pvt->i7core_pci)) + edac_pci_release_generic_ctl(pvt->i7core_pci); + else + i7core_printk(KERN_ERR, + "Couldn't find mem_ctl_info for socket %d\n", + pvt->i7core_dev->socket); + pvt->i7core_pci = NULL; +} + static int i7core_register_mci(struct i7core_dev *i7core_dev, const int num_channels, const int num_csrows) { @@ -1969,22 +1989,12 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, pvt->inject.page = -1; pvt->inject.col = -1; + /* allocating generic PCI control info */ + i7core_pci_ctl_create(pvt); + /* Registers on edac_mce in order to receive memory errors */ pvt->edac_mce.priv = mci; pvt->edac_mce.check_error = i7core_mce_check_error; - - /* allocating generic PCI control info */ - pvt->i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, - EDAC_MOD_STR); - if (unlikely(!pvt->i7core_pci)) { - printk(KERN_WARNING - "%s(): Unable to create PCI control\n", - __func__); - printk(KERN_WARNING - "%s(): PCI error report via EDAC not setup\n", - __func__); - } - rc = edac_mce_register(&pvt->edac_mce); if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ @@ -2094,13 +2104,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) edac_mce_unregister(&pvt->edac_mce); /* Disable EDAC polling */ - if (likely(pvt->i7core_pci)) - edac_pci_release_generic_ctl(pvt->i7core_pci); - else - i7core_printk(KERN_ERR, - "Couldn't find mem_ctl_info for socket %d\n", - i7core_dev->socket); - pvt->i7core_pci = NULL; + i7core_pci_ctl_release(pvt); /* Remove MC sysfs nodes */ edac_mc_del_mc(&i7core_dev->pdev[0]->dev); From 64c10f6e0e6b4473b97c29c574e9517f93bedaec Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:28:14 -0300 Subject: [PATCH 19/34] i7core_edac: Always do get/put for all devices We already do 'get' for all sockets at once. So do 'put' in the same way. And let args of the 'get' function to void since it handles only the single, static and known size table pci_dev_table[]. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index a5cbea5abd62..19faeffac9dc 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1255,7 +1255,7 @@ static const struct mcidev_sysfs_attribute i7core_sysfs_udimm_attrs[] = { ****************************************************************************/ /* - * i7core_put_devices 'put' all the devices that we have + * i7core_put_all_devices 'put' all the devices that we have * reserved via 'get' */ static void i7core_put_devices(struct i7core_dev *i7core_dev) @@ -1323,7 +1323,7 @@ static unsigned i7core_pci_lastbus(void) } /* - * i7core_get_devices Find and perform 'get' operation on the MCH's + * i7core_get_all_devices Find and perform 'get' operation on the MCH's * device/functions we want to reference for this driver * * Need to 'get' device 16 func 1 and func 2 @@ -1432,14 +1432,16 @@ static int i7core_get_onedevice(struct pci_dev **prev, return 0; } -static int i7core_get_devices(const struct pci_id_table *table) +static int i7core_get_all_devices(void) { - int i, rc, last_bus; + int i, j, rc, last_bus; struct pci_dev *pdev = NULL; + const struct pci_id_table *table; last_bus = i7core_pci_lastbus(); - while (table && table->descr) { + for (j = 0; j < ARRAY_SIZE(pci_dev_table); j++) { + table = &pci_dev_table[j]; for (i = 0; i < table->n_devs; i++) { pdev = NULL; do { @@ -1455,7 +1457,6 @@ static int i7core_get_devices(const struct pci_id_table *table) } } while (pdev); } - table++; } return 0; @@ -2033,7 +2034,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, } probed++; - rc = i7core_get_devices(pci_dev_table); + rc = i7core_get_all_devices(); if (unlikely(rc < 0)) goto fail0; @@ -2071,7 +2072,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, static void __devexit i7core_remove(struct pci_dev *pdev) { struct mem_ctl_info *mci; - struct i7core_dev *i7core_dev, *tmp; + struct i7core_dev *i7core_dev; struct i7core_pvt *pvt; debugf0(__FILE__ ": %s()\n", __func__); @@ -2085,7 +2086,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) */ mutex_lock(&i7core_edac_lock); - list_for_each_entry_safe(i7core_dev, tmp, &i7core_edac_list, list) { + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { mci = find_mci_by_dev(&i7core_dev->pdev[0]->dev); if (unlikely(!mci || !mci->pvt_info)) { debugf0("MC: " __FILE__ ": %s(): dev = %p\n", @@ -2112,12 +2113,12 @@ static void __devexit i7core_remove(struct pci_dev *pdev) debugf1("%s: free mci struct\n", mci->ctl_name); kfree(mci->ctl_name); edac_mc_free(mci); - - /* Release PCI resources */ - i7core_put_devices(i7core_dev); - free_i7core_dev(i7core_dev); } } + + /* Release PCI resources */ + i7core_put_all_devices(); + probed--; mutex_unlock(&i7core_edac_lock); From 5939813b9c4270d0f46375c3cad64226bb1fcd62 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:28:25 -0300 Subject: [PATCH 20/34] i7core_edac: Fix order of lines in i7core_register_mci The flag is_registered is not initialized until mci_bind_devs() is called. Refer it properly. The mci->dev and mci->edac_check is required in edac_mc_add_mc(), so prepare them just before the call. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 19faeffac9dc..6bebf4d73f48 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1933,9 +1933,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", __func__, mci, &i7core_dev->pdev[0]->dev); - /* record ptr to the generic device */ - mci->dev = &i7core_dev->pdev[0]->dev; - pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); @@ -1954,21 +1951,22 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, mci->dev_name = pci_name(i7core_dev->pdev[0]); mci->ctl_page_to_phys = NULL; - if (pvt->is_registered) - mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs; - else - mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs; - - /* Set the function pointer to an actual operation function */ - mci->edac_check = i7core_check_error; - /* Store pci devices at mci for faster access */ rc = mci_bind_devs(mci, i7core_dev); if (unlikely(rc < 0)) goto fail; + if (pvt->is_registered) + mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs; + else + mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs; + /* Get dimm basic config */ get_dimm_config(mci, &csrow); + /* record ptr to the generic device */ + mci->dev = &i7core_dev->pdev[0]->dev; + /* Set the function pointer to an actual operation function */ + mci->edac_check = i7core_check_error; /* add this new MC control structure to EDAC's list of MCs */ if (unlikely(edac_mc_add_mc(mci))) { From 628c5ddfb08094a5ef9186dc866d09bfcac105c9 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:28:40 -0300 Subject: [PATCH 21/34] i7core_edac: Fix error path of i7core_register_mci Release resources properly. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 6bebf4d73f48..3542e8c0a63f 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1954,7 +1954,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, /* Store pci devices at mci for faster access */ rc = mci_bind_devs(mci, i7core_dev); if (unlikely(rc < 0)) - goto fail; + goto fail0; if (pvt->is_registered) mci->mc_driver_sysfs_attributes = i7core_sysfs_rdimm_attrs; @@ -1977,7 +1977,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, */ rc = -EINVAL; - goto fail; + goto fail0; } /* Default error mask is any memory */ @@ -1998,11 +1998,17 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, if (unlikely(rc < 0)) { debugf0("MC: " __FILE__ ": %s(): failed edac_mce_register()\n", __func__); + goto fail1; } -fail: - if (rc < 0) - edac_mc_free(mci); + return 0; + +fail1: + i7core_pci_ctl_release(pvt); + edac_mc_del_mc(mci->dev); +fail0: + kfree(mci->ctl_name); + edac_mc_free(mci); return rc; } From 2896637b86243c39a4f08d15388dcc06130fff29 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:28:51 -0300 Subject: [PATCH 22/34] i7core_edac: Call pci_dev_put() when alloc_i7core_dev() failed Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 3542e8c0a63f..2e2db3c083ed 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1384,8 +1384,10 @@ static int i7core_get_onedevice(struct pci_dev **prev, i7core_dev = get_i7core_dev(socket); if (!i7core_dev) { i7core_dev = alloc_i7core_dev(socket, table); - if (!i7core_dev) + if (!i7core_dev) { + pci_dev_put(pdev); return -ENOMEM; + } } if (i7core_dev->pdev[devno]) { From 71fe01706d631513bdbd73381f4b76dacea5cf77 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:29:47 -0300 Subject: [PATCH 23/34] i7core_edac: Check probe counter in i7core_remove Prevent i7core_remove from running multiple times. Otherwise value proved will be negative and something will be wrong. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 2e2db3c083ed..472fa375f1eb 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2092,6 +2092,12 @@ static void __devexit i7core_remove(struct pci_dev *pdev) */ mutex_lock(&i7core_edac_lock); + + if (unlikely(!probed)) { + mutex_unlock(&i7core_edac_lock); + return; + } + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { mci = find_mci_by_dev(&i7core_dev->pdev[0]->dev); if (unlikely(!mci || !mci->pvt_info)) { From 73589c80cd0dab94db50800c4834a8d8522cd54f Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:32:05 -0300 Subject: [PATCH 24/34] i7core_edac: Use saved pointers We already have saved pointers. Use shorter ones. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 472fa375f1eb..7ee5034100b9 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2099,7 +2099,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) } list_for_each_entry(i7core_dev, &i7core_edac_list, list) { - mci = find_mci_by_dev(&i7core_dev->pdev[0]->dev); + mci = i7core_dev->mci; if (unlikely(!mci || !mci->pvt_info)) { debugf0("MC: " __FILE__ ": %s(): dev = %p\n", __func__, &i7core_dev->pdev[0]->dev); @@ -2108,7 +2108,6 @@ static void __devexit i7core_remove(struct pci_dev *pdev) "Couldn't find mci hanler\n"); } else { pvt = mci->pvt_info; - i7core_dev = pvt->i7core_dev; debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", __func__, mci, &i7core_dev->pdev[0]->dev); @@ -2120,7 +2119,7 @@ static void __devexit i7core_remove(struct pci_dev *pdev) i7core_pci_ctl_release(pvt); /* Remove MC sysfs nodes */ - edac_mc_del_mc(&i7core_dev->pdev[0]->dev); + edac_mc_del_mc(mci->dev); debugf1("%s: free mci struct\n", mci->ctl_name); kfree(mci->ctl_name); From 1c6edbbe2529684859ff8e34a19e34fe9894a3b7 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:32:33 -0300 Subject: [PATCH 25/34] i7core_edac: Introduce i7core_unregister_mci In i7core_probe, when setup of mci for 2nd or later socket failed, we should cleanup prepared mci for 1st socket or so before "put" of all devices. So let have i7core_unregister_mci that can be shared between here and i7core_remove. While here fix a typo "hanler". Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 76 ++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 32 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 7ee5034100b9..7164707ed99e 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1471,10 +1471,6 @@ static int mci_bind_devs(struct mem_ctl_info *mci, struct pci_dev *pdev; int i, func, slot; - /* Associates i7core_dev and mci for future usage */ - pvt->i7core_dev = i7core_dev; - i7core_dev->mci = mci; - pvt->is_registered = 0; for (i = 0; i < i7core_dev->n_devs; i++) { pdev = i7core_dev->pdev[i]; @@ -1918,6 +1914,39 @@ static void i7core_pci_ctl_release(struct i7core_pvt *pvt) pvt->i7core_pci = NULL; } +static void i7core_unregister_mci(struct i7core_dev *i7core_dev) +{ + struct mem_ctl_info *mci = i7core_dev->mci; + struct i7core_pvt *pvt; + + if (unlikely(!mci || !mci->pvt_info)) { + debugf0("MC: " __FILE__ ": %s(): dev = %p\n", + __func__, &i7core_dev->pdev[0]->dev); + + i7core_printk(KERN_ERR, "Couldn't find mci handler\n"); + return; + } + + pvt = mci->pvt_info; + + debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", + __func__, mci, &i7core_dev->pdev[0]->dev); + + /* Disable MCE NMI handler */ + edac_mce_unregister(&pvt->edac_mce); + + /* Disable EDAC polling */ + i7core_pci_ctl_release(pvt); + + /* Remove MC sysfs nodes */ + edac_mc_del_mc(mci->dev); + + debugf1("%s: free mci struct\n", mci->ctl_name); + kfree(mci->ctl_name); + edac_mc_free(mci); + i7core_dev->mci = NULL; +} + static int i7core_register_mci(struct i7core_dev *i7core_dev, const int num_channels, const int num_csrows) { @@ -2003,6 +2032,10 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, goto fail1; } + /* Associates i7core_dev and mci for future usage */ + pvt->i7core_dev = i7core_dev; + i7core_dev->mci = mci; + return 0; fail1: @@ -2011,6 +2044,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, fail0: kfree(mci->ctl_name); edac_mc_free(mci); + i7core_dev->mci = NULL; return rc; } @@ -2065,6 +2099,10 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return 0; fail1: + list_for_each_entry(i7core_dev, &i7core_edac_list, list) { + if (i7core_dev->mci) + i7core_unregister_mci(i7core_dev); + } i7core_put_all_devices(); fail0: mutex_unlock(&i7core_edac_lock); @@ -2077,9 +2115,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, */ static void __devexit i7core_remove(struct pci_dev *pdev) { - struct mem_ctl_info *mci; struct i7core_dev *i7core_dev; - struct i7core_pvt *pvt; debugf0(__FILE__ ": %s()\n", __func__); @@ -2099,32 +2135,8 @@ static void __devexit i7core_remove(struct pci_dev *pdev) } list_for_each_entry(i7core_dev, &i7core_edac_list, list) { - mci = i7core_dev->mci; - if (unlikely(!mci || !mci->pvt_info)) { - debugf0("MC: " __FILE__ ": %s(): dev = %p\n", - __func__, &i7core_dev->pdev[0]->dev); - - i7core_printk(KERN_ERR, - "Couldn't find mci hanler\n"); - } else { - pvt = mci->pvt_info; - - debugf0("MC: " __FILE__ ": %s(): mci = %p, dev = %p\n", - __func__, mci, &i7core_dev->pdev[0]->dev); - - /* Disable MCE NMI handler */ - edac_mce_unregister(&pvt->edac_mce); - - /* Disable EDAC polling */ - i7core_pci_ctl_release(pvt); - - /* Remove MC sysfs nodes */ - edac_mc_del_mc(mci->dev); - - debugf1("%s: free mci struct\n", mci->ctl_name); - kfree(mci->ctl_name); - edac_mc_free(mci); - } + if (i7core_dev->mci) + i7core_unregister_mci(i7core_dev); } /* Release PCI resources */ From aace42831aa46f210bf3b0d8f1527092cc37eaad Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:32:45 -0300 Subject: [PATCH 26/34] i7core_edac: Reduce args of i7core_register_mci We can check the number of channels in i7core_register_mci. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 7164707ed99e..795df30000a1 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1947,17 +1947,20 @@ static void i7core_unregister_mci(struct i7core_dev *i7core_dev) i7core_dev->mci = NULL; } -static int i7core_register_mci(struct i7core_dev *i7core_dev, - const int num_channels, const int num_csrows) +static int i7core_register_mci(struct i7core_dev *i7core_dev) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; int csrow = 0; - int rc; + int rc, channels, csrows; + + /* Check the number of active and not disabled channels */ + rc = i7core_get_active_channels(i7core_dev->socket, &channels, &csrows); + if (unlikely(rc < 0)) + return rc; /* allocate a new MC control structure */ - mci = edac_mc_alloc(sizeof(*pvt), num_csrows, num_channels, - i7core_dev->socket); + mci = edac_mc_alloc(sizeof(*pvt), csrows, channels, i7core_dev->socket); if (unlikely(!mci)) return -ENOMEM; @@ -2079,16 +2082,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, goto fail0; list_for_each_entry(i7core_dev, &i7core_edac_list, list) { - int channels; - int csrows; - - /* Check the number of active and not disabled channels */ - rc = i7core_get_active_channels(i7core_dev->socket, - &channels, &csrows); - if (unlikely(rc < 0)) - goto fail1; - - rc = i7core_register_mci(i7core_dev, channels, csrows); + rc = i7core_register_mci(i7core_dev); if (unlikely(rc < 0)) goto fail1; } From 2e5185f7ff2b26206889d7ebb09ddc4c59b656a4 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:32:56 -0300 Subject: [PATCH 27/34] i7core_edac: Remove unused arg csrow from get_dimm_config A local is enough. Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 795df30000a1..b466f803db12 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -580,12 +580,13 @@ static int i7core_get_active_channels(const u8 socket, unsigned *channels, return 0; } -static int get_dimm_config(const struct mem_ctl_info *mci, int *csrow) +static int get_dimm_config(const struct mem_ctl_info *mci) { struct i7core_pvt *pvt = mci->pvt_info; struct csrow_info *csr; struct pci_dev *pdev; int i, j; + int csrow = 0; unsigned long last_page = 0; enum edac_type mode; enum mem_type mtype; @@ -701,7 +702,7 @@ static int get_dimm_config(const struct mem_ctl_info *mci, int *csrow) npages = MiB_TO_PAGES(size); - csr = &mci->csrows[*csrow]; + csr = &mci->csrows[csrow]; csr->first_page = last_page + 1; last_page += npages; csr->last_page = last_page; @@ -709,13 +710,13 @@ static int get_dimm_config(const struct mem_ctl_info *mci, int *csrow) csr->page_mask = 0; csr->grain = 8; - csr->csrow_idx = *csrow; + csr->csrow_idx = csrow; csr->nr_channels = 1; csr->channels[0].chan_idx = i; csr->channels[0].ce_count = 0; - pvt->csrow_map[i][j] = *csrow; + pvt->csrow_map[i][j] = csrow; switch (banks) { case 4: @@ -734,7 +735,7 @@ static int get_dimm_config(const struct mem_ctl_info *mci, int *csrow) csr->edac_mode = mode; csr->mtype = mtype; - (*csrow)++; + csrow++; } pci_read_config_dword(pdev, MC_SAG_CH_0, &value[0]); @@ -1951,7 +1952,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) { struct mem_ctl_info *mci; struct i7core_pvt *pvt; - int csrow = 0; int rc, channels, csrows; /* Check the number of active and not disabled channels */ @@ -1996,7 +1996,7 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) mci->mc_driver_sysfs_attributes = i7core_sysfs_udimm_attrs; /* Get dimm basic config */ - get_dimm_config(mci, &csrow); + get_dimm_config(mci); /* record ptr to the generic device */ mci->dev = &i7core_dev->pdev[0]->dev; /* Set the function pointer to an actual operation function */ From 21b6806a8cbda694eb1bed8d5b60bd7c322ad343 Mon Sep 17 00:00:00 2001 From: Hidetoshi Seto Date: Fri, 20 Aug 2010 04:33:10 -0300 Subject: [PATCH 28/34] i7core_edac: Remove unused member channels in i7core_pvt Signed-off-by: Hidetoshi Seto Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index b466f803db12..4a12961c5ef6 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -243,8 +243,6 @@ struct i7core_pvt { struct i7core_inject inject; struct i7core_channel channel[NUM_CHANS]; - int channels; /* Number of active channels */ - int ce_count_available; int csrow_map[NUM_CHANS][MAX_DIMMS]; From 6d37d240f2ff411c4d58bbbddefbda73a227d40c Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 20 Aug 2010 12:48:26 -0300 Subject: [PATCH 29/34] i7core_edac: Fix an oops at i7core probe changeset c91d57ba9ce5b5c93a7077e2f72510eb1f9131c4 moved the init of the priv pointer to the end of the probe routine. However, we need them before that, otherwise, we hit an OOPS: [ 67.743453] EDAC DEBUG: mci_bind_devs: Associated fn 0.0, dev = ffff88011b46e000, socket 0 [ 67.751861] BUG: unable to handle kernel NULL pointer dereference at 0000000000000010 [ 67.759685] IP: [] i7core_probe+0x979/0x130c [i7core_edac] [ 67.766721] PGD 10bd38067 PUD 10bd37067 PMD 0 [ 67.771178] Oops: 0000 [#1] SMP [ 67.774414] last sysfs file: /sys/devices/system/cpu/cpu1/cache/index2/shared_cpu_map [ 67.782213] CPU 1 [ 67.784042] Modules linked in: i7core_edac(+) edac_core cpufreq_ondemand binfmt_misc dm_multipath video output pci_slot snd_hda_codd Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 4a12961c5ef6..915835339d7c 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1968,6 +1968,10 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) pvt = mci->pvt_info; memset(pvt, 0, sizeof(*pvt)); + /* Associates i7core_dev and mci for future usage */ + pvt->i7core_dev = i7core_dev; + i7core_dev->mci = mci; + /* * FIXME: how to handle RDDR3 at MCI level? It is possible to have * Mixed RDDR3/UDDR3 with Nehalem, provided that they are on different @@ -2033,10 +2037,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev) goto fail1; } - /* Associates i7core_dev and mci for future usage */ - pvt->i7core_dev = i7core_dev; - i7core_dev->mci = mci; - return 0; fail1: From 88ef5ea9767b0c7bfb4b477e1857629fe8fa2983 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Fri, 20 Aug 2010 15:39:38 -0300 Subject: [PATCH 30/34] i7core_edac: it is safe to i7core_unregister_mci() when mci=NULL i7core_unregister_mci() checks internally when mci=NULL. There's no need to test it outside. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 915835339d7c..d55f74a6cd49 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2091,10 +2091,9 @@ static int __devinit i7core_probe(struct pci_dev *pdev, return 0; fail1: - list_for_each_entry(i7core_dev, &i7core_edac_list, list) { - if (i7core_dev->mci) - i7core_unregister_mci(i7core_dev); - } + list_for_each_entry(i7core_dev, &i7core_edac_list, list) + i7core_unregister_mci(i7core_dev); + i7core_put_all_devices(); fail0: mutex_unlock(&i7core_edac_lock); @@ -2126,10 +2125,8 @@ static void __devexit i7core_remove(struct pci_dev *pdev) return; } - list_for_each_entry(i7core_dev, &i7core_edac_list, list) { - if (i7core_dev->mci) - i7core_unregister_mci(i7core_dev); - } + list_for_each_entry(i7core_dev, &i7core_edac_list, list) + i7core_unregister_mci(i7core_dev); /* Release PCI resources */ i7core_put_all_devices(); From 79daef2099a02fed35747c23bad22f30441133ea Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 21 Aug 2010 01:03:52 -0300 Subject: [PATCH 31/34] i7core_edac: Fix refcount error at PCI devices Probably due to a bug or some testing logic at PCI level, device refcount for :00.0 device is decremented at the end of the pci_get_device, made by i7core_get_all_devices(). The fact is that the first versions of the driver relied on those devices to probe for Nehalem, but the current versions don't use it at all. So, let's just remove those devices from the driver, making it simpler and fixing the bug. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 37 ++----------------------------------- 1 file changed, 2 insertions(+), 35 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index d55f74a6cd49..9868796f4871 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -281,7 +281,8 @@ static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { /* Memory controller */ { PCI_DESCR(3, 0, PCI_DEVICE_ID_INTEL_I7_MCR) }, { PCI_DESCR(3, 1, PCI_DEVICE_ID_INTEL_I7_MC_TAD) }, - /* Exists only for RDIMM */ + + /* Exists only for RDIMM */ { PCI_DESCR(3, 2, PCI_DEVICE_ID_INTEL_I7_MC_RAS), .optional = 1 }, { PCI_DESCR(3, 4, PCI_DEVICE_ID_INTEL_I7_MC_TEST) }, @@ -302,16 +303,6 @@ static const struct pci_id_descr pci_dev_descr_i7core_nehalem[] = { { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_I7_MC_CH2_ADDR) }, { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_I7_MC_CH2_RANK) }, { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_I7_MC_CH2_TC) }, - - /* Generic Non-core registers */ - /* - * This is the PCI device on i7core and on Xeon 35xx (8086:2c41) - * On Xeon 55xx, however, it has a different id (8086:2c40). So, - * the probing code needs to test for the other address in case of - * failure of this one - */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_I7_NONCORE) }, - }; static const struct pci_id_descr pci_dev_descr_lynnfield[] = { @@ -328,12 +319,6 @@ static const struct pci_id_descr pci_dev_descr_lynnfield[] = { { PCI_DESCR( 5, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_ADDR) }, { PCI_DESCR( 5, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_RANK) }, { PCI_DESCR( 5, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH1_TC) }, - - /* - * This is the PCI device has an alternate address on some - * processors like Core i7 860 - */ - { PCI_DESCR( 0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE) }, }; static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = { @@ -361,10 +346,6 @@ static const struct pci_id_descr pci_dev_descr_i7core_westmere[] = { { PCI_DESCR(6, 1, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_ADDR_REV2) }, { PCI_DESCR(6, 2, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_RANK_REV2) }, { PCI_DESCR(6, 3, PCI_DEVICE_ID_INTEL_LYNNFIELD_MC_CH2_TC_REV2) }, - - /* Generic Non-core registers */ - { PCI_DESCR(0, 0, PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_REV2) }, - }; #define PCI_ID_TABLE_ENTRY(A) { .descr=A, .n_devs = ARRAY_SIZE(A) } @@ -1342,20 +1323,6 @@ static int i7core_get_onedevice(struct pci_dev **prev, pdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_descr->dev_id, *prev); - /* - * On Xeon 55xx, the Intel Quckpath Arch Generic Non-core regs - * is at addr 8086:2c40, instead of 8086:2c41. So, we need - * to probe for the alternate address in case of failure - */ - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_I7_NONCORE && !pdev) - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_I7_NONCORE_ALT, *prev); - - if (dev_descr->dev_id == PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE && !pdev) - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, - PCI_DEVICE_ID_INTEL_LYNNFIELD_NONCORE_ALT, - *prev); - if (!pdev) { if (*prev) { *prev = pdev; From a3e1541637f2096ab31af311c53eaeb0853650d3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sat, 21 Aug 2010 08:52:41 -0300 Subject: [PATCH 32/34] i7core_edac: Avoid PCI refcount to reach zero on successive load/reload That's a nasty bug that took me a lot of time to track, and whose solution took just one line to solve. The best fragrances and the worse poisons are shipped on the smalest bottles. The drivers/pci/quick.c implements the pci_get_device function. The normal behavior is that you call it, the function returns you a pdev pointer and increment pdev->kobj.kref.refcount of the pci device. However, if you want to keep searching an object, you need to pass the previous pdev function to the search. When you use a not null pointer to pdev "from" field, pci_get_device will decrement pdev->kobj.kref.refcount, assuming that the driver won't be using the previous pdev. The solution is simple: we just need to call pci_dev_get() manually, for the pdev's that the driver will actually use. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 9868796f4871..71f4dc699abe 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -1395,6 +1395,13 @@ static int i7core_get_onedevice(struct pci_dev **prev, dev_descr->func, PCI_VENDOR_ID_INTEL, dev_descr->dev_id); + /* + * As stated on drivers/pci/search.c, the reference count for + * @from is always decremented if it is not %NULL. So, as we need + * to get all devices up to null, we need to do a get for the device + */ + pci_dev_get(pdev); + *prev = pdev; return 0; From 3c52cc57ccd5c99441368d5e66be36681ce90e72 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 24 Oct 2010 11:12:28 -0200 Subject: [PATCH 33/34] i7core_edac: properly terminate pci_dev_table At pci_xeon_fixup(), it waits for a null-terminated table, while at i7core_get_all_devices, it just do a for 0..ARRAY_SIZE. As other tables are zero-terminated, change it to be terminate with 0 as well, and fixes a bug where it may be running out of the table elements. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 71f4dc699abe..e3404b2bbaa2 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -353,6 +353,7 @@ static const struct pci_id_table pci_dev_table[] = { PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_nehalem), PCI_ID_TABLE_ENTRY(pci_dev_descr_lynnfield), PCI_ID_TABLE_ENTRY(pci_dev_descr_i7core_westmere), + {0,} /* 0 terminated list. */ }; /* @@ -1409,14 +1410,13 @@ static int i7core_get_onedevice(struct pci_dev **prev, static int i7core_get_all_devices(void) { - int i, j, rc, last_bus; + int i, rc, last_bus; struct pci_dev *pdev = NULL; - const struct pci_id_table *table; + const struct pci_id_table *table = pci_dev_table; last_bus = i7core_pci_lastbus(); - for (j = 0; j < ARRAY_SIZE(pci_dev_table); j++) { - table = &pci_dev_table[j]; + while (table && table->descr) { for (i = 0; i < table->n_devs; i++) { pdev = NULL; do { @@ -1432,6 +1432,7 @@ static int i7core_get_all_devices(void) } } while (pdev); } + table++; } return 0; From 76a7bd81130646459dfded1845e0d511488a6afa Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Sun, 24 Oct 2010 11:36:19 -0200 Subject: [PATCH 34/34] i7core_edac: return -ENODEV when devices were already probed Due to the nature of i7core, we need to probe and attach all PCI devices used by this driver during the first time probe is called. However, PCI core will call the probe routine one time for each CPU socket. If we return -EINVAL to those calls, it would seem that the driver fails, when, in fact, there's no more devices left to initialize. Changing the return code to -ENODEV solves this issue. Signed-off-by: Mauro Carvalho Chehab --- drivers/edac/i7core_edac.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index e3404b2bbaa2..362861c15779 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -2046,7 +2046,7 @@ static int __devinit i7core_probe(struct pci_dev *pdev, */ if (unlikely(probed >= 1)) { mutex_unlock(&i7core_edac_lock); - return -EINVAL; + return -ENODEV; } probed++;