summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2015-09-15 22:24:46 -0600
committerBen Hutchings <ben@decadent.org.uk>2015-11-27 12:48:19 +0000
commitb2af40d1de4d8d3e22c8a6aeb785ab1d1c41801a (patch)
treed3c764691220b978374dcebe362995fc6482c4ea /drivers
parent991e923fb23b1fff62283078fd4734f42e1bf398 (diff)
PCI: Use function 0 VPD for identical functions, regular VPD for others
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 <alex.williamson@redhat.com> Signed-off-by: Bjorn Helgaas <helgaas@kernel.org> Acked-by: Myron Stowe <myron.stowe@redhat.com> Acked-by: Mark Rustad <mark.d.rustad@intel.com> [bwh: Backported to 3.2: adjust context] Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/access.c22
-rw-r--r--drivers/pci/quirks.c20
2 files changed, 18 insertions, 24 deletions
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 8599e2037109..32785cd72e40 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -391,23 +391,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;
@@ -416,12 +399,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 93be76036e68..604ee35e3905 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -1941,12 +1941,28 @@ static void __devinit quirk_netmos(struct pci_dev *dev)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, 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)
{
+ struct pci_dev *f0;
+
if ((dev->class >> 8) != PCI_CLASS_NETWORK_ETHERNET ||
- !dev->multifunction || !PCI_FUNC(dev->devfn))
+ !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_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, quirk_f0_vpd_link);