Skip to content

Commit d2bd39c

Browse files
ij-intelbjorn-helgaas
authored andcommitted
PCI: Store all PCIe Supported Link Speeds
The PCIe bandwidth controller added by a subsequent commit will require selecting PCIe Link Speeds that are lower than the Maximum Link Speed. The struct pci_bus only stores max_bus_speed. Even if PCIe r6.1 sec 8.2.1 currently disallows gaps in supported Link Speeds, the Implementation Note in PCIe r6.1 sec 7.5.3.18, recommends determining supported Link Speeds using the Supported Link Speeds Vector in the Link Capabilities 2 Register (when available) to "avoid software being confused if a future specification defines Links that do not require support for all slower speeds." Reuse code in pcie_get_speed_cap() to add pcie_get_supported_speeds() to query the Supported Link Speeds Vector of a PCIe device. The value is taken directly from the Supported Link Speeds Vector or synthesized from the Max Link Speed in the Link Capabilities Register when the Link Capabilities 2 Register is not available. 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 (PCIe r6.1 sec 7.5.3.18): Supported Link Speeds Vector - This field indicates the supported Link speed(s) of the associated Port. Add supported_speeds into the struct pci_dev that caches the Supported Link Speeds Vector. supported_speeds contains a set of Link Speeds only in the case where PCIe Link Speed can be determined. Root Complex Integrated Endpoints do not have a well-defined Link Speed because they do not implement either of the Link Capabilities Registers, which is allowed by PCIe r6.1 sec 7.5.3 (the same limitation applies to determining cur_bus_speed and max_bus_speed that are PCI_SPEED_UNKNOWN in such case). This is of no concern from PCIe bandwidth controller point of view because such devices are not attached into a PCIe Root Port that could be controlled. The supported_speeds field keeps the extra reserved zero at the least significant bit to match the Link Capabilities 2 Register layout. An attempt was made to store supported_speeds field into the struct pci_bus as an intersection of both ends of the Link, however, the subordinate struct pci_bus is not available early enough. The Target Speed quirk (in pcie_failed_link_retrain()) can run either during initial scan or later, requiring it to use the API provided by the PCIe bandwidth controller to set the Target Link Speed in order to co-exist with the bandwidth controller. When the Target Speed quirk is calling the bandwidth controller during initial scan, the struct pci_bus is not yet initialized. As such, storing supported_speeds into the struct pci_bus is not viable. Suggested-by: Lukas Wunner <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Ilpo Järvinen <[email protected]> [bhelgaas: move pcie_get_supported_speeds() decl to drivers/pci/pci.h] Signed-off-by: Bjorn Helgaas <[email protected]> Reviewed-by: Jonathan Cameron <[email protected]>
1 parent 04af8a3 commit d2bd39c

File tree

5 files changed

+56
-17
lines changed

5 files changed

+56
-17
lines changed

drivers/pci/pci.c

Lines changed: 42 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6189,38 +6189,64 @@ u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
61896189
EXPORT_SYMBOL(pcie_bandwidth_available);
61906190

61916191
/**
6192-
* pcie_get_speed_cap - query for the PCI device's link speed capability
6192+
* pcie_get_supported_speeds - query Supported Link Speed Vector
61936193
* @dev: PCI device to query
61946194
*
6195-
* Query the PCI device speed capability. Return the maximum link speed
6196-
* supported by the device.
6195+
* Query @dev supported link speeds.
6196+
*
6197+
* Implementation Note in PCIe r6.0 sec 7.5.3.18 recommends determining
6198+
* supported link speeds using the Supported Link Speeds Vector in the Link
6199+
* Capabilities 2 Register (when available).
6200+
*
6201+
* Link Capabilities 2 was added in PCIe r3.0, sec 7.8.18.
6202+
*
6203+
* Without Link Capabilities 2, i.e., prior to PCIe r3.0, Supported Link
6204+
* Speeds field in Link Capabilities is used and only 2.5 GT/s and 5.0 GT/s
6205+
* speeds were defined.
6206+
*
6207+
* For @dev without Supported Link Speed Vector, the field is synthesized
6208+
* from the Max Link Speed field in the Link Capabilities Register.
6209+
*
6210+
* Return: Supported Link Speeds Vector (+ reserved 0 at LSB).
61976211
*/
6198-
enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev)
6212+
u8 pcie_get_supported_speeds(struct pci_dev *dev)
61996213
{
62006214
u32 lnkcap2, lnkcap;
6215+
u8 speeds;
62016216

62026217
/*
6203-
* Link Capabilities 2 was added in PCIe r3.0, sec 7.8.18. The
6204-
* implementation note there recommends using the Supported Link
6205-
* Speeds Vector in Link Capabilities 2 when supported.
6206-
*
6207-
* Without Link Capabilities 2, i.e., prior to PCIe r3.0, software
6208-
* should use the Supported Link Speeds field in Link Capabilities,
6209-
* where only 2.5 GT/s and 5.0 GT/s speeds were defined.
6218+
* Speeds retain the reserved 0 at LSB before PCIe Supported Link
6219+
* Speeds Vector to allow using SLS Vector bit defines directly.
62106220
*/
62116221
pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2);
6222+
speeds = lnkcap2 & PCI_EXP_LNKCAP2_SLS;
62126223

62136224
/* PCIe r3.0-compliant */
6214-
if (lnkcap2)
6215-
return PCIE_LNKCAP2_SLS2SPEED(lnkcap2);
6225+
if (speeds)
6226+
return speeds;
62166227

62176228
pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
6229+
6230+
/* Synthesize from the Max Link Speed field */
62186231
if ((lnkcap & PCI_EXP_LNKCAP_SLS) == PCI_EXP_LNKCAP_SLS_5_0GB)
6219-
return PCIE_SPEED_5_0GT;
6232+
speeds = PCI_EXP_LNKCAP2_SLS_5_0GB | PCI_EXP_LNKCAP2_SLS_2_5GB;
62206233
else if ((lnkcap & PCI_EXP_LNKCAP_SLS) == PCI_EXP_LNKCAP_SLS_2_5GB)
6221-
return PCIE_SPEED_2_5GT;
6234+
speeds = PCI_EXP_LNKCAP2_SLS_2_5GB;
62226235

6223-
return PCI_SPEED_UNKNOWN;
6236+
return speeds;
6237+
}
6238+
6239+
/**
6240+
* pcie_get_speed_cap - query for the PCI device's link speed capability
6241+
* @dev: PCI device to query
6242+
*
6243+
* Query the PCI device speed capability.
6244+
*
6245+
* Return: the maximum link speed supported by the device.
6246+
*/
6247+
enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev)
6248+
{
6249+
return PCIE_LNKCAP2_SLS2SPEED(dev->supported_speeds);
62246250
}
62256251
EXPORT_SYMBOL(pcie_get_speed_cap);
62266252

drivers/pci/pci.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ static inline int pcie_dev_speed_mbps(enum pci_bus_speed speed)
373373
return -EINVAL;
374374
}
375375

376+
u8 pcie_get_supported_speeds(struct pci_dev *dev);
376377
const char *pci_speed_string(enum pci_bus_speed speed);
377378
enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev);
378379
enum pcie_link_width pcie_get_width_cap(struct pci_dev *dev);

drivers/pci/probe.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1947,6 +1947,9 @@ int pci_setup_device(struct pci_dev *dev)
19471947

19481948
set_pcie_untrusted(dev);
19491949

1950+
if (pci_is_pcie(dev))
1951+
dev->supported_speeds = pcie_get_supported_speeds(dev);
1952+
19501953
/* "Unknown power state" */
19511954
dev->current_state = PCI_UNKNOWN;
19521955

include/linux/pci.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,14 @@ struct pci_sriov;
318318
struct pci_p2pdma;
319319
struct rcec_ea;
320320

321-
/* The pci_dev structure describes PCI devices */
321+
/* struct pci_dev - describes a PCI device
322+
*
323+
* @supported_speeds: PCIe Supported Link Speeds Vector (+ reserved 0 at
324+
* LSB). 0 when the supported speeds cannot be
325+
* determined (e.g., for Root Complex Integrated
326+
* Endpoints without the relevant Capability
327+
* Registers).
328+
*/
322329
struct pci_dev {
323330
struct list_head bus_list; /* Node in per-bus list */
324331
struct pci_bus *bus; /* Bus this device is on */
@@ -522,6 +529,7 @@ struct pci_dev {
522529
struct npem *npem; /* Native PCIe Enclosure Management */
523530
#endif
524531
u16 acs_cap; /* ACS Capability offset */
532+
u8 supported_speeds; /* Supported Link Speeds Vector */
525533
phys_addr_t rom; /* Physical address if not from BAR */
526534
size_t romlen; /* Length if not from BAR */
527535
/*

include/uapi/linux/pci_regs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,7 @@
678678
#define PCI_EXP_DEVSTA2 0x2a /* Device Status 2 */
679679
#define PCI_CAP_EXP_RC_ENDPOINT_SIZEOF_V2 0x2c /* end of v2 EPs w/o link */
680680
#define PCI_EXP_LNKCAP2 0x2c /* Link Capabilities 2 */
681+
#define PCI_EXP_LNKCAP2_SLS 0x000000fe /* Supported Link Speeds Vector */
681682
#define PCI_EXP_LNKCAP2_SLS_2_5GB 0x00000002 /* Supported Speed 2.5GT/s */
682683
#define PCI_EXP_LNKCAP2_SLS_5_0GB 0x00000004 /* Supported Speed 5GT/s */
683684
#define PCI_EXP_LNKCAP2_SLS_8_0GB 0x00000008 /* Supported Speed 8GT/s */

0 commit comments

Comments
 (0)