| From d0f6404e68ef5023606841dac7f593035c92a9ae Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 16 Jul 2020 14:25:11 -0400 |
| Subject: EDAC/ie31200: Fallback if host bridge device is already initialized |
| |
| From: Jason Baron <jbaron@akamai.com> |
| |
| [ Upstream commit 709ed1bcef12398ac1a35c149f3e582db04456c2 ] |
| |
| 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 |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/edac/ie31200_edac.c | 50 ++++++++++++++++++++++++++++++++++--- |
| 1 file changed, 47 insertions(+), 3 deletions(-) |
| |
| diff --git a/drivers/edac/ie31200_edac.c b/drivers/edac/ie31200_edac.c |
| index 1c88d97074951..3438b98e60948 100644 |
| --- a/drivers/edac/ie31200_edac.c |
| +++ b/drivers/edac/ie31200_edac.c |
| @@ -145,6 +145,8 @@ |
| (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; |
| @@ -512,12 +514,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) |
| @@ -526,6 +532,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; |
| @@ -574,17 +582,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); |
| -- |
| 2.25.1 |
| |