summaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci.c
diff options
context:
space:
mode:
authorJacob Keller <jacob.e.keller@intel.com>2013-07-31 02:53:26 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2013-07-31 03:30:20 -0400
commit81377c8d3563e7aec5c8baaaacacb48034f430a0 (patch)
treefe58387e3bea2c5b5656e2a81d9bfd558b2a3d83 /drivers/pci/pci.c
parent59da381ee2afc806f85becf3aa64ffc952355552 (diff)
PCI: Add function to obtain minimum link width and speed
A PCI Express device can potentially report a link width and speed which it will not properly fulfill due to being plugged into a slower link higher in the chain. This function walks up the PCI bus chain and calculates the minimum link width and speed of this entire chain. This can be useful to enable a device to determine if it has enough bandwidth for optimum functionality. Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/pci/pci.c')
-rw-r--r--drivers/pci/pci.c43
1 files changed, 43 insertions, 0 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e37fea6e178d..c71e78c46705 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -3579,6 +3579,49 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
3579} 3579}
3580 3580
3581/** 3581/**
3582 * pcie_get_minimum_link - determine minimum link settings of a PCI device
3583 * @dev: PCI device to query
3584 * @speed: storage for minimum speed
3585 * @width: storage for minimum width
3586 *
3587 * This function will walk up the PCI device chain and determine the minimum
3588 * link width and speed of the device.
3589 */
3590int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
3591 enum pcie_link_width *width)
3592{
3593 int ret;
3594
3595 *speed = PCI_SPEED_UNKNOWN;
3596 *width = PCIE_LNK_WIDTH_UNKNOWN;
3597
3598 while (dev) {
3599 u16 lnksta;
3600 enum pci_bus_speed next_speed;
3601 enum pcie_link_width next_width;
3602
3603 ret = pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
3604 if (ret)
3605 return ret;
3606
3607 next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
3608 next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
3609 PCI_EXP_LNKSTA_NLW_SHIFT;
3610
3611 if (next_speed < *speed)
3612 *speed = next_speed;
3613
3614 if (next_width < *width)
3615 *width = next_width;
3616
3617 dev = dev->bus->self;
3618 }
3619
3620 return 0;
3621}
3622EXPORT_SYMBOL(pcie_get_minimum_link);
3623
3624/**
3582 * pci_select_bars - Make BAR mask from the type of resource 3625 * pci_select_bars - Make BAR mask from the type of resource
3583 * @dev: the PCI device for which BAR mask is made 3626 * @dev: the PCI device for which BAR mask is made
3584 * @flags: resource type mask to be selected 3627 * @flags: resource type mask to be selected