PCI: Use function 0 VPD for identical functions, regular VPD for others

932c435cab ("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: 932c435cab ("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>
CC: stable@vger.kernel.org
This commit is contained in:
Alex Williamson 2015-09-15 22:24:46 -06:00 committed by Bjorn Helgaas
parent 9d9240756e
commit da2d03ea27
2 changed files with 18 additions and 24 deletions

View File

@ -475,23 +475,6 @@ static const struct pci_vpd_ops pci_vpd_f0_ops = {
.release = pci_vpd_pci22_release, .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) int pci_vpd_pci22_init(struct pci_dev *dev)
{ {
struct pci_vpd_pci22 *vpd; struct pci_vpd_pci22 *vpd;
@ -500,12 +483,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev)
cap = pci_find_capability(dev, PCI_CAP_ID_VPD); cap = pci_find_capability(dev, PCI_CAP_ID_VPD);
if (!cap) if (!cap)
return -ENODEV; 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); vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC);
if (!vpd) if (!vpd)
return -ENOMEM; return -ENOMEM;

View File

@ -1907,11 +1907,27 @@ static void quirk_netmos(struct pci_dev *dev)
DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID,
PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos); 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) 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; return;
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; 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, DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID,
PCI_CLASS_NETWORK_ETHERNET, 8, quirk_f0_vpd_link); PCI_CLASS_NETWORK_ETHERNET, 8, quirk_f0_vpd_link);