diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/pci.c | 43 | ||||
-rw-r--r-- | drivers/pci/pci.h | 3 | ||||
-rw-r--r-- | drivers/pci/probe.c | 4 |
3 files changed, 48 insertions, 2 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index b821a62958f..e8ccf6c0f08 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -3998,6 +3998,49 @@ int pcie_set_mps(struct pci_dev *dev, int mps) } /** + * pcie_get_minimum_link - determine minimum link settings of a PCI device + * @dev: PCI device to query + * @speed: storage for minimum speed + * @width: storage for minimum width + * + * This function will walk up the PCI device chain and determine the minimum + * link width and speed of the device. + */ +int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed, + enum pcie_link_width *width) +{ + int ret; + + *speed = PCI_SPEED_UNKNOWN; + *width = PCIE_LNK_WIDTH_UNKNOWN; + + while (dev) { + u16 lnksta; + enum pci_bus_speed next_speed; + enum pcie_link_width next_width; + + ret = pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta); + if (ret) + return ret; + + next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS]; + next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >> + PCI_EXP_LNKSTA_NLW_SHIFT; + + if (next_speed < *speed) + *speed = next_speed; + + if (next_width < *width) + *width = next_width; + + dev = dev->bus->self; + } + + return 0; +} +EXPORT_SYMBOL(pcie_get_minimum_link); + +/** * pci_select_bars - Make BAR mask from the type of resource * @dev: the PCI device for which BAR mask is made * @flags: resource type mask to be selected diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index 816c297f170..8a00c063d7b 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -6,6 +6,9 @@ #define PCI_CFG_SPACE_SIZE 256 #define PCI_CFG_SPACE_EXP_SIZE 4096 +extern const unsigned char pcix_bus_speed[]; +extern const unsigned char pcie_link_speed[]; + /* Functions internal to the PCI core code */ int pci_create_sysfs_dev_files(struct pci_dev *pdev); diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index eeb50bd6240..4f9cc93c3b5 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -518,7 +518,7 @@ static struct pci_host_bridge *pci_alloc_host_bridge(struct pci_bus *b) return bridge; } -static unsigned char pcix_bus_speed[] = { +const unsigned char pcix_bus_speed[] = { PCI_SPEED_UNKNOWN, /* 0 */ PCI_SPEED_66MHz_PCIX, /* 1 */ PCI_SPEED_100MHz_PCIX, /* 2 */ @@ -537,7 +537,7 @@ static unsigned char pcix_bus_speed[] = { PCI_SPEED_133MHz_PCIX_533 /* F */ }; -static unsigned char pcie_link_speed[] = { +const unsigned char pcie_link_speed[] = { PCI_SPEED_UNKNOWN, /* 0 */ PCIE_SPEED_2_5GT, /* 1 */ PCIE_SPEED_5_0GT, /* 2 */ |