[PATCH next V4 3/8] PCI: Add device link bandwidth capabilities calculation

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Added a function for calculating a PCI device's total link bandwidth
capabilities. This function queries for the device link speed and
width, multiplies them and applies encoding overhead for the different
PCIe generations.

Signed-off-by: Tal Gilboa <talgi@xxxxxxxxxxxx>
Reviewed-by: Tariq Toukan <tariqt@xxxxxxxxxxxx>
---
 drivers/pci/pci.c   | 22 ++++++++++++++++++++++
 include/linux/pci.h | 12 ++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 90a6cf2..553d8f3 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -5212,6 +5212,28 @@ int pcie_get_width_cap(struct pci_dev *dev, enum pcie_link_width *width)
 EXPORT_SYMBOL(pcie_get_width_cap);
 
 /**
+ * pcie_bandwidth_capable - Calculates a PCI device's link bandwidth capability
+ * @dev: PCI device
+ * @speed: storage for link speed
+ * @width: storage for link width
+ *
+ * This function caculates a PCI device's link bandwidth by querying for its
+ * link speed and width, multiplying them, and applying encoding overhead.
+ */
+int pcie_bandwidth_capable(struct pci_dev *dev, enum pci_bus_speed *speed,
+			   enum pcie_link_width *width)
+{
+	pcie_get_speed_cap(dev, speed);
+	pcie_get_width_cap(dev, width);
+
+	if (*speed == PCI_SPEED_UNKNOWN || *width == PCIE_LNK_WIDTH_UNKNOWN)
+		return 0;
+
+	return (*width) * PCIE_SPEED2MBS_ENC(*speed);
+}
+EXPORT_SYMBOL(pcie_bandwidth_capable);
+
+/**
  * 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
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 1e3d05f..9f57c45 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -265,6 +265,16 @@ enum pci_bus_speed {
 	 (speed) == PCIE_SPEED_2_5GT ? "2.5 GT/s" : \
 	 "Unknown speed")
 
+/**
+ * PCIe speed to Mb/s with encoding overhead:
+ * 20% for gen2, ~1.5% for gen3
+ */
+#define PCIE_SPEED2MBS_ENC(speed) \
+	((speed) == PCIE_SPEED_8_0GT ? 7877 : \
+	 (speed) == PCIE_SPEED_5_0GT ? 4000 : \
+	 (speed) == PCIE_SPEED_2_5GT ? 2000 : \
+	 0)
+
 struct pci_cap_saved_data {
 	u16		cap_nr;
 	bool		cap_extended;
@@ -1090,6 +1100,8 @@ 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_bandwidth_capable(struct pci_dev *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);
-- 
1.8.3.1




[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux