edac, mce: correct corenum reporting
[safe/jmp/linux-2.6] / drivers / edac / i82443bxgx_edac.c
index d190104..577760a 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <linux/slab.h>
 
+#include <linux/edac.h>
 #include "edac_core.h"
 
 #define I82443_REVISION        "0.1"
@@ -113,9 +114,15 @@ struct i82443bxgx_edacmc_error_info {
 
 static struct edac_pci_ctl_info *i82443bxgx_pci;
 
+static struct pci_dev *mci_pdev;       /* init dev: in case that AGP code has
+                                        * already registered driver
+                                        */
+
+static int i82443bxgx_registered = 1;
+
 static void i82443bxgx_edacmc_get_error_info(struct mem_ctl_info *mci,
-                                            struct i82443bxgx_edacmc_error_info
-                                            *info)
+                               struct i82443bxgx_edacmc_error_info
+                               *info)
 {
        struct pci_dev *pdev;
        pdev = to_pci_dev(mci->dev);
@@ -151,17 +158,18 @@ static int i82443bxgx_edacmc_process_error_info(struct mem_ctl_info *mci,
                error_found = 1;
                if (handle_errors)
                        edac_mc_handle_ce(mci, page, pageoffset,
-                                         /* 440BX/GX don't make syndrome information available */
-                                         0, edac_mc_find_csrow_by_page(mci, page), 0,  /* channel */
-                                         mci->ctl_name);
+                               /* 440BX/GX don't make syndrome information
+                                * available */
+                               0, edac_mc_find_csrow_by_page(mci, page), 0,
+                               mci->ctl_name);
        }
 
        if (info->eap & I82443BXGX_EAP_OFFSET_MBE) {
                error_found = 1;
                if (handle_errors)
                        edac_mc_handle_ue(mci, page, pageoffset,
-                                         edac_mc_find_csrow_by_page(mci, page),
-                                         mci->ctl_name);
+                                       edac_mc_find_csrow_by_page(mci, page),
+                                       mci->ctl_name);
        }
 
        return error_found;
@@ -177,9 +185,9 @@ static void i82443bxgx_edacmc_check(struct mem_ctl_info *mci)
 }
 
 static void i82443bxgx_init_csrows(struct mem_ctl_info *mci,
-                                  struct pci_dev *pdev,
-                                  enum edac_type edac_mode,
-                                  enum mem_type mtype)
+                               struct pci_dev *pdev,
+                               enum edac_type edac_mode,
+                               enum mem_type mtype)
 {
        struct csrow_info *csrow;
        int index;
@@ -233,11 +241,12 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        debugf0("MC: " __FILE__ ": %s()\n", __func__);
 
        /* Something is really hosed if PCI config space reads from
-          the MC aren't working.  */
+        * the MC aren't working.
+        */
        if (pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg))
                return -EIO;
 
-       mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS);
+       mci = edac_mc_alloc(0, I82443BXGX_NR_CSROWS, I82443BXGX_NR_CHANS, 0);
 
        if (mci == NULL)
                return -ENOMEM;
@@ -258,8 +267,8 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
                mtype = MEM_RDR;
                break;
        default:
-               debugf0
-                   ("Unknown/reserved DRAM type value in DRAMC register!\n");
+               debugf0("Unknown/reserved DRAM type value "
+                       "in DRAMC register!\n");
                mtype = -MEM_UNKNOWN;
        }
 
@@ -271,10 +280,10 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        mci->scrub_cap = SCRUB_FLAG_HW_SRC;
        pci_read_config_dword(pdev, I82443BXGX_NBXCFG, &nbxcfg);
        ecc_mode = ((nbxcfg >> I82443BXGX_NBXCFG_OFFSET_DRAM_INTEGRITY) &
-                   (BIT(0) | BIT(1)));
+               (BIT(0) | BIT(1)));
 
        mci->scrub_mode = (ecc_mode == I82443BXGX_NBXCFG_INTEGRITY_SCRUB)
-           ? SCRUB_HW_SRC : SCRUB_NONE;
+               ? SCRUB_HW_SRC : SCRUB_NONE;
 
        switch (ecc_mode) {
        case I82443BXGX_NBXCFG_INTEGRITY_NONE:
@@ -288,9 +297,8 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
                edac_mode = EDAC_SECDED;
                break;
        default:
-               debugf0
-                   ("%s(): Unknown/reserved ECC state in NBXCFG register!\n",
-                    __func__);
+               debugf0("%s(): Unknown/reserved ECC state "
+                       "in NBXCFG register!\n", __func__);
                edac_mode = EDAC_UNKNOWN;
                break;
        }
@@ -301,10 +309,10 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
         * here, or we get "phantom" errors occuring at module-load
         * time. */
        pci_write_bits32(pdev, I82443BXGX_EAP,
-                        (I82443BXGX_EAP_OFFSET_SBE |
-                         I82443BXGX_EAP_OFFSET_MBE),
-                        (I82443BXGX_EAP_OFFSET_SBE |
-                         I82443BXGX_EAP_OFFSET_MBE));
+                       (I82443BXGX_EAP_OFFSET_SBE |
+                               I82443BXGX_EAP_OFFSET_MBE),
+                       (I82443BXGX_EAP_OFFSET_SBE |
+                               I82443BXGX_EAP_OFFSET_MBE));
 
        mci->mod_name = EDAC_MOD_STR;
        mci->mod_ver = I82443_REVISION;
@@ -313,7 +321,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        mci->edac_check = i82443bxgx_edacmc_check;
        mci->ctl_page_to_phys = NULL;
 
-       if (edac_mc_add_mc(mci, 0)) {
+       if (edac_mc_add_mc(mci)) {
                debugf3("%s(): failed edac_mc_add_mc()\n", __func__);
                goto fail;
        }
@@ -332,7 +340,7 @@ static int i82443bxgx_edacmc_probe1(struct pci_dev *pdev, int dev_idx)
        debugf3("MC: " __FILE__ ": %s(): success\n", __func__);
        return 0;
 
-      fail:
+fail:
        edac_mc_free(mci);
        return -ENODEV;
 }
@@ -343,10 +351,17 @@ EXPORT_SYMBOL_GPL(i82443bxgx_edacmc_probe1);
 static int __devinit i82443bxgx_edacmc_init_one(struct pci_dev *pdev,
                                                const struct pci_device_id *ent)
 {
+       int rc;
+
        debugf0("MC: " __FILE__ ": %s()\n", __func__);
 
        /* don't need to call pci_device_enable() */
-       return i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+       rc = i82443bxgx_edacmc_probe1(pdev, ent->driver_data);
+
+       if (mci_pdev == NULL)
+               mci_pdev = pci_dev_get(pdev);
+
+       return rc;
 }
 
 static void __devexit i82443bxgx_edacmc_remove_one(struct pci_dev *pdev)
@@ -385,12 +400,61 @@ static struct pci_driver i82443bxgx_edacmc_driver = {
 
 static int __init i82443bxgx_edacmc_init(void)
 {
-       return pci_register_driver(&i82443bxgx_edacmc_driver);
+       int pci_rc;
+       /* Ensure that the OPSTATE is set correctly for POLL or NMI */
+       opstate_init();
+
+       pci_rc = pci_register_driver(&i82443bxgx_edacmc_driver);
+       if (pci_rc < 0)
+               goto fail0;
+
+       if (mci_pdev == NULL) {
+               const struct pci_device_id *id = &i82443bxgx_pci_tbl[0];
+               int i = 0;
+               i82443bxgx_registered = 0;
+
+               while (mci_pdev == NULL && id->vendor != 0) {
+                       mci_pdev = pci_get_device(id->vendor,
+                                       id->device, NULL);
+                       i++;
+                       id = &i82443bxgx_pci_tbl[i];
+               }
+               if (!mci_pdev) {
+                       debugf0("i82443bxgx pci_get_device fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+
+               pci_rc = i82443bxgx_edacmc_init_one(mci_pdev, i82443bxgx_pci_tbl);
+
+               if (pci_rc < 0) {
+                       debugf0("i82443bxgx init fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+       }
+
+       return 0;
+
+fail1:
+       pci_unregister_driver(&i82443bxgx_edacmc_driver);
+
+fail0:
+       if (mci_pdev != NULL)
+               pci_dev_put(mci_pdev);
+
+       return pci_rc;
 }
 
 static void __exit i82443bxgx_edacmc_exit(void)
 {
        pci_unregister_driver(&i82443bxgx_edacmc_driver);
+
+       if (!i82443bxgx_registered)
+               i82443bxgx_edacmc_remove_one(mci_pdev);
+
+       if (mci_pdev)
+               pci_dev_put(mci_pdev);
 }
 
 module_init(i82443bxgx_edacmc_init);
@@ -399,3 +463,6 @@ module_exit(i82443bxgx_edacmc_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Tim Small <tim@buttersideup.com> - WPAD");
 MODULE_DESCRIPTION("EDAC MC support for Intel 82443BX/GX memory controllers");
+
+module_param(edac_op_state, int, 0444);
+MODULE_PARM_DESC(edac_op_state, "EDAC Error Reporting state: 0=Poll,1=NMI");