From 398ee80192b1d44026bcf02a27dd62a6d3df236d Mon Sep 17 00:00:00 2001 From: Huisong Li Date: Tue, 23 Mar 2021 21:45:55 +0800 Subject: [PATCH] net/hns3: fix link update when failed to get link info In the "hns3_dev_link_update" API, the link information of the port is obtained first, and then 'dev_link' in dev->data is updated. When the driver is resetting or fails to obtain link info, the current driver still reports the previous link info to the user. This may cause that the dev->data->dev_link may be inconsistent with the hw link status. Therefore, the link status consistency between the hardware, driver, and framework can be ensured in this interface regardless of whether the driver is normal or abnormal. Fixes: 109e4dd1bd7a ("net/hns3: get link state change through mailbox") Cc: stable@dpdk.org Signed-off-by: Huisong Li Signed-off-by: Min Hu (Connor) --- drivers/net/hns3/hns3_ethdev.c | 55 +++++++++++++++++++++++----------- 1 file changed, 38 insertions(+), 17 deletions(-) diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c index 9a57cc6b62..9c718082b0 100644 --- a/drivers/net/hns3/hns3_ethdev.c +++ b/drivers/net/hns3/hns3_ethdev.c @@ -2698,20 +2698,22 @@ hns3_fw_version_get(struct rte_eth_dev *eth_dev, char *fw_version, } static int -hns3_dev_link_update(struct rte_eth_dev *eth_dev, - __rte_unused int wait_to_complete) +hns3_update_port_link_info(struct rte_eth_dev *eth_dev) { - struct hns3_adapter *hns = eth_dev->data->dev_private; - struct hns3_hw *hw = &hns->hw; - struct hns3_mac *mac = &hw->mac; - struct rte_eth_link new_link; + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); - if (!hns3_is_reset_pending(hns)) { - hns3_update_link_status(hw); - hns3_update_link_info(eth_dev); - } + (void)hns3_update_link_status(hw); + + return hns3_update_link_info(eth_dev); +} + +static void +hns3_setup_linkstatus(struct rte_eth_dev *eth_dev, + struct rte_eth_link *new_link) +{ + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + struct hns3_mac *mac = &hw->mac; - memset(&new_link, 0, sizeof(new_link)); switch (mac->link_speed) { case ETH_SPEED_NUM_10M: case ETH_SPEED_NUM_100M: @@ -2722,20 +2724,39 @@ hns3_dev_link_update(struct rte_eth_dev *eth_dev, case ETH_SPEED_NUM_50G: case ETH_SPEED_NUM_100G: case ETH_SPEED_NUM_200G: - new_link.link_speed = mac->link_speed; + new_link->link_speed = mac->link_speed; break; default: if (mac->link_status) - new_link.link_speed = ETH_SPEED_NUM_UNKNOWN; + new_link->link_speed = ETH_SPEED_NUM_UNKNOWN; else - new_link.link_speed = ETH_SPEED_NUM_NONE; + new_link->link_speed = ETH_SPEED_NUM_NONE; break; } - new_link.link_duplex = mac->link_duplex; - new_link.link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN; - new_link.link_autoneg = + new_link->link_duplex = mac->link_duplex; + new_link->link_status = mac->link_status ? ETH_LINK_UP : ETH_LINK_DOWN; + new_link->link_autoneg = !(eth_dev->data->dev_conf.link_speeds & ETH_LINK_SPEED_FIXED); +} + +static int +hns3_dev_link_update(struct rte_eth_dev *eth_dev, + __rte_unused int wait_to_complete) +{ + struct hns3_hw *hw = HNS3_DEV_PRIVATE_TO_HW(eth_dev->data->dev_private); + struct hns3_mac *mac = &hw->mac; + struct rte_eth_link new_link; + int ret; + + ret = hns3_update_port_link_info(eth_dev); + if (ret) { + mac->link_status = ETH_LINK_DOWN; + hns3_err(hw, "failed to get port link info, ret = %d.", ret); + } + + memset(&new_link, 0, sizeof(new_link)); + hns3_setup_linkstatus(eth_dev, &new_link); return rte_eth_linkstatus_set(eth_dev, &new_link); } -- 2.20.1