[dpdk-dev] [PATCH] i40e: support autoneg or force link speed

Cunming Liang cunming.liang at intel.com
Thu Jul 31 22:44:07 CEST 2014


- i40e force link up/down
- i40e autoneg/force speed

Signed-off-by: Cunming Liang <cunming.liang at intel.com>
Acked-by: Helin Zhang <helin.zhang at intel.com>
Acked-by: Chen Jing D(Mark) <jing.d.chen at intel.com>
Tested-by: Xu HuilongX <huilongx.xu at intel.com>
---
 app/test-pmd/cmdline.c            |  17 +++--
 lib/librte_pmd_i40e/i40e_ethdev.c | 139 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+), 6 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 345be11..0abc233 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -527,7 +527,8 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"port close (port_id|all)\n"
 			"    Close all ports or port_id.\n\n"
 
-			"port config (port_id|all) speed (10|100|1000|10000|auto)"
+			"port config (port_id|all)"
+			" speed (10|100|1000|10000|40000|auto)"
 			" duplex (half|full|auto)\n"
 			"    Set speed and duplex for all ports or port_id\n\n"
 
@@ -801,7 +802,9 @@ cmd_config_speed_all_parsed(void *parsed_result,
 	else if (!strcmp(res->value1, "1000"))
 		link_speed = ETH_LINK_SPEED_1000;
 	else if (!strcmp(res->value1, "10000"))
-		link_speed = ETH_LINK_SPEED_10000;
+		link_speed = ETH_LINK_SPEED_10G;
+	else if (!strcmp(res->value1, "40000"))
+		link_speed = ETH_LINK_SPEED_40G;
 	else if (!strcmp(res->value1, "auto"))
 		link_speed = ETH_LINK_SPEED_AUTONEG;
 	else {
@@ -839,7 +842,7 @@ cmdline_parse_token_string_t cmd_config_speed_all_item1 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item1, "speed");
 cmdline_parse_token_string_t cmd_config_speed_all_value1 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, value1,
-						"10#100#1000#10000#auto");
+						"10#100#1000#10000#40000#auto");
 cmdline_parse_token_string_t cmd_config_speed_all_item2 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_all, item2, "duplex");
 cmdline_parse_token_string_t cmd_config_speed_all_value2 =
@@ -849,7 +852,7 @@ cmdline_parse_token_string_t cmd_config_speed_all_value2 =
 cmdline_parse_inst_t cmd_config_speed_all = {
 	.f = cmd_config_speed_all_parsed,
 	.data = NULL,
-	.help_str = "port config all speed 10|100|1000|10000|auto duplex "
+	.help_str = "port config all speed 10|100|1000|10000|40000|auto duplex "
 							"half|full|auto",
 	.tokens = {
 		(void *)&cmd_config_speed_all_port,
@@ -901,6 +904,8 @@ cmd_config_speed_specific_parsed(void *parsed_result,
 		link_speed = ETH_LINK_SPEED_1000;
 	else if (!strcmp(res->value1, "10000"))
 		link_speed = ETH_LINK_SPEED_10000;
+	else if (!strcmp(res->value1, "40000"))
+		link_speed = ETH_LINK_SPEED_40G;
 	else if (!strcmp(res->value1, "auto"))
 		link_speed = ETH_LINK_SPEED_AUTONEG;
 	else {
@@ -939,7 +944,7 @@ cmdline_parse_token_string_t cmd_config_speed_specific_item1 =
 								"speed");
 cmdline_parse_token_string_t cmd_config_speed_specific_value1 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, value1,
-						"10#100#1000#10000#auto");
+						"10#100#1000#10000#40000#auto");
 cmdline_parse_token_string_t cmd_config_speed_specific_item2 =
 	TOKEN_STRING_INITIALIZER(struct cmd_config_speed_specific, item2,
 								"duplex");
@@ -950,7 +955,7 @@ cmdline_parse_token_string_t cmd_config_speed_specific_value2 =
 cmdline_parse_inst_t cmd_config_speed_specific = {
 	.f = cmd_config_speed_specific_parsed,
 	.data = NULL,
-	.help_str = "port config X speed 10|100|1000|10000|auto duplex "
+	.help_str = "port config X speed 10|100|1000|10000|40000|auto duplex "
 							"half|full|auto",
 	.tokens = {
 		(void *)&cmd_config_speed_specific_port,
diff --git a/lib/librte_pmd_i40e/i40e_ethdev.c b/lib/librte_pmd_i40e/i40e_ethdev.c
index 9ed31b5..fe4c78e 100644
--- a/lib/librte_pmd_i40e/i40e_ethdev.c
+++ b/lib/librte_pmd_i40e/i40e_ethdev.c
@@ -128,6 +128,8 @@ static void i40e_dev_promiscuous_enable(struct rte_eth_dev *dev);
 static void i40e_dev_promiscuous_disable(struct rte_eth_dev *dev);
 static void i40e_dev_allmulticast_enable(struct rte_eth_dev *dev);
 static void i40e_dev_allmulticast_disable(struct rte_eth_dev *dev);
+static int i40e_dev_set_link_up(struct rte_eth_dev *dev);
+static int i40e_dev_set_link_down(struct rte_eth_dev *dev);
 static void i40e_dev_stats_get(struct rte_eth_dev *dev,
 			       struct rte_eth_stats *stats);
 static void i40e_dev_stats_reset(struct rte_eth_dev *dev);
@@ -222,6 +224,8 @@ static struct eth_dev_ops i40e_eth_dev_ops = {
 	.promiscuous_disable          = i40e_dev_promiscuous_disable,
 	.allmulticast_enable          = i40e_dev_allmulticast_enable,
 	.allmulticast_disable         = i40e_dev_allmulticast_disable,
+	.dev_set_link_up              = i40e_dev_set_link_up,
+	.dev_set_link_down            = i40e_dev_set_link_down,
 	.link_update                  = i40e_dev_link_update,
 	.stats_get                    = i40e_dev_stats_get,
 	.stats_reset                  = i40e_dev_stats_reset,
@@ -649,6 +653,100 @@ i40e_vsi_disable_queues_intr(struct i40e_vsi *vsi)
 	I40E_WRITE_REG(hw, I40E_PFINT_DYN_CTLN(vsi->msix_intr - 1), 0);
 }
 
+static inline uint8_t
+i40e_parse_link_speed(uint16_t eth_link_speed)
+{
+	uint8_t link_speed = I40E_LINK_SPEED_UNKNOWN;
+
+	switch (eth_link_speed) {
+	case ETH_LINK_SPEED_40G:
+		link_speed = I40E_LINK_SPEED_40GB;
+		break;
+	case ETH_LINK_SPEED_20G:
+		link_speed = I40E_LINK_SPEED_20GB;
+		break;
+	case ETH_LINK_SPEED_10G:
+		link_speed = I40E_LINK_SPEED_10GB;
+		break;
+	case ETH_LINK_SPEED_1000:
+		link_speed = I40E_LINK_SPEED_1GB;
+		break;
+	case ETH_LINK_SPEED_100:
+		link_speed = I40E_LINK_SPEED_100MB;
+		break;
+	}
+
+	return link_speed;
+}
+
+static int
+i40e_phy_conf_link(struct i40e_hw *hw, uint8_t abilities, uint8_t force_speed)
+{
+	enum i40e_status_code status;
+	struct i40e_aq_get_phy_abilities_resp phy_ab;
+	struct i40e_aq_set_phy_config phy_conf = {0};
+	const uint8_t mask = I40E_AQ_PHY_FLAG_PAUSE_TX |
+			I40E_AQ_PHY_FLAG_PAUSE_RX |
+			I40E_AQ_PHY_FLAG_LOW_POWER;
+	const uint8_t advt = I40E_LINK_SPEED_40GB |
+			I40E_LINK_SPEED_10GB |
+			I40E_LINK_SPEED_1GB |
+			I40E_LINK_SPEED_100MB;
+	int ret = -ENOTSUP;
+
+	status = i40e_aq_get_phy_capabilities(hw, false, false, &phy_ab,
+					      NULL);
+	if (status)
+		return ret;
+
+	/* bits 0-2 use the values from get_phy_abilities_resp */
+	abilities &= ~mask;
+	abilities |= phy_ab.abilities & mask;
+
+	/* update ablities and speed */
+	if (abilities & I40E_AQ_PHY_AN_ENABLED)
+		phy_conf.link_speed = advt;
+	else
+		phy_conf.link_speed = force_speed;
+
+	phy_conf.abilities = abilities;
+
+	/* use get_phy_abilities_resp value for the rest */
+	phy_conf.phy_type = phy_ab.phy_type;
+	phy_conf.eee_capability = phy_ab.eee_capability;
+	phy_conf.eeer = phy_ab.eeer_val;
+	phy_conf.low_power_ctrl = phy_ab.d3_lpan;
+
+	PMD_DRV_LOG(DEBUG, "\n\tCurrent: abilities %x, link_speed %x\n"
+		    "\tConfig:  abilities %x, link_speed %x",
+		    phy_ab.abilities, phy_ab.link_speed,
+		    phy_conf.abilities, phy_conf.link_speed);
+
+	status = i40e_aq_set_phy_config(hw, &phy_conf, NULL);
+	if (status)
+		return ret;
+
+	return I40E_SUCCESS;
+}
+
+static int
+i40e_apply_link_speed(struct rte_eth_dev *dev)
+{
+	uint8_t speed;
+	uint8_t abilities = 0;
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	struct rte_eth_conf *conf = &dev->data->dev_conf;
+
+	speed = i40e_parse_link_speed(conf->link_speed);
+	abilities |= I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+	if (conf->link_speed == ETH_LINK_SPEED_AUTONEG)
+		abilities |= I40E_AQ_PHY_AN_ENABLED;
+	else
+		abilities |= I40E_AQ_PHY_LINK_ENABLED;
+
+	return i40e_phy_conf_link(hw, abilities, speed);
+}
+
 static int
 i40e_dev_start(struct rte_eth_dev *dev)
 {
@@ -657,6 +755,14 @@ i40e_dev_start(struct rte_eth_dev *dev)
 	struct i40e_vsi *vsi = pf->main_vsi;
 	int ret;
 
+	if ((dev->data->dev_conf.link_duplex != ETH_LINK_AUTONEG_DUPLEX) &&
+		(dev->data->dev_conf.link_duplex != ETH_LINK_FULL_DUPLEX)) {
+		PMD_INIT_LOG(ERR, "Invalid link_duplex (%hu) for port %hhu\n",
+				dev->data->dev_conf.link_duplex,
+				dev->data->port_id);
+		return -EINVAL;
+	}
+
 	/* Initialize VSI */
 	ret = i40e_vsi_init(vsi);
 	if (ret != I40E_SUCCESS) {
@@ -682,6 +788,13 @@ i40e_dev_start(struct rte_eth_dev *dev)
 			PMD_DRV_LOG(INFO, "fail to set vsi broadcast\n");
 	}
 
+	/* Apply link configure */
+	ret = i40e_apply_link_speed(dev);
+	if (I40E_SUCCESS != ret) {
+		PMD_DRV_LOG(ERR, "Fail to apply link setting\n");
+		goto err_up;
+	}
+
 	return I40E_SUCCESS;
 
 err_up:
@@ -703,6 +816,9 @@ i40e_dev_stop(struct rte_eth_dev *dev)
 	/* Clear all queues and release memory */
 	i40e_dev_clear_queues(dev);
 
+	/* Set link down */
+	i40e_dev_set_link_down(dev);
+
 	/* un-map queues with interrupt registers */
 	i40e_vsi_disable_queues_intr(vsi);
 	i40e_vsi_queues_unbind_intr(vsi);
@@ -798,6 +914,29 @@ i40e_dev_allmulticast_disable(struct rte_eth_dev *dev)
 		PMD_DRV_LOG(ERR, "Failed to disable multicast promiscuous\n");
 }
 
+/*
+ * Set device link up.
+ */
+static int
+i40e_dev_set_link_up(struct rte_eth_dev *dev)
+{
+	/* re-apply link speed setting */
+	return i40e_apply_link_speed(dev);
+}
+
+/*
+ * Set device link down.
+ */
+static int
+i40e_dev_set_link_down(__rte_unused struct rte_eth_dev *dev)
+{
+	uint8_t speed = I40E_LINK_SPEED_UNKNOWN;
+	uint8_t abilities = I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+
+	return i40e_phy_conf_link(hw, abilities, speed);
+}
+
 int
 i40e_dev_link_update(struct rte_eth_dev *dev,
 		     __rte_unused int wait_to_complete)
-- 
1.8.1.4



More information about the dev mailing list