EDAC/ie31200: Fallback if host bridge device is already initialized
authorJason Baron <jbaron@akamai.com>
Thu, 16 Jul 2020 18:25:11 +0000 (14:25 -0400)
committerTony Luck <tony.luck@intel.com>
Mon, 10 Aug 2020 18:13:06 +0000 (11:13 -0700)
The Intel uncore driver may claim some of the pci ids from ie31200 which
means that the ie31200 edac driver will not initialize them as part of
pci_register_driver().

Let's add a fallback for this case to 'pci_get_device()' to get a
reference on the device such that it can still be configured. This is
similar in approach to other edac drivers.

Signed-off-by: Jason Baron <jbaron@akamai.com>
Cc: Borislav Petkov <bp@suse.de>
Cc: Mauro Carvalho Chehab <mchehab@kernel.org>
Cc: linux-edac <linux-edac@vger.kernel.org>
Signed-off-by: Tony Luck <tony.luck@intel.com>
Link: https://lore.kernel.org/r/1594923911-10885-1-git-send-email-jbaron@akamai.com
drivers/edac/ie31200_edac.c

index d68346a..ebe5099 100644 (file)
        (n << (28 + (2 * skl) - PAGE_SHIFT))
 
 static int nr_channels;
+static struct pci_dev *mci_pdev;
+static int ie31200_registered = 1;
 
 struct ie31200_priv {
        void __iomem *window;
@@ -538,12 +540,16 @@ fail_free:
 static int ie31200_init_one(struct pci_dev *pdev,
                            const struct pci_device_id *ent)
 {
-       edac_dbg(0, "MC:\n");
+       int rc;
 
+       edac_dbg(0, "MC:\n");
        if (pci_enable_device(pdev) < 0)
                return -EIO;
+       rc = ie31200_probe1(pdev, ent->driver_data);
+       if (rc == 0 && !mci_pdev)
+               mci_pdev = pci_dev_get(pdev);
 
-       return ie31200_probe1(pdev, ent->driver_data);
+       return rc;
 }
 
 static void ie31200_remove_one(struct pci_dev *pdev)
@@ -552,6 +558,8 @@ static void ie31200_remove_one(struct pci_dev *pdev)
        struct ie31200_priv *priv;
 
        edac_dbg(0, "\n");
+       pci_dev_put(mci_pdev);
+       mci_pdev = NULL;
        mci = edac_mc_del_mc(&pdev->dev);
        if (!mci)
                return;
@@ -593,17 +601,53 @@ static struct pci_driver ie31200_driver = {
 
 static int __init ie31200_init(void)
 {
+       int pci_rc, i;
+
        edac_dbg(3, "MC:\n");
        /* Ensure that the OPSTATE is set correctly for POLL or NMI */
        opstate_init();
 
-       return pci_register_driver(&ie31200_driver);
+       pci_rc = pci_register_driver(&ie31200_driver);
+       if (pci_rc < 0)
+               goto fail0;
+
+       if (!mci_pdev) {
+               ie31200_registered = 0;
+               for (i = 0; ie31200_pci_tbl[i].vendor != 0; i++) {
+                       mci_pdev = pci_get_device(ie31200_pci_tbl[i].vendor,
+                                                 ie31200_pci_tbl[i].device,
+                                                 NULL);
+                       if (mci_pdev)
+                               break;
+               }
+               if (!mci_pdev) {
+                       edac_dbg(0, "ie31200 pci_get_device fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+               pci_rc = ie31200_init_one(mci_pdev, &ie31200_pci_tbl[i]);
+               if (pci_rc < 0) {
+                       edac_dbg(0, "ie31200 init fail\n");
+                       pci_rc = -ENODEV;
+                       goto fail1;
+               }
+       }
+       return 0;
+
+fail1:
+       pci_unregister_driver(&ie31200_driver);
+fail0:
+       pci_dev_put(mci_pdev);
+
+       return pci_rc;
 }
 
 static void __exit ie31200_exit(void)
 {
        edac_dbg(3, "MC:\n");
        pci_unregister_driver(&ie31200_driver);
+       if (!ie31200_registered)
+               ie31200_remove_one(mci_pdev);
 }
 
 module_init(ie31200_init);