i7core_edac: Don't do the legacy PCI probe by default
[pandora-kernel.git] / drivers / edac / i7core_edac.c
index e0187d1..a76a4c0 100644 (file)
 
 #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,34 +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",
@@ -1179,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 */
 };
 
 /****************************************************************************
@@ -1206,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
@@ -1261,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;
 
@@ -1372,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();
 
@@ -1403,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,
@@ -1447,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:
@@ -1469,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;
@@ -1486,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;
@@ -1640,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;
@@ -1845,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;
@@ -1858,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;
@@ -1880,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;
 
@@ -1904,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;
@@ -1928,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__
@@ -1948,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)
 {
@@ -2007,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
@@ -2023,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--;
 
@@ -2069,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);