edac: make i82443bxgx_edac coexist with intel_agp
authorVladislav Bogdanov <slava_reg@nsys.by>
Thu, 16 Oct 2008 05:04:26 +0000 (22:04 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 16 Oct 2008 18:21:48 +0000 (11:21 -0700)
Fix 443BX/GX MCH suppport in a EDAC.

It makes i82443bxgx_edac coexist with intel_agp using the same approach as
several other EDAC drivers.

Tested on Intel's L443GX with redhat's 2.6.18 with whole EDAC subsystem
backported a while ago.

[root@host ~]# dmesg|grep -iE '(AGP|EDAC)'
Linux agpgart interface v0.101 (c) Dave Jones
agpgart: Detected an Intel 440GX Chipset.
agpgart: AGP aperture is 64M @ 0xf8000000
EDAC MC: Ver: 2.1.0 Jun 27 2008
EDAC MC0: Giving out device to 'i82443bxgx_edac' 'I82443BXGX': DEV 0000:00:00.0
EDAC PCI0: Giving out device to module 'i82443bxgx_edac' controller 'EDAC PCI controller': DEV '0000:00:00.0' (POLLED)

Signed-off-by: Vladislav Bogdanov <slava@nsys.by>
Cc: Doug Thompson <norsk5@yahoo.com>
Cc: Dave Airlie <airlied@linux.ie>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
drivers/edac/i82443bxgx_edac.c

index c5305e3..577760a 100644 (file)
@@ -114,6 +114,12 @@ 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)
@@ -345,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)
@@ -387,15 +400,61 @@ static struct pci_driver i82443bxgx_edacmc_driver = {
 
 static int __init i82443bxgx_edacmc_init(void)
 {
+       int pci_rc;
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
 
-       return pci_register_driver(&i82443bxgx_edacmc_driver);
+       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);