Merge branch 'net-hns3-fix-configuration-deadlocks-and-refactor-link-setup'

Jijie Shao says:

====================
net: hns3: fix configuration deadlocks and refactor link setup

This patch series addresses a sequence of link configuration deadlocks
and parameter contamination issues in the hns3 network driver, which
typically occur during hardware resets or driver initialization under
specific user-configured scenarios.

The bugs root from asynchronous discrepancies between the MAC state
machine and cached user requests during sudden hardware resets, leading
to invalid parameter combos or frozen registers.
====================

Link: https://patch.msgid.link/20260624141319.271439-1-shaojijie@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
Jakub Kicinski
2026-06-25 09:15:46 -07:00
3 changed files with 102 additions and 38 deletions

View File

@@ -811,12 +811,11 @@ static int hns3_get_link_ksettings(struct net_device *netdev,
}
static int hns3_check_ksettings_param(const struct net_device *netdev,
const struct ethtool_link_ksettings *cmd)
const struct ethtool_link_ksettings *cmd,
u8 media_type)
{
struct hnae3_handle *handle = hns3_get_handle(netdev);
const struct hnae3_ae_ops *ops = hns3_get_ops(handle);
u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN;
u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN;
u32 lane_num;
u8 autoneg;
u32 speed;
@@ -836,9 +835,6 @@ static int hns3_check_ksettings_param(const struct net_device *netdev,
return 0;
}
if (ops->get_media_type)
ops->get_media_type(handle, &media_type, &module_type);
if (cmd->base.duplex == DUPLEX_HALF &&
media_type != HNAE3_MEDIA_TYPE_COPPER) {
netdev_err(netdev,
@@ -863,6 +859,8 @@ static int hns3_set_link_ksettings(struct net_device *netdev,
struct hnae3_handle *handle = hns3_get_handle(netdev);
struct hnae3_ae_dev *ae_dev = hns3_get_ae_dev(handle);
const struct hnae3_ae_ops *ops = hns3_get_ops(handle);
u8 module_type = HNAE3_MODULE_TYPE_UNKNOWN;
u8 media_type = HNAE3_MEDIA_TYPE_UNKNOWN;
int ret;
/* Chip don't support this mode. */
@@ -878,22 +876,23 @@ static int hns3_set_link_ksettings(struct net_device *netdev,
cmd->base.autoneg, cmd->base.speed, cmd->base.duplex,
cmd->lanes);
/* Only support ksettings_set for netdev with phy attached for now */
if (netdev->phydev) {
if (cmd->base.speed == SPEED_1000 &&
cmd->base.autoneg == AUTONEG_DISABLE)
return -EINVAL;
if (!ops->get_media_type)
return -EOPNOTSUPP;
ops->get_media_type(handle, &media_type, &module_type);
return phy_ethtool_ksettings_set(netdev->phydev, cmd);
} else if (test_bit(HNAE3_DEV_SUPPORT_PHY_IMP_B, ae_dev->caps) &&
ops->set_phy_link_ksettings) {
return ops->set_phy_link_ksettings(handle, cmd);
if (media_type == HNAE3_MEDIA_TYPE_COPPER) {
if (!ops->set_phy_link_ksettings)
return -EOPNOTSUPP;
ret = ops->set_phy_link_ksettings(handle, cmd);
if (ret != -ENODEV)
return ret;
/* PHY_INEXISTENT, use MAC-level configuration */
}
if (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2)
return -EOPNOTSUPP;
ret = hns3_check_ksettings_param(netdev, cmd);
ret = hns3_check_ksettings_param(netdev, cmd, media_type);
if (ret)
return ret;

View File

@@ -1504,6 +1504,11 @@ static int hclge_configure(struct hclge_dev *hdev)
hdev->hw.mac.req_autoneg = AUTONEG_ENABLE;
hdev->hw.mac.req_duplex = DUPLEX_FULL;
/* When lane_num is 0, the firmware will automatically
* select the appropriate lane_num based on the speed.
*/
hdev->hw.mac.req_lane_num = 0;
hclge_parse_link_mode(hdev, cfg.speed_ability);
hdev->hw.mac.max_speed = hclge_get_max_speed(cfg.speed_ability);
@@ -2579,8 +2584,11 @@ static int hclge_cfg_mac_speed_dup_h(struct hnae3_handle *handle, int speed,
if (ret)
return ret;
hdev->hw.mac.req_speed = (u32)speed;
hdev->hw.mac.req_duplex = duplex;
hdev->hw.mac.req_lane_num = lane_num;
if (speed != SPEED_UNKNOWN)
hdev->hw.mac.req_speed = (u32)speed;
if (duplex != DUPLEX_UNKNOWN)
hdev->hw.mac.req_duplex = duplex;
return 0;
}
@@ -2611,6 +2619,7 @@ static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
int ret;
if (!hdev->hw.mac.support_autoneg) {
if (enable) {
@@ -2622,7 +2631,10 @@ static int hclge_set_autoneg(struct hnae3_handle *handle, bool enable)
}
}
return hclge_set_autoneg_en(hdev, enable);
ret = hclge_set_autoneg_en(hdev, enable);
if (!ret)
hdev->hw.mac.req_autoneg = enable;
return ret;
}
static int hclge_get_autoneg(struct hnae3_handle *handle)
@@ -2884,20 +2896,6 @@ static int hclge_mac_init(struct hclge_dev *hdev)
if (!test_bit(HCLGE_STATE_RST_HANDLING, &hdev->state))
hdev->hw.mac.duplex = HCLGE_MAC_FULL;
if (hdev->hw.mac.support_autoneg) {
ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.autoneg);
if (ret)
return ret;
}
if (!hdev->hw.mac.autoneg) {
ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.req_speed,
hdev->hw.mac.req_duplex,
hdev->hw.mac.lane_num);
if (ret)
return ret;
}
mac->link = 0;
if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) {
@@ -3285,8 +3283,8 @@ static int hclge_get_phy_link_ksettings(struct hnae3_handle *handle,
}
static int
hclge_set_phy_link_ksettings(struct hnae3_handle *handle,
const struct ethtool_link_ksettings *cmd)
hclge_ethtool_ksettings_set(struct hnae3_handle *handle,
const struct ethtool_link_ksettings *cmd)
{
struct hclge_desc desc[HCLGE_PHY_LINK_SETTING_BD_NUM];
struct hclge_vport *vport = hclge_get_vport(handle);
@@ -3327,10 +3325,34 @@ hclge_set_phy_link_ksettings(struct hnae3_handle *handle,
return ret;
}
hdev->hw.mac.req_autoneg = cmd->base.autoneg;
hdev->hw.mac.req_speed = cmd->base.speed;
hdev->hw.mac.req_duplex = cmd->base.duplex;
linkmode_copy(hdev->hw.mac.advertising, cmd->link_modes.advertising);
return 0;
}
static int
hclge_set_phy_link_ksettings(struct hnae3_handle *handle,
const struct ethtool_link_ksettings *cmd)
{
struct hclge_vport *vport = hclge_get_vport(handle);
struct hclge_dev *hdev = vport->back;
int ret = -ENODEV;
if (hnae3_dev_phy_imp_supported(hdev)) {
ret = hclge_ethtool_ksettings_set(handle, cmd);
} else if (handle->netdev->phydev) {
if (cmd->base.speed == SPEED_1000 &&
cmd->base.autoneg == AUTONEG_DISABLE)
return -EINVAL;
ret = phy_ethtool_ksettings_set(handle->netdev->phydev, cmd);
}
if (ret)
return ret;
hdev->hw.mac.req_autoneg = cmd->base.autoneg;
if (cmd->base.speed != SPEED_UNKNOWN)
hdev->hw.mac.req_speed = cmd->base.speed;
if (cmd->base.duplex != DUPLEX_UNKNOWN)
hdev->hw.mac.req_duplex = cmd->base.duplex;
return 0;
}
@@ -9294,6 +9316,27 @@ static int hclge_set_wol(struct hnae3_handle *handle,
return ret;
}
static int hclge_set_autoneg_speed_dup(struct hclge_dev *hdev)
{
int ret;
if (hdev->hw.mac.support_autoneg) {
ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.req_autoneg);
if (ret)
return ret;
}
if (!hdev->hw.mac.req_autoneg) {
ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.req_speed,
hdev->hw.mac.req_duplex,
hdev->hw.mac.req_lane_num);
if (ret)
return ret;
}
return 0;
}
static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
{
struct pci_dev *pdev = ae_dev->pdev;
@@ -9455,6 +9498,20 @@ static int hclge_init_ae_dev(struct hnae3_ae_dev *ae_dev)
if (ret)
goto err_ptp_uninit;
if (hdev->hw.mac.media_type != HNAE3_MEDIA_TYPE_COPPER) {
hdev->hw.mac.req_autoneg = hdev->hw.mac.autoneg;
if (hdev->hw.mac.autoneg == AUTONEG_DISABLE &&
hdev->hw.mac.speed != SPEED_UNKNOWN)
hdev->hw.mac.req_speed = hdev->hw.mac.speed;
}
ret = hclge_set_autoneg_speed_dup(hdev);
if (ret) {
dev_err(&pdev->dev,
"failed to set autoneg speed duplex, ret = %d\n", ret);
goto err_ptp_uninit;
}
INIT_KFIFO(hdev->mac_tnl_log);
hclge_dcb_ops_set(hdev);
@@ -9785,6 +9842,13 @@ static int hclge_reset_ae_dev(struct hnae3_ae_dev *ae_dev)
return ret;
}
ret = hclge_set_autoneg_speed_dup(hdev);
if (ret) {
dev_err(&pdev->dev,
"failed to set autoneg speed duplex, ret = %d\n", ret);
return ret;
}
ret = hclge_tp_port_init(hdev);
if (ret) {
dev_err(&pdev->dev, "failed to init tp port, ret = %d\n",

View File

@@ -287,6 +287,7 @@ struct hclge_mac {
u8 support_autoneg;
u8 speed_type; /* 0: sfp speed, 1: active speed */
u8 lane_num;
u8 req_lane_num;
u32 speed;
u32 req_speed;
u32 max_speed;