diff --git a/drivers/net/ethernet/hisilicon/hns3/hnae3.h b/drivers/net/ethernet/hisilicon/hns3/hnae3.h index 1440a74c6b5d68cb595f4b0245fb02f7bb176531..1f522dbb1a947a221516680f1e21c09c3b5d3a58 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hnae3.h +++ b/drivers/net/ethernet/hisilicon/hns3/hnae3.h @@ -271,6 +271,8 @@ struct hnae3_ae_dev { * get auto autonegotiation of pause frame use * restart_autoneg() * restart autonegotiation + * halt_autoneg() + * halt/resume autonegotiation when autonegotiation on * get_coalesce_usecs() * get usecs to delay a TX interrupt after a packet is sent * get_rx_max_coalesced_frames() @@ -390,6 +392,7 @@ struct hnae3_ae_ops { int (*set_autoneg)(struct hnae3_handle *handle, bool enable); int (*get_autoneg)(struct hnae3_handle *handle); int (*restart_autoneg)(struct hnae3_handle *handle); + int (*halt_autoneg)(struct hnae3_handle *handle, bool halt); void (*get_coalesce_usecs)(struct hnae3_handle *handle, u32 *tx_usecs, u32 *rx_usecs); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index 4759224ab80abb37d7a86bbc77bda05765a19448..70c46989f95d3b83103ea9e2bb332e94db3c3afc 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -329,6 +329,13 @@ static void hns3_self_test(struct net_device *ndev, if (if_running) ndev->netdev_ops->ndo_stop(ndev); + /* Tell firmware to stop mac autoneg before loopback test start, + * otherwise loopback test may be failed when the port is still + * negotiating. + */ + if (h->ae_algo->ops->halt_autoneg) + h->ae_algo->ops->halt_autoneg(h, true); + set_bit(HNS3_NIC_STATE_TESTING, &priv->state); for (i = 0; i < HNS3_SELF_TEST_TPYE_NUM; i++) { @@ -351,6 +358,8 @@ static void hns3_self_test(struct net_device *ndev, clear_bit(HNS3_NIC_STATE_TESTING, &priv->state); + if (h->ae_algo->ops->halt_autoneg) + h->ae_algo->ops->halt_autoneg(h, false); if (if_running) ndev->netdev_ops->ndo_open(ndev); } diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index c5dda7721369b7ff5ced3d403480c2bb91275820..a5d220911f708226417cd95a5532ee2b0350d72e 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -969,7 +969,6 @@ static void hclge_parse_fiber_link_mode(struct hclge_dev *hdev, linkmode_set_bit(ETHTOOL_LINK_MODE_FIBRE_BIT, mac->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mac->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_FEC_NONE_BIT, mac->supported); - linkmode_copy(mac->advertising, mac->supported); #else unsigned long *supported = hdev->hw.mac.supported; @@ -1005,7 +1004,6 @@ static void hclge_parse_backplane_link_mode(struct hclge_dev *hdev, #endif linkmode_set_bit(ETHTOOL_LINK_MODE_Backplane_BIT, mac->supported); linkmode_set_bit(ETHTOOL_LINK_MODE_Pause_BIT, mac->supported); - linkmode_copy(mac->advertising, mac->supported); } static void hclge_parse_copper_link_mode(struct hclge_dev *hdev, @@ -2346,6 +2344,17 @@ static int hclge_restart_autoneg(struct hnae3_handle *handle) return hclge_notify_client(hdev, HNAE3_UP_CLIENT); } +static int hclge_halt_autoneg(struct hnae3_handle *handle, bool halt) +{ + struct hclge_vport *vport = hclge_get_vport(handle); + struct hclge_dev *hdev = vport->back; + + if (hdev->hw.mac.support_autoneg && hdev->hw.mac.autoneg) + return hclge_set_autoneg_en(hdev, !halt); + + return 0; +} + static int hclge_set_fec_hw(struct hclge_dev *hdev, u32 fec_mode) { struct hclge_config_fec_cmd *req; @@ -2419,6 +2428,15 @@ static int hclge_mac_init(struct hclge_dev *hdev) return ret; } + if (hdev->hw.mac.support_autoneg) { + ret = hclge_set_autoneg_en(hdev, hdev->hw.mac.autoneg); + if (ret) { + dev_err(&hdev->pdev->dev, + "Config mac autoneg fail ret=%d\n", ret); + return ret; + } + } + mac->link = 0; if (mac->user_fec_mode & BIT(HNAE3_FEC_USER_DEF)) { @@ -2552,12 +2570,14 @@ static void hclge_update_port_capability(struct hclge_mac *mac) else if (mac->media_type == HNAE3_MEDIA_TYPE_COPPER) mac->module_type = HNAE3_MODULE_TYPE_TP; - if (mac->autoneg == AUTONEG_ENABLE) + if (mac->support_autoneg) { linkmode_set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mac->supported); - else + linkmode_copy(mac->advertising, mac->supported); + } else { linkmode_clear_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, mac->supported); - linkmode_copy(mac->advertising, mac->supported); + linkmode_zero(mac->advertising); + } } static int hclge_get_sfp_speed(struct hclge_dev *hdev, u32 *speed) @@ -2606,10 +2626,10 @@ static int hclge_get_sfp_info(struct hclge_dev *hdev, struct hclge_mac *mac) mac->speed_type = resp->query_type; mac->speed = le32_to_cpu(resp->speed); - /* if speed_type is insistent with query_type, it means the - * firmware version is too old, do not update these params, + /* if resp->speed_ability is 0, it means it's an old version + * firmware, do not update these params */ - if (mac->speed_type == QUERY_ACTIVE_SPEED) { + if (resp->speed_ability) { mac->module_type = le32_to_cpu(resp->module_type); mac->speed_ability = le32_to_cpu(resp->speed_ability); mac->autoneg = resp->autoneg; @@ -2618,6 +2638,8 @@ static int hclge_get_sfp_info(struct hclge_dev *hdev, struct hclge_mac *mac) mac->fec_mode = 0; else mac->fec_mode = BIT(resp->active_fec); + } else { + mac->speed_type = QUERY_SFP_SPEED; } return 0; @@ -9416,6 +9438,7 @@ struct hnae3_ae_ops hclge_ops = { .set_autoneg = hclge_set_autoneg, .get_autoneg = hclge_get_autoneg, .restart_autoneg = hclge_restart_autoneg, + .halt_autoneg = hclge_halt_autoneg, .get_pauseparam = hclge_get_pauseparam, .set_pauseparam = hclge_set_pauseparam, .set_mtu = hclge_set_mtu, diff --git a/drivers/net/ethernet/hisilicon/hns3/kcompat.h b/drivers/net/ethernet/hisilicon/hns3/kcompat.h index 472c1e99e628f1478bb0913b264c66baf72942d6..a946cc003886cece7156a21e269f81a0bf0fa195 100644 --- a/drivers/net/ethernet/hisilicon/hns3/kcompat.h +++ b/drivers/net/ethernet/hisilicon/hns3/kcompat.h @@ -397,6 +397,11 @@ static inline void linkmode_clear_bit(int nr, volatile unsigned long *addr) __clear_bit(nr, addr); } +static inline void linkmode_zero(unsigned long *dst) +{ + bitmap_zero(dst, __ETHTOOL_LINK_MODE_MASK_NBITS); +} + #else #define HAS_LINK_MODE_OPS