X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-kernel.git;a=blobdiff_plain;f=drivers%2Fedac%2Fi7core_edac.c;h=a76a4c06785899def496986e167fd70d09205d1c;hp=0fd5b85a0f756745bd1074ae673e89d6c81a237a;hb=54a08ab153cf38a08ccce7544d58c819ad02dd18;hpb=30c278192f9ab06125fb042f6e46763e0fd7140a diff --git a/drivers/edac/i7core_edac.c b/drivers/edac/i7core_edac.c index 0fd5b85a0f75..a76a4c067858 100644 --- a/drivers/edac/i7core_edac.c +++ b/drivers/edac/i7core_edac.c @@ -39,6 +39,14 @@ #include "edac_core.h" +/* Static vars */ +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. @@ -212,8 +220,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 { @@ -261,18 +269,17 @@ struct i7core_pvt { /* Count indicator to show errors not got */ unsigned mce_overrun; -}; -/* Static vars */ -static LIST_HEAD(i7core_edac_list); -static DEFINE_MUTEX(i7core_edac_lock); + /* Struct to control EDAC polling */ + struct edac_pci_ctl_info *i7core_pci; +}; #define PCI_DESCR(device, function, device_id) \ .dev = (device), \ .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) }, @@ -309,7 +316,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) }, @@ -331,7 +338,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) }, @@ -362,8 +369,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), @@ -378,8 +385,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 ****************************************************************************/ @@ -484,7 +489,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; @@ -545,7 +550,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; @@ -664,11 +669,7 @@ static int get_dimm_config(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; @@ -736,7 +737,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; @@ -921,7 +922,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; @@ -1120,35 +1121,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", @@ -1180,8 +1180,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 */ }; /**************************************************************************** @@ -1207,22 +1243,24 @@ 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(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; + /* * 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 @@ -1262,9 +1300,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; @@ -1373,11 +1412,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(); @@ -1404,7 +1443,6 @@ static int i7core_get_devices(struct pci_id_table *table) } return 0; - return 0; } static int mci_bind_devs(struct mem_ctl_info *mci, @@ -1448,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: @@ -1470,7 +1499,9 @@ error: 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; @@ -1487,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; @@ -1641,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; @@ -1846,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; @@ -1859,7 +1893,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; @@ -1881,7 +1916,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; @@ -1905,18 +1945,6 @@ static int i7core_register_mci(struct i7core_dev *i7core_dev, goto fail; } - /* allocating generic PCI control info */ - i7core_pci = edac_pci_create_generic_ctl(&i7core_dev->pdev[0]->dev, - EDAC_MOD_STR); - if (unlikely(!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; @@ -1929,6 +1957,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__ @@ -1949,8 +1989,6 @@ fail: * < 0 for error code */ -static int probed = 0; - static int __devinit i7core_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -2008,12 +2046,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,20 +2060,44 @@ 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)) { + 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); + + /* 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 + i7core_printk(KERN_ERR, + "Couldn't find mem_ctl_info for socket %d\n", + i7core_dev->socket); + pvt->i7core_pci = NULL; + + /* Remove MC sysfs nodes */ + edac_mc_del_mc(&i7core_dev->pdev[0]->dev); + + 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); - } else { - i7core_printk(KERN_ERR, - "Couldn't find mci for socket %d\n", - i7core_dev->socket); } + list_del(&i7core_dev->list); + kfree(i7core_dev); } probed--; @@ -2070,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);