aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorJacob Keller <jacob.e.keller@intel.com>2013-07-31 02:53:31 -0400
committerJeff Kirsher <jeffrey.t.kirsher@intel.com>2013-07-31 03:50:04 -0400
commite027d1aec4bb49030646d2c186a721f94372d7f2 (patch)
treebb6e4db798b934e3bd16400a1337b241d5ee8f11 /drivers/net
parent81377c8d3563e7aec5c8baaaacacb48034f430a0 (diff)
ixgbe: call pcie_get_mimimum_link to check if device has enough bandwidth
This patch uses the new pcie_get_minimum_link function to perform a check to ensure that the adapter is hooked into a slot which is capable of providing the necessary bandwidth. This check supersedes the original method which only checked the current pci device. The new method is capable of determining the minimum speed and link of an entire PCI chain. -v2- * update the error message to include encoding loss CC: Bjorn Helgaas <bhelgaas@google.com> Signed-off-by: Jacob Keller <jacob.e.keller@intel.com> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c136
1 files changed, 129 insertions, 7 deletions
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 2d0e8465a68b..69c6a495aaee 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -195,6 +195,85 @@ static s32 ixgbe_get_parent_bus_info(struct ixgbe_adapter *adapter)
195 return 0; 195 return 0;
196} 196}
197 197
198/**
199 * ixgbe_check_from_parent - Determine whether PCIe info should come from parent
200 * @hw: hw specific details
201 *
202 * This function is used by probe to determine whether a device's PCI-Express
203 * bandwidth details should be gathered from the parent bus instead of from the
204 * device. Used to ensure that various locations all have the correct device ID
205 * checks.
206 */
207static inline bool ixgbe_pcie_from_parent(struct ixgbe_hw *hw)
208{
209 switch (hw->device_id) {
210 case IXGBE_DEV_ID_82599_SFP_SF_QP:
211 return true;
212 default:
213 return false;
214 }
215}
216
217static void ixgbe_check_minimum_link(struct ixgbe_adapter *adapter,
218 int expected_gts)
219{
220 int max_gts = 0;
221 enum pci_bus_speed speed = PCI_SPEED_UNKNOWN;
222 enum pcie_link_width width = PCIE_LNK_WIDTH_UNKNOWN;
223 struct pci_dev *pdev;
224
225 /* determine whether to use the the parent device
226 */
227 if (ixgbe_pcie_from_parent(&adapter->hw))
228 pdev = adapter->pdev->bus->parent->self;
229 else
230 pdev = adapter->pdev;
231
232 if (pcie_get_minimum_link(pdev, &speed, &width) ||
233 speed == PCI_SPEED_UNKNOWN || width == PCIE_LNK_WIDTH_UNKNOWN) {
234 e_dev_warn("Unable to determine PCI Express bandwidth.\n");
235 return;
236 }
237
238 switch (speed) {
239 case PCIE_SPEED_2_5GT:
240 /* 8b/10b encoding reduces max throughput by 20% */
241 max_gts = 2 * width;
242 break;
243 case PCIE_SPEED_5_0GT:
244 /* 8b/10b encoding reduces max throughput by 20% */
245 max_gts = 4 * width;
246 break;
247 case PCIE_SPEED_8_0GT:
248 /* 128b/130b encoding only reduces throughput by 1% */
249 max_gts = 8 * width;
250 break;
251 default:
252 e_dev_warn("Unable to determine PCI Express bandwidth.\n");
253 return;
254 }
255
256 e_dev_info("PCI Express bandwidth of %dGT/s available\n",
257 max_gts);
258 e_dev_info("(Speed:%s, Width: x%d, Encoding Loss:%s)\n",
259 (speed == PCIE_SPEED_8_0GT ? "8.0GT/s" :
260 speed == PCIE_SPEED_5_0GT ? "5.0GT/s" :
261 speed == PCIE_SPEED_2_5GT ? "2.5GT/s" :
262 "Unknown"),
263 width,
264 (speed == PCIE_SPEED_2_5GT ? "20%" :
265 speed == PCIE_SPEED_5_0GT ? "20%" :
266 speed == PCIE_SPEED_8_0GT ? "N/a" :
267 "Unknown"));
268
269 if (max_gts < expected_gts) {
270 e_dev_warn("This is not sufficient for optimal performance of this card.\n");
271 e_dev_warn("For optimal performance, at least %dGT/s of bandwidth is required.\n",
272 expected_gts);
273 e_dev_warn("A slot with more lanes and/or higher speed is suggested.\n");
274 }
275}
276
198static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter) 277static void ixgbe_service_event_schedule(struct ixgbe_adapter *adapter)
199{ 278{
200 if (!test_bit(__IXGBE_DOWN, &adapter->state) && 279 if (!test_bit(__IXGBE_DOWN, &adapter->state) &&
@@ -7249,6 +7328,41 @@ static const struct net_device_ops ixgbe_netdev_ops = {
7249}; 7328};
7250 7329
7251/** 7330/**
7331 * ixgbe_enumerate_functions - Get the number of ports this device has
7332 * @adapter: adapter structure
7333 *
7334 * This function enumerates the phsyical functions co-located on a single slot,
7335 * in order to determine how many ports a device has. This is most useful in
7336 * determining the required GT/s of PCIe bandwidth necessary for optimal
7337 * performance.
7338 **/
7339static inline int ixgbe_enumerate_functions(struct ixgbe_adapter *adapter)
7340{
7341 struct ixgbe_hw *hw = &adapter->hw;
7342 struct list_head *entry;
7343 int physfns = 0;
7344
7345 /* Some cards can not use the generic count PCIe functions method, and
7346 * so must be hardcoded to the correct value.
7347 */
7348 switch (hw->device_id) {
7349 case IXGBE_DEV_ID_82599_SFP_SF_QP:
7350 physfns = 4;
7351 break;
7352 default:
7353 list_for_each(entry, &adapter->pdev->bus_list) {
7354 struct pci_dev *pdev =
7355 list_entry(entry, struct pci_dev, bus_list);
7356 /* don't count virtual functions */
7357 if (!pdev->is_virtfn)
7358 physfns++;
7359 }
7360 }
7361
7362 return physfns;
7363}
7364
7365/**
7252 * ixgbe_wol_supported - Check whether device supports WoL 7366 * ixgbe_wol_supported - Check whether device supports WoL
7253 * @hw: hw specific details 7367 * @hw: hw specific details
7254 * @device_id: the device ID 7368 * @device_id: the device ID
@@ -7330,7 +7444,7 @@ static int ixgbe_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
7330 struct ixgbe_hw *hw; 7444 struct ixgbe_hw *hw;
7331 const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data]; 7445 const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
7332 static int cards_found; 7446 static int cards_found;
7333 int i, err, pci_using_dac; 7447 int i, err, pci_using_dac, expected_gts;
7334 unsigned int indices = MAX_TX_QUEUES; 7448 unsigned int indices = MAX_TX_QUEUES;
7335 u8 part_str[IXGBE_PBANUM_LENGTH]; 7449 u8 part_str[IXGBE_PBANUM_LENGTH];
7336#ifdef IXGBE_FCOE 7450#ifdef IXGBE_FCOE
@@ -7619,7 +7733,7 @@ skip_sriov:
7619 7733
7620 /* pick up the PCI bus settings for reporting later */ 7734 /* pick up the PCI bus settings for reporting later */
7621 hw->mac.ops.get_bus_info(hw); 7735 hw->mac.ops.get_bus_info(hw);
7622 if (hw->device_id == IXGBE_DEV_ID_82599_SFP_SF_QP) 7736 if (ixgbe_pcie_from_parent(hw))
7623 ixgbe_get_parent_bus_info(adapter); 7737 ixgbe_get_parent_bus_info(adapter);
7624 7738
7625 /* print bus type/speed/width info */ 7739 /* print bus type/speed/width info */
@@ -7645,12 +7759,20 @@ skip_sriov:
7645 e_dev_info("MAC: %d, PHY: %d, PBA No: %s\n", 7759 e_dev_info("MAC: %d, PHY: %d, PBA No: %s\n",
7646 hw->mac.type, hw->phy.type, part_str); 7760 hw->mac.type, hw->phy.type, part_str);
7647 7761
7648 if (hw->bus.width <= ixgbe_bus_width_pcie_x4) { 7762 /* calculate the expected PCIe bandwidth required for optimal
7649 e_dev_warn("PCI-Express bandwidth available for this card is " 7763 * performance. Note that some older parts will never have enough
7650 "not sufficient for optimal performance.\n"); 7764 * bandwidth due to being older generation PCIe parts. We clamp these
7651 e_dev_warn("For optimal performance a x8 PCI-Express slot " 7765 * parts to ensure no warning is displayed if it can't be fixed.
7652 "is required.\n"); 7766 */
7767 switch (hw->mac.type) {
7768 case ixgbe_mac_82598EB:
7769 expected_gts = min(ixgbe_enumerate_functions(adapter) * 10, 16);
7770 break;
7771 default:
7772 expected_gts = ixgbe_enumerate_functions(adapter) * 10;
7773 break;
7653 } 7774 }
7775 ixgbe_check_minimum_link(adapter, expected_gts);
7654 7776
7655 /* reset the hardware with the new settings */ 7777 /* reset the hardware with the new settings */
7656 err = hw->mac.ops.start_hw(hw); 7778 err = hw->mac.ops.start_hw(hw);