@@ -177,14 +177,14 @@ static ssize_t max_link_width_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
- u32 linkcap;
+ enum pcie_link_width width;
int err;
- err = pcie_capability_read_dword(pci_dev, PCI_EXP_LNKCAP, &linkcap);
+ err = pcie_get_width_cap(pci_dev, &width);
if (err)
return -EINVAL;
- return sprintf(buf, "%u\n", (linkcap & PCI_EXP_LNKCAP_MLW) >> 4);
+ return sprintf(buf, "%u\n", width);
}
static DEVICE_ATTR_RO(max_link_width);
@@ -5206,6 +5206,29 @@ int pcie_get_speed_cap(struct pci_dev *dev, enum pci_bus_speed *speed)
EXPORT_SYMBOL(pcie_get_speed_cap);
/**
+ * pcie_get_width_cap - queries for the PCI device's link width capability.
+ * @dev: PCI device to query
+ * @width: storage for link width
+ *
+ * This function queries the PCI device width capability.
+ */
+int pcie_get_width_cap(struct pci_dev *dev, enum pcie_link_width *width)
+{
+ u32 lnkcap;
+ int err;
+
+ *width = PCIE_LNK_WIDTH_UNKNOWN;
+
+ err = pcie_capability_read_dword(dev, PCI_EXP_LNKCAP, &lnkcap);
+ if (!err && lnkcap)
+ /* Shift start of width mask by 4 to get actual speed cap */
+ *width = (lnkcap & PCI_EXP_LNKCAP_MLW) >> 4;
+
+ return err;
+}
+EXPORT_SYMBOL(pcie_get_width_cap);
+
+/**
* 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
@@ -1084,6 +1084,7 @@ static inline int pci_is_managed(struct pci_dev *pdev)
int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
enum pcie_link_width *width);
int pcie_get_speed_cap(struct pci_dev *dev, enum pci_bus_speed *speed);
+int pcie_get_width_cap(struct pci_dev *dev, enum pcie_link_width *width);
int pcie_flr(struct pci_dev *dev);
int __pci_reset_function_locked(struct pci_dev *dev);
int pci_reset_function(struct pci_dev *dev);