@@ -2564,6 +2564,7 @@ static void pci_set_msi_domain(struct pci_dev *dev)
void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
{
+ u8 dev_speeds = 0;
int ret;
pci_configure_device(dev);
@@ -2590,11 +2591,20 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
pci_init_capabilities(dev);
+ if (pci_is_pcie(dev) && PCI_FUNC(dev->devfn) == 0) {
+ u32 linkcap, linkcap2;
+
+ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &linkcap);
+ pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &linkcap2);
+ dev_speeds = pcie_get_supported_speeds(linkcap, linkcap2);
+ }
/*
* Add the device to our list of discovered devices
* and the bus list for fixup functions, etc.
*/
down_write(&pci_bus_sem);
+ if (dev_speeds)
+ bus->pcie_dev_speeds = dev_speeds;
list_add_tail(&dev->bus_list, &bus->devices);
up_write(&pci_bus_sem);
@@ -36,6 +36,8 @@ static void pci_destroy_dev(struct pci_dev *dev)
device_del(&dev->dev);
down_write(&pci_bus_sem);
+ if (pci_is_pcie(dev) && PCI_FUNC(dev->devfn) == 0)
+ dev->bus->pcie_dev_speeds = 0;
list_del(&dev->bus_list);
up_write(&pci_bus_sem);
@@ -665,6 +665,7 @@ struct pci_bus {
unsigned char max_bus_speed; /* enum pci_bus_speed */
unsigned char cur_bus_speed; /* enum pci_bus_speed */
u8 pcie_bus_speeds;/* Supported Link Speeds Vector (+ reserved 0 at LSB) */
+ u8 pcie_dev_speeds;/* Device's Supported Link Speeds Vector (+ 0 at LSB) */
#ifdef CONFIG_PCI_DOMAINS_GENERIC
int domain_nr;
#endif
The Supported Link Speeds Vector in the Link Capabilities Register 2 corresponds to the bus below on Root Ports and Downstream Ports, whereas it corresponds to the bus above on Upstream Ports and Endpoints. Only the former is currently cached in pcie_bus_speeds in the struct pci_bus. The link speeds that are supported is the intersection of these two. Store the device's Supported Link Speeds Vector into the struct pci_bus when the Function 0 is enumerated (the Multi-Function Devices must have same speeds the same for all Functions) to be easily able to calculate the intersection of Supported Link Speeds. Suggested-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com> --- drivers/pci/probe.c | 10 ++++++++++ drivers/pci/remove.c | 2 ++ include/linux/pci.h | 1 + 3 files changed, 13 insertions(+)