diff options
author | Alex Williamson <alex.williamson@redhat.com> | 2015-09-16 00:24:46 -0400 |
---|---|---|
committer | Bjorn Helgaas <helgaas@kernel.org> | 2015-09-24 18:06:32 -0400 |
commit | da2d03ea27f6ed9d2005a67b20dd021ddacf1e4d (patch) | |
tree | 5ed4545d7fd11df195a195055ff0cdf43dcee378 | |
parent | 9d9240756e63dd87d6cbf5da8b98ceb8f8192b55 (diff) |
PCI: Use function 0 VPD for identical functions, regular VPD for others
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>
CC: stable@vger.kernel.org
-rw-r--r-- | drivers/pci/access.c | 22 | ||||
-rw-r--r-- | 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 5a5f0a7ba801..59ac36fe7c42 100644 --- a/drivers/pci/access.c +++ b/drivers/pci/access.c | |||
@@ -475,23 +475,6 @@ static const struct pci_vpd_ops pci_vpd_f0_ops = { | |||
475 | .release = pci_vpd_pci22_release, | 475 | .release = pci_vpd_pci22_release, |
476 | }; | 476 | }; |
477 | 477 | ||
478 | static int pci_vpd_f0_dev_check(struct pci_dev *dev) | ||
479 | { | ||
480 | struct pci_dev *tdev = pci_get_slot(dev->bus, | ||
481 | PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); | ||
482 | int ret = 0; | ||
483 | |||
484 | if (!tdev) | ||
485 | return -ENODEV; | ||
486 | if (!tdev->vpd || !tdev->multifunction || | ||
487 | dev->class != tdev->class || dev->vendor != tdev->vendor || | ||
488 | dev->device != tdev->device) | ||
489 | ret = -ENODEV; | ||
490 | |||
491 | pci_dev_put(tdev); | ||
492 | return ret; | ||
493 | } | ||
494 | |||
495 | int pci_vpd_pci22_init(struct pci_dev *dev) | 478 | int pci_vpd_pci22_init(struct pci_dev *dev) |
496 | { | 479 | { |
497 | struct pci_vpd_pci22 *vpd; | 480 | struct pci_vpd_pci22 *vpd; |
@@ -500,12 +483,7 @@ int pci_vpd_pci22_init(struct pci_dev *dev) | |||
500 | cap = pci_find_capability(dev, PCI_CAP_ID_VPD); | 483 | cap = pci_find_capability(dev, PCI_CAP_ID_VPD); |
501 | if (!cap) | 484 | if (!cap) |
502 | return -ENODEV; | 485 | return -ENODEV; |
503 | if (dev->dev_flags & PCI_DEV_FLAGS_VPD_REF_F0) { | ||
504 | int ret = pci_vpd_f0_dev_check(dev); | ||
505 | 486 | ||
506 | if (ret) | ||
507 | return ret; | ||
508 | } | ||
509 | vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC); | 487 | vpd = kzalloc(sizeof(*vpd), GFP_ATOMIC); |
510 | if (!vpd) | 488 | if (!vpd) |
511 | return -ENOMEM; | 489 | return -ENOMEM; |
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c index 6a30252cd79f..b03373fd05ca 100644 --- a/drivers/pci/quirks.c +++ b/drivers/pci/quirks.c | |||
@@ -1907,11 +1907,27 @@ static void quirk_netmos(struct pci_dev *dev) | |||
1907 | DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, | 1907 | DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_NETMOS, PCI_ANY_ID, |
1908 | PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos); | 1908 | PCI_CLASS_COMMUNICATION_SERIAL, 8, quirk_netmos); |
1909 | 1909 | ||
1910 | /* | ||
1911 | * Quirk non-zero PCI functions to route VPD access through function 0 for | ||
1912 | * devices that share VPD resources between functions. The functions are | ||
1913 | * expected to be identical devices. | ||
1914 | */ | ||
1910 | static void quirk_f0_vpd_link(struct pci_dev *dev) | 1915 | static void quirk_f0_vpd_link(struct pci_dev *dev) |
1911 | { | 1916 | { |
1912 | if (!dev->multifunction || !PCI_FUNC(dev->devfn)) | 1917 | struct pci_dev *f0; |
1918 | |||
1919 | if (!PCI_FUNC(dev->devfn)) | ||
1913 | return; | 1920 | return; |
1914 | dev->dev_flags |= PCI_DEV_FLAGS_VPD_REF_F0; | 1921 | |
1922 | f0 = pci_get_slot(dev->bus, PCI_DEVFN(PCI_SLOT(dev->devfn), 0)); | ||
1923 | if (!f0) | ||
1924 | return; | ||
1925 | |||
1926 | if (f0->vpd && dev->class == f0->class && | ||
1927 | dev->vendor == f0->vendor && dev->device == f0->device) | ||
1928 | dev->dev_flags |= PCI_DEV_FLAGS_VPD_REF_F0; | ||
1929 | |||
1930 | pci_dev_put(f0); | ||
1915 | } | 1931 | } |
1916 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, | 1932 | DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_VENDOR_ID_INTEL, PCI_ANY_ID, |
1917 | PCI_CLASS_NETWORK_ETHERNET, 8, quirk_f0_vpd_link); | 1933 | PCI_CLASS_NETWORK_ETHERNET, 8, quirk_f0_vpd_link); |