diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c index a71f7d97ae0d0de2664bed763f1b2bf13282ff84..5e800bd290552dc80aa8e6e8930b9673ef1f30c4 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c @@ -55,7 +55,7 @@ static const struct hns3_stats hns3_rxq_stats[] = { #define HNS3_TQP_STATS_COUNT (HNS3_TXQ_STATS_COUNT + HNS3_RXQ_STATS_COUNT) -#define HNS3_SELF_TEST_TPYE_NUM 3 +#define HNS3_SELF_TEST_TPYE_NUM 4 #define HNS3_NIC_LB_TEST_PKT_NUM 1 #define HNS3_NIC_LB_TEST_RING_ID 0 #define HNS3_NIC_LB_TEST_PACKET_SIZE 128 @@ -85,6 +85,7 @@ static int hns3_lp_setup(struct net_device *ndev, enum hnae3_loop loop, bool en) case HNAE3_LOOP_SERIAL_SERDES: case HNAE3_LOOP_PARALLEL_SERDES: case HNAE3_LOOP_APP: + case HNAE3_LOOP_PHY: ret = h->ae_algo->ops->set_loopback(h, loop, en); break; default: @@ -329,6 +330,10 @@ static void hns3_self_test(struct net_device *ndev, st_param[HNAE3_LOOP_PARALLEL_SERDES][1] = h->flags & HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK; + st_param[HNAE3_LOOP_PHY][0] = HNAE3_LOOP_PHY; + st_param[HNAE3_LOOP_PHY][1] = + h->flags & HNAE3_SUPPORT_PHY_LOOPBACK; + if (if_running) ndev->netdev_ops->ndo_stop(ndev); diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index 538c9e07cb6dd074d772dd14cea1ed76d2abbe9a..00c083a4f6965607f317ca4704541865d2c97dba 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -37,6 +37,8 @@ #define HCLGE_RESET_MAX_FAIL_CNT 5 +#define HCLGE_LINK_STATUS_MS 10 + static int hclge_set_mac_mtu(struct hclge_dev *hdev, int new_mps); static int hclge_init_vlan_config(struct hclge_dev *hdev); static void hclge_sync_vlan_filter(struct hclge_dev *hdev); @@ -572,6 +574,7 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK) struct hclge_vport *vport = hclge_get_vport(handle); + struct phy_device *phy_dev = handle->netdev->phydev; struct hclge_dev *hdev = vport->back; int count = 0; @@ -594,6 +597,12 @@ static int hclge_get_sset_count(struct hnae3_handle *handle, int stringset) count += 2; handle->flags |= HNAE3_SUPPORT_SERDES_SERIAL_LOOPBACK; handle->flags |= HNAE3_SUPPORT_SERDES_PARALLEL_LOOPBACK; + + if (phy_dev) { + count += 1; + handle->flags |= HNAE3_SUPPORT_PHY_LOOPBACK; + } + } else if (stringset == ETH_SS_STATS) { count = ARRAY_SIZE(g_mac_stats_string) + hclge_tqps_get_sset_count(handle, stringset); @@ -6088,6 +6097,63 @@ static void hclge_cfg_mac_mode(struct hclge_dev *hdev, bool enable) "mac enable fail, ret =%d.\n", ret); } +static void hclge_phy_link_status_wait(struct hclge_dev *hdev, + struct phy_device *phydev, int link_ret) +{ +#define HCLGE_PHY_LINK_STATUS_NUM 200 + + int i = 0; + int ret; + + do { + ret = phy_read_status(phydev); + if (ret) + dev_warn(&hdev->pdev->dev, + "phy update link status fail\n"); + + if (phydev->link == link_ret) + break; + msleep(HCLGE_LINK_STATUS_MS); + } while (++i < HCLGE_PHY_LINK_STATUS_NUM); +} + +static int hclge_mac_link_status_wait(struct hclge_dev *hdev, int link_ret) +{ +#define HCLGE_MAC_LINK_STATUS_NUM 100 + + int i = 0; + int ret; + + do { + ret = hclge_get_mac_link_status(hdev); + if (ret == link_ret) + return 0; + msleep(HCLGE_LINK_STATUS_MS); + } while (++i < HCLGE_MAC_LINK_STATUS_NUM); + return -EBUSY; +} + +static int hclge_mac_phy_link_status_wait(struct hclge_dev *hdev, bool en) +{ +#define HCLGE_LINK_STATUS_DOWN 0 +#define HCLGE_LINK_STATUS_UP 1 + + struct phy_device *phydev = hdev->hw.mac.phydev; + int link_ret; + int ret; + + if (en) + link_ret = HCLGE_LINK_STATUS_UP; + else + link_ret = HCLGE_LINK_STATUS_DOWN; + + if (phydev) + hclge_phy_link_status_wait(hdev, phydev, link_ret); + + ret = hclge_mac_link_status_wait(hdev, link_ret); + return ret; +} + static int hclge_set_app_loopback(struct hclge_dev *hdev, bool en) { struct hclge_config_mac_mode_cmd *req; @@ -6130,15 +6196,9 @@ static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en, #define HCLGE_SERDES_RETRY_MS 10 #define HCLGE_SERDES_RETRY_NUM 100 -#define HCLGE_MAC_LINK_STATUS_MS 10 -#define HCLGE_MAC_LINK_STATUS_NUM 100 -#define HCLGE_MAC_LINK_STATUS_DOWN 0 -#define HCLGE_MAC_LINK_STATUS_UP 1 - struct hclge_serdes_lb_cmd *req; struct hclge_desc desc; int ret, i = 0; - int mac_link_ret = 0; u8 loop_mode_b; req = (struct hclge_serdes_lb_cmd *)desc.data; @@ -6160,10 +6220,8 @@ static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en, if (en) { req->enable = loop_mode_b; req->mask = loop_mode_b; - mac_link_ret = HCLGE_MAC_LINK_STATUS_UP; } else { req->mask = loop_mode_b; - mac_link_ret = HCLGE_MAC_LINK_STATUS_DOWN; } ret = hclge_cmd_send(&hdev->hw, &desc, 1); @@ -6196,19 +6254,69 @@ static int hclge_set_serdes_loopback(struct hclge_dev *hdev, bool en, hclge_cfg_mac_mode(hdev, en); - i = 0; + ret = hclge_mac_phy_link_status_wait(hdev, en); + if (ret) + dev_err(&hdev->pdev->dev, + "serdes loopback config mac mode timeout\n"); - do { - /* serdes Internal loopback, independent of the network cable.*/ - msleep(HCLGE_MAC_LINK_STATUS_MS); - ret = hclge_get_mac_link_status(hdev); - if (ret == mac_link_ret) - return 0; - } while (++i < HCLGE_MAC_LINK_STATUS_NUM); + return ret; +} - dev_err(&hdev->pdev->dev, "config mac mode timeout\n"); +static int hclge_enable_phy_loopback(struct hclge_dev *hdev, + struct phy_device *phydev) +{ + int ret; - return -EBUSY; + if (!phydev->suspended) { + ret = phy_suspend(phydev); + if (ret) + return ret; + } + + ret = phy_resume(phydev); + if (ret) + return ret; + + ret = phy_loopback(phydev, true); + return ret; +} + +static int hclge_disable_phy_loopback(struct hclge_dev *hdev, + struct phy_device *phydev) +{ + int ret; + + ret = phy_loopback(phydev, false); + if (ret) + return ret; + + ret = phy_suspend(phydev); + return ret; +} + +static int hclge_set_phy_loopback(struct hclge_dev *hdev, + struct phy_device *phydev, bool en) +{ + int ret; + + if (en) + ret = hclge_enable_phy_loopback(hdev, phydev); + else + ret = hclge_disable_phy_loopback(hdev, phydev); + if (ret) { + dev_err(&hdev->pdev->dev, + "set phy loopback fail, ret = %d\n", ret); + return ret; + } + + hclge_cfg_mac_mode(hdev, en); + + ret = hclge_mac_phy_link_status_wait(hdev, en); + if (ret) + dev_err(&hdev->pdev->dev, + "phy loopback config mac mode timeout\n"); + + return ret; } static int hclge_tqp_enable(struct hclge_dev *hdev, unsigned int tqp_id, @@ -6236,9 +6344,11 @@ static int hclge_set_loopback(struct hnae3_handle *handle, enum hnae3_loop loop_mode, bool en) { struct hclge_vport *vport = hclge_get_vport(handle); + struct phy_device *phydev = handle->netdev->phydev; struct hnae3_knic_private_info *kinfo; struct hclge_dev *hdev = vport->back; - int i, ret; + int ret = 0; + int i; switch (loop_mode) { case HNAE3_LOOP_APP: @@ -6248,6 +6358,10 @@ static int hclge_set_loopback(struct hnae3_handle *handle, case HNAE3_LOOP_PARALLEL_SERDES: ret = hclge_set_serdes_loopback(hdev, en, loop_mode); break; + case HNAE3_LOOP_PHY: + if (phydev) + ret = hclge_set_phy_loopback(hdev, phydev, en); + break; default: ret = -ENOTSUPP; dev_err(&hdev->pdev->dev,