From: Alex Williamson <[email protected]>

3.12-stable review patch.  If anyone has any objections, please let me know.

===============

commit da2d03ea27f6ed9d2005a67b20dd021ddacf1e4d upstream.

932c435caba8 ("PCI: Add dev_flags bit to access VPD through function 0")
added PCI_DEV_FLAGS_VPD_REF_F0.  Previously, we set the flag on every
non-zero function of quirked devices.  If a function turned out to be
different from function 0, i.e., it had a different class, vendor ID, or
device ID, the flag remained set but we didn't make VPD accessible at all.

Flip this around so we only set PCI_DEV_FLAGS_VPD_REF_F0 for functions that
are identical to function 0, and allow regular VPD access for any other
functions.

[bhelgaas: changelog, stable tag]
Fixes: 932c435caba8 ("PCI: Add dev_flags bit to access VPD through function 0")
Signed-off-by: Alex Williamson <[email protected]>
Signed-off-by: Bjorn Helgaas <[email protected]>
Acked-by: Myron Stowe <[email protected]>
Acked-by: Mark Rustad <[email protected]>
Signed-off-by: Jiri Slaby <[email protected]>
---
 drivers/pci/access.c | 22 ----------------------
 drivers/pci/quirks.c | 20 ++++++++++++++++++--
 2 files changed, 18 insertions(+), 24 deletions(-)

diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 16a022ee54a6..da26bc899d5f 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -395,23 +395,6 @@ static const struct pci_vpd_ops pci_vpd_f0_ops = {
        .release = pci_vpd_pci22_release,
 };
 
-static int pci_vpd_f0_dev_check(struct pci_dev *dev)
-{
-       struct pci_dev *tdev = pci_get_slot(dev->bus,
-                                           PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
-       int ret = 0;
-
-       if (!tdev)
-               return -ENODEV;
-       if (!tdev->vpd || !tdev->multifunction ||
-           dev->class != tdev->class || dev->vendor != tdev->vendor ||
-           dev->device != tdev->device)
-               ret = -ENODEV;
-
-       pci_dev_put(tdev);
-       return ret;
-}
-
 int pci_vpd_pci22_init(struct pci_dev *dev)
 {
        struct pci_vpd_pci22 *vpd;
@@ -420,12 +403,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
        cap = pci_find_capability(dev, PCI_CAP_ID_VPD);
        if (!cap)
                return -ENODEV;
-       if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) {
-               int ret = pci_vpd_f0_dev_check(dev);
 
-               if (ret)
-                       return ret;
-       }
        vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC);
        if (!vpd)
                return -ENOMEM;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index cb245bd510a2..b1f5f51b0196 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1894,11 +1894,27 @@ static void quirk_netmos(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID,
                         PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos);
 
+/*
+ * Quirk non-zero PCI functions to route VPD access through function 0 for
+ * devices that share VPD resources between functions.  The functions are
+ * expected to be identical devices.
+ */
 static void quirk_f0_vpd_link(struct pci_dev *dev)
 {
-       if (!dev->multifunction || !PCI_FUNC(dev->devfn))
+       struct pci_dev *f0;
+
+       if (!PCI_FUNC(dev->devfn))
                return;
-       dev->dev_flags |= PCI_DEV_FLAGS_VPD_REF_F0;
+
+       f0 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0));
+       if (!f0)
+               return;
+
+       if (f0->vpd && dev->class == f0->class &&
+           dev->vendor == f0->vendor && dev->device == f0->device)
+               dev->dev_flags |= PCI_DEV_FLAGS_VPD_REF_F0;
+
+       pci_dev_put(f0);
 }
 DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
                              PCI_CLASS_NETWORK_ETHERNET, 8, quirk_f0_vpd_link);
-- 
2.11.0

Reply via email to