PCI: Add pcie_bandwidth_available() to compute bandwidth available to device
Add pcie_bandwidth_available() to compute the bandwidth available to a device. This may be limited by the device itself or by a slower upstream link leading to the device. The available bandwidth at each link along the path is computed as: link_width * link_speed * (1 - encoding_overhead) 2.5 and 5.0 GT/s links use 8b/10b encoding, which reduces the raw bandwidth available by 20%; 8.0 GT/s and faster links use 128b/130b encoding, which reduces it by about 1.5%. The result is in Mb/s, i.e., megabits/second, of raw bandwidth. Also return the device with the slowest link and the speed and width of that link. Signed-off-by: Tal Gilboa <talgi@mellanox.com> [bhelgaas: changelog, leave pcie_get_minimum_link() alone for now, return bw directly, use pci_upstream_bridge(), check "next_bw <= bw" to find uppermost limiting device, return speed/width of the limiting device] Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
Родитель
b852f63aa6
Коммит
6db79a88c6
|
@ -5146,6 +5146,64 @@ int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
|
|||
}
|
||||
EXPORT_SYMBOL(pcie_get_minimum_link);
|
||||
|
||||
/**
|
||||
* pcie_bandwidth_available - determine minimum link settings of a PCIe
|
||||
* device and its bandwidth limitation
|
||||
* @dev: PCI device to query
|
||||
* @limiting_dev: storage for device causing the bandwidth limitation
|
||||
* @speed: storage for speed of limiting device
|
||||
* @width: storage for width of limiting device
|
||||
*
|
||||
* Walk up the PCI device chain and find the point where the minimum
|
||||
* bandwidth is available. Return the bandwidth available there and (if
|
||||
* limiting_dev, speed, and width pointers are supplied) information about
|
||||
* that point. The bandwidth returned is in Mb/s, i.e., megabits/second of
|
||||
* raw bandwidth.
|
||||
*/
|
||||
u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
|
||||
enum pci_bus_speed *speed,
|
||||
enum pcie_link_width *width)
|
||||
{
|
||||
u16 lnksta;
|
||||
enum pci_bus_speed next_speed;
|
||||
enum pcie_link_width next_width;
|
||||
u32 bw, next_bw;
|
||||
|
||||
if (speed)
|
||||
*speed = PCI_SPEED_UNKNOWN;
|
||||
if (width)
|
||||
*width = PCIE_LNK_WIDTH_UNKNOWN;
|
||||
|
||||
bw = 0;
|
||||
|
||||
while (dev) {
|
||||
pcie_capability_read_word(dev, PCI_EXP_LNKSTA, &lnksta);
|
||||
|
||||
next_speed = pcie_link_speed[lnksta & PCI_EXP_LNKSTA_CLS];
|
||||
next_width = (lnksta & PCI_EXP_LNKSTA_NLW) >>
|
||||
PCI_EXP_LNKSTA_NLW_SHIFT;
|
||||
|
||||
next_bw = next_width * PCIE_SPEED2MBS_ENC(next_speed);
|
||||
|
||||
/* Check if current device limits the total bandwidth */
|
||||
if (!bw || next_bw <= bw) {
|
||||
bw = next_bw;
|
||||
|
||||
if (limiting_dev)
|
||||
*limiting_dev = dev;
|
||||
if (speed)
|
||||
*speed = next_speed;
|
||||
if (width)
|
||||
*width = next_width;
|
||||
}
|
||||
|
||||
dev = pci_upstream_bridge(dev);
|
||||
}
|
||||
|
||||
return bw;
|
||||
}
|
||||
EXPORT_SYMBOL(pcie_bandwidth_available);
|
||||
|
||||
/**
|
||||
* pcie_get_speed_cap - query for the PCI device's link speed capability
|
||||
* @dev: PCI device to query
|
||||
|
|
|
@ -1083,6 +1083,9 @@ int pcie_get_mps(struct pci_dev *dev);
|
|||
int pcie_set_mps(struct pci_dev *dev, int mps);
|
||||
int pcie_get_minimum_link(struct pci_dev *dev, enum pci_bus_speed *speed,
|
||||
enum pcie_link_width *width);
|
||||
u32 pcie_bandwidth_available(struct pci_dev *dev, struct pci_dev **limiting_dev,
|
||||
enum pci_bus_speed *speed,
|
||||
enum pcie_link_width *width);
|
||||
void pcie_flr(struct pci_dev *dev);
|
||||
int __pci_reset_function_locked(struct pci_dev *dev);
|
||||
int pci_reset_function(struct pci_dev *dev);
|
||||
|
|
Загрузка…
Ссылка в новой задаче