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