mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 03:27:30 -04:00
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:
@@ -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;
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user