|
@@ -3578,6 +3578,49 @@ int pcie_set_mps(struct pci_dev *dev, int mps)
|
|
|
PCI_EXP_DEVCTL_PAYLOAD, v);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * 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
|