Commit 6cf57be0 authored by Tal Gilboa's avatar Tal Gilboa Committed by Bjorn Helgaas

PCI: Add pcie_get_speed_cap() to find max supported link speed

Add pcie_get_speed_cap() to find the max link speed supported by a device.
Change max_link_speed_show() to use pcie_get_speed_cap().
Signed-off-by: default avatarTal Gilboa <talgi@mellanox.com>
[bhelgaas: return speed directly instead of error and *speed, don't export
outside drivers/pci]
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarTariq Toukan <tariqt@mellanox.com>
parent 1acfb9b7
...@@ -158,33 +158,9 @@ static DEVICE_ATTR_RO(resource); ...@@ -158,33 +158,9 @@ static DEVICE_ATTR_RO(resource);
static ssize_t max_link_speed_show(struct device *dev, static ssize_t max_link_speed_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct pci_dev *pci_dev = to_pci_dev(dev); struct pci_dev *pdev = to_pci_dev(dev);
u32 linkcap;
int err;
const char *speed;
err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap);
if (err)
return -EINVAL;
switch (linkcap & PCI_EXP_LNKCAP_SLS) {
case PCI_EXP_LNKCAP_SLS_16_0GB:
speed = "16 GT/s";
break;
case PCI_EXP_LNKCAP_SLS_8_0GB:
speed = "8 GT/s";
break;
case PCI_EXP_LNKCAP_SLS_5_0GB:
speed = "5 GT/s";
break;
case PCI_EXP_LNKCAP_SLS_2_5GB:
speed = "2.5 GT/s";
break;
default:
speed = "Unknown speed";
}
return sprintf(buf, "%s\n", speed); return sprintf(buf, "%s\n", PCIE_SPEED2STR(pcie_get_speed_cap(pdev)));
} }
static DEVICE_ATTR_RO(max_link_speed); static DEVICE_ATTR_RO(max_link_speed);
......
...@@ -5146,6 +5146,50 @@ int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed, ...@@ -5146,6 +5146,50 @@ int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
} }
EXPORT_SYMBOL(pcie_get_minimum_link); EXPORT_SYMBOL(pcie_get_minimum_link);
/**
* pcie_get_speed_cap - query for the PCI device's link speed capability
* @dev: PCI device to query
*
* Query the PCI device speed capability. Return the maximum link speed
* supported by the device.
*/
enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev)
{
u32 lnkcap2, lnkcap;
/*
* PCIe r4.0 sec 7.5.3.18 recommends using the Supported Link
* Speeds Vector in Link Capabilities 2 when supported, falling
* back to Max Link Speed in Link Capabilities otherwise.
*/
pcie_capability_read_dword(dev, PCI_EXP_LNKCAP2, &lnkcap2);
if (lnkcap2) { /* PCIe r3.0-compliant */
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_16_0GB)
return PCIE_SPEED_16_0GT;
else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
return PCIE_SPEED_8_0GT;
else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_5_0GB)
return PCIE_SPEED_5_0GT;
else if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_2_5GB)
return PCIE_SPEED_2_5GT;
return PCI_SPEED_UNKNOWN;
}
pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
if (lnkcap) {
if (lnkcap & PCI_EXP_LNKCAP_SLS_16_0GB)
return PCIE_SPEED_16_0GT;
else if (lnkcap & PCI_EXP_LNKCAP_SLS_8_0GB)
return PCIE_SPEED_8_0GT;
else if (lnkcap & PCI_EXP_LNKCAP_SLS_5_0GB)
return PCIE_SPEED_5_0GT;
else if (lnkcap & PCI_EXP_LNKCAP_SLS_2_5GB)
return PCIE_SPEED_2_5GT;
}
return PCI_SPEED_UNKNOWN;
}
/** /**
* pci_select_bars - Make BAR mask from the type of resource * pci_select_bars - Make BAR mask from the type of resource
* @dev: the PCI device for which BAR mask is made * @dev: the PCI device for which BAR mask is made
......
...@@ -253,6 +253,16 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx); ...@@ -253,6 +253,16 @@ bool pci_bus_clip_resource(struct pci_dev *dev, int idx);
void pci_reassigndev_resource_alignment(struct pci_dev *dev); void pci_reassigndev_resource_alignment(struct pci_dev *dev);
void pci_disable_bridge_window(struct pci_dev *dev); void pci_disable_bridge_window(struct pci_dev *dev);
/* PCIe link information */
#define PCIE_SPEED2STR(speed) \
((speed) == PCIE_SPEED_16_0GT ? "16 GT/s" : \
(speed) == PCIE_SPEED_8_0GT ? "8 GT/s" : \
(speed) == PCIE_SPEED_5_0GT ? "5 GT/s" : \
(speed) == PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
"Unknown speed")
enum pci_bus_speed pcie_get_speed_cap(struct pci_dev *dev);
/* Single Root I/O Virtualization */ /* Single Root I/O Virtualization */
struct pci_sriov { struct pci_sriov {
int pos; /* Capability position */ int pos; /* Capability position */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment