i40e: support autoneg or force link speed

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

Signed-off-by: Cunming Liang <cunming.liang@intel.com>
Acked-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Chen Jing D(Mark) <jing.d.chen@intel.com>
Tested-by: Xu HuilongX <huilongx.xu@intel.com>
This commit is contained in:
Cunming Liang 2014-08-01 04:44:07 +08:00 committed by Thomas Monjalon
parent 4f41de4fd5
commit 6e145fcc75
2 changed files with 152 additions and 6 deletions

View File

@ -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,

View File

@ -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,102 @@ 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;
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;
memset(&phy_conf, 0, sizeof(phy_conf));
/* 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 +757,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 +790,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 +818,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 +916,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)