Blame SOURCES/dpdk-17.11-i40e-fix-link-status-timeout.patch

c7ffa4
From: Fan Zhang <roy.fan.zhang@intel.com>
c7ffa4
Subject: [dpdk-dev,v2] drivers/i40e: fix link update no wait
c7ffa4
Date: Thu,  8 Mar 2018 12:17:52 +0000
c7ffa4
c7ffa4
Fixes: 263333bbb7a9 ("i40e: fix link status timeout")
c7ffa4
Cc: cunming.liang@intel.com
c7ffa4
Cc: stable@dpdk.org
c7ffa4
c7ffa4
In i40e_dev_link_update() the driver obtains the link status
c7ffa4
info via admin queue command despite of "no_wait" flag. This
c7ffa4
requires relatively long time and may be a problem to some
c7ffa4
application such as ovs-dpdk
c7ffa4
(https://bugzilla.redhat.com/show_bug.cgi?id=1551761).
c7ffa4
c7ffa4
This patch aims to fix the problem by using a different
c7ffa4
approach of obtaining link status for i40e NIC without waiting.
c7ffa4
Instead of getting the link status via admin queue command,
c7ffa4
this patch reads the link status registers to accelerate the
c7ffa4
procedure.
c7ffa4
c7ffa4
Signed-off-by: Fan Zhang <roy.fan.zhang@intel.com>
c7ffa4
Signed-off-by: Andrey Chilikin <andrey.chilikin@intel.com>
c7ffa4
Reviewed-by: Eelco Chaudron <echaudro@redhat.com>
c7ffa4
Tested-by: Eelco Chaudron <echaudro@redhat.com>
c7ffa4
---
c7ffa4
v2:
c7ffa4
- add ccs after fixline
c7ffa4
c7ffa4
 drivers/net/i40e/i40e_ethdev.c | 128 ++++++++++++++++++++++++++++++-----------
c7ffa4
 1 file changed, 95 insertions(+), 33 deletions(-)
c7ffa4
c7ffa4
diff --git openvswitch-2.7.4/drivers/net/i40e/i40e_ethdev.c openvswitch-2.7.4/drivers/net/i40e/i40e_ethdev.c
c7ffa4
index 508b4171c..968249ed1 100644
c7ffa4
--- openvswitch-2.7.4/drivers/net/i40e/i40e_ethdev.c
c7ffa4
+++ openvswitch-2.7.4/drivers/net/i40e/i40e_ethdev.c
c7ffa4
@@ -2437,77 +2437,140 @@ i40e_dev_set_link_down(struct rte_eth_dev *dev)
c7ffa4
 	return i40e_phy_conf_link(hw, abilities, speed, false);
c7ffa4
 }
c7ffa4
 
c7ffa4
-int
c7ffa4
-i40e_dev_link_update(struct rte_eth_dev *dev,
c7ffa4
-		     int wait_to_complete)
c7ffa4
+#define __rte_always_inline inline __attribute__((always_inline))
c7ffa4
+static __rte_always_inline void
c7ffa4
+update_link_no_wait(struct i40e_hw *hw, struct rte_eth_link *link)
c7ffa4
+{
c7ffa4
+/* Link status registers and values*/
c7ffa4
+#define I40E_PRTMAC_LINKSTA		0x001E2420
c7ffa4
+#define I40E_REG_LINK_UP		0x40000080
c7ffa4
+#define I40E_PRTMAC_MACC		0x001E24E0
c7ffa4
+#define I40E_REG_MACC_25GB		0x00020000
c7ffa4
+#define I40E_REG_SPEED_MASK		0x38000000
c7ffa4
+#define I40E_REG_SPEED_100MB		0x00000000
c7ffa4
+#define I40E_REG_SPEED_1GB		0x08000000
c7ffa4
+#define I40E_REG_SPEED_10GB		0x10000000
c7ffa4
+#define I40E_REG_SPEED_20GB		0x20000000
c7ffa4
+#define I40E_REG_SPEED_25_40GB		0x18000000
c7ffa4
+	uint32_t link_speed;
c7ffa4
+	uint32_t reg_val;
c7ffa4
+
c7ffa4
+	reg_val = I40E_READ_REG(hw, I40E_PRTMAC_LINKSTA);
c7ffa4
+	link_speed = reg_val & I40E_REG_SPEED_MASK;
c7ffa4
+	reg_val &= I40E_REG_LINK_UP;
c7ffa4
+	link->link_status = (reg_val == I40E_REG_LINK_UP) ? 1 : 0;
c7ffa4
+
c7ffa4
+	if (unlikely(link->link_status != 0))
c7ffa4
+		return;
c7ffa4
+
c7ffa4
+	/* Parse the link status */
c7ffa4
+	switch (link_speed) {
c7ffa4
+	case I40E_REG_SPEED_100MB:
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_100M;
c7ffa4
+		break;
c7ffa4
+	case I40E_REG_SPEED_1GB:
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_1G;
c7ffa4
+		break;
c7ffa4
+	case I40E_REG_SPEED_10GB:
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_10G;
c7ffa4
+		break;
c7ffa4
+	case I40E_REG_SPEED_20GB:
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_20G;
c7ffa4
+		break;
c7ffa4
+	case I40E_REG_SPEED_25_40GB:
c7ffa4
+		reg_val = I40E_READ_REG(hw, I40E_PRTMAC_MACC);
c7ffa4
+
c7ffa4
+		if (reg_val & I40E_REG_MACC_25GB)
c7ffa4
+			link->link_speed = ETH_SPEED_NUM_25G;
c7ffa4
+		else
c7ffa4
+			link->link_speed = ETH_SPEED_NUM_40G;
c7ffa4
+
c7ffa4
+		break;
c7ffa4
+	default:
c7ffa4
+		PMD_DRV_LOG(ERR, "Unknown link speed info %u", link_speed);
c7ffa4
+		break;
c7ffa4
+	}
c7ffa4
+}
c7ffa4
+
c7ffa4
+static __rte_always_inline void
c7ffa4
+update_link_wait(struct i40e_hw *hw, struct rte_eth_link *link,
c7ffa4
+	bool enable_lse)
c7ffa4
 {
c7ffa4
-#define CHECK_INTERVAL 100  /* 100ms */
c7ffa4
-#define MAX_REPEAT_TIME 10  /* 1s (10 * 100ms) in total */
c7ffa4
-	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
c7ffa4
+#define CHECK_INTERVAL             100  /* 100ms */
c7ffa4
+#define MAX_REPEAT_TIME            10  /* 1s (10 * 100ms) in total */
c7ffa4
+	uint32_t rep_cnt = MAX_REPEAT_TIME;
c7ffa4
 	struct i40e_link_status link_status;
c7ffa4
-	struct rte_eth_link link, old;
c7ffa4
 	int status;
c7ffa4
-	unsigned rep_cnt = MAX_REPEAT_TIME;
c7ffa4
-	bool enable_lse = dev->data->dev_conf.intr_conf.lsc ? true : false;
c7ffa4
 
c7ffa4
-	memset(&link, 0, sizeof(link));
c7ffa4
-	memset(&old, 0, sizeof(old));
c7ffa4
 	memset(&link_status, 0, sizeof(link_status));
c7ffa4
-	rte_i40e_dev_atomic_read_link_status(dev, &old;;
c7ffa4
 
c7ffa4
 	do {
c7ffa4
 		/* Get link status information from hardware */
c7ffa4
 		status = i40e_aq_get_link_info(hw, enable_lse,
c7ffa4
 						&link_status, NULL);
c7ffa4
-		if (status != I40E_SUCCESS) {
c7ffa4
-			link.link_speed = ETH_SPEED_NUM_100M;
c7ffa4
-			link.link_duplex = ETH_LINK_FULL_DUPLEX;
c7ffa4
+		if (unlikely(status != I40E_SUCCESS)) {
c7ffa4
+			link->link_speed = ETH_SPEED_NUM_100M;
c7ffa4
+			link->link_duplex = ETH_LINK_FULL_DUPLEX;
c7ffa4
 			PMD_DRV_LOG(ERR, "Failed to get link info");
c7ffa4
-			goto out;
c7ffa4
+			return;
c7ffa4
 		}
c7ffa4
 
c7ffa4
-		link.link_status = link_status.link_info & I40E_AQ_LINK_UP;
c7ffa4
-		if (!wait_to_complete || link.link_status)
c7ffa4
-			break;
c7ffa4
+		link->link_status = link_status.link_info & I40E_AQ_LINK_UP;
c7ffa4
+		if (unlikely(link->link_status != 0))
c7ffa4
+			return;
c7ffa4
 
c7ffa4
 		rte_delay_ms(CHECK_INTERVAL);
c7ffa4
 	} while (--rep_cnt);
c7ffa4
 
c7ffa4
-	if (!link.link_status)
c7ffa4
-		goto out;
c7ffa4
-
c7ffa4
-	/* i40e uses full duplex only */
c7ffa4
-	link.link_duplex = ETH_LINK_FULL_DUPLEX;
c7ffa4
-
c7ffa4
 	/* Parse the link status */
c7ffa4
 	switch (link_status.link_speed) {
c7ffa4
 	case I40E_LINK_SPEED_100MB:
c7ffa4
-		link.link_speed = ETH_SPEED_NUM_100M;
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_100M;
c7ffa4
 		break;
c7ffa4
 	case I40E_LINK_SPEED_1GB:
c7ffa4
-		link.link_speed = ETH_SPEED_NUM_1G;
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_1G;
c7ffa4
 		break;
c7ffa4
 	case I40E_LINK_SPEED_10GB:
c7ffa4
-		link.link_speed = ETH_SPEED_NUM_10G;
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_10G;
c7ffa4
 		break;
c7ffa4
 	case I40E_LINK_SPEED_20GB:
c7ffa4
-		link.link_speed = ETH_SPEED_NUM_20G;
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_20G;
c7ffa4
 		break;
c7ffa4
 	case I40E_LINK_SPEED_25GB:
c7ffa4
-		link.link_speed = ETH_SPEED_NUM_25G;
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_25G;
c7ffa4
 		break;
c7ffa4
 	case I40E_LINK_SPEED_40GB:
c7ffa4
-		link.link_speed = ETH_SPEED_NUM_40G;
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_40G;
c7ffa4
 		break;
c7ffa4
 	default:
c7ffa4
-		link.link_speed = ETH_SPEED_NUM_100M;
c7ffa4
+		link->link_speed = ETH_SPEED_NUM_100M;
c7ffa4
 		break;
c7ffa4
 	}
c7ffa4
+}
c7ffa4
+
c7ffa4
+int
c7ffa4
+i40e_dev_link_update(struct rte_eth_dev *dev,
c7ffa4
+		     int wait_to_complete)
c7ffa4
+{
c7ffa4
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
c7ffa4
+	struct rte_eth_link link, old;
c7ffa4
+	bool enable_lse = dev->data->dev_conf.intr_conf.lsc ? true : false;
c7ffa4
 
c7ffa4
+	memset(&link, 0, sizeof(link));
c7ffa4
+	memset(&old, 0, sizeof(old));
c7ffa4
+
c7ffa4
+	rte_i40e_dev_atomic_read_link_status(dev, &old;;
c7ffa4
+
c7ffa4
+	/* i40e uses full duplex only */
c7ffa4
+	link.link_duplex = ETH_LINK_FULL_DUPLEX;
c7ffa4
 	link.link_autoneg = !(dev->data->dev_conf.link_speeds &
c7ffa4
 			ETH_LINK_SPEED_FIXED);
c7ffa4
 
c7ffa4
-out:
c7ffa4
+	if (!wait_to_complete)
c7ffa4
+		update_link_no_wait(hw, &link);
c7ffa4
+	else
c7ffa4
+		update_link_wait(hw, &link, enable_lse);
c7ffa4
+
c7ffa4
 	rte_i40e_dev_atomic_write_link_status(dev, &link);
c7ffa4
 	if (link.link_status == old.link_status)
c7ffa4
 		return -1;