If duplex setting is half, mac and phy can not transmit and receive data at the same time, loopback test of serdes and phy will be failed, print message as follow: hns3 0000:35:00.2 eth2: self test start hns3 0000:35:00.2 eth2: link down hns3 0000:35:00.2 eth2: mode 2 recv fail, cnt=0x0, budget=0x1 hns3 0000:35:00.2 eth2: mode 3 recv fail, cnt=0x0, budget=0x1 hns3 0000:35:00.2 eth2: mode 4 recv fail, cnt=0x0, budget=0x1 hns3 0000:35:00.2 eth2: self test end The test result is FAIL The test extra info: External Loopback test 4 App Loopback test 0 Serdes serial Loopback test 3 Serdes parallel Loopback test 3 Phy Loopback test 3 To fix this problem, duplex setting of mac or phy will be set to full before serdes and phy starting loopback test, and restore duplex setting after test is end. Fixes: c39c4d98dc65 ("net: hns3: Add mac loopback selftest support in hns3 driver") Signed-off-by: Jijie Shao --- .../hisilicon/hns3/hns3pf/hclge_main.c | 26 +++++++++++++++++++ .../hisilicon/hns3/hns3pf/hclge_main.h | 1 + 2 files changed, 27 insertions(+) diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c index f209a05e2033..78b10f2668e5 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c @@ -7844,8 +7844,15 @@ static int hclge_cfg_common_loopback(struct hclge_dev *hdev, bool en, static int hclge_set_common_loopback(struct hclge_dev *hdev, bool en, enum hnae3_loop loop_mode) { + u8 duplex; int ret; + duplex = en ? DUPLEX_FULL : hdev->hw.mac.duplex; + ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed, duplex, + hdev->hw.mac.lane_num); + if (ret) + return ret; + ret = hclge_cfg_common_loopback(hdev, en, loop_mode); if (ret) return ret; @@ -7871,6 +7878,12 @@ static int hclge_enable_phy_loopback(struct hclge_dev *hdev, return ret; } + hdev->hw.mac.duplex_last = phydev->duplex; + + ret = phy_set_bits(phydev, MII_BMCR, BMCR_FULLDPLX); + if (ret) + return ret; + ret = phy_resume(phydev); if (ret) return ret; @@ -7887,12 +7900,19 @@ static int hclge_disable_phy_loopback(struct hclge_dev *hdev, if (ret) return ret; + if (hdev->hw.mac.duplex_last == DUPLEX_HALF) { + ret = phy_clear_bits(phydev, MII_BMCR, BMCR_FULLDPLX); + if (ret) + return ret; + } + return phy_suspend(phydev); } static int hclge_set_phy_loopback(struct hclge_dev *hdev, bool en) { struct phy_device *phydev = hdev->hw.mac.phydev; + u8 duplex; int ret; if (!phydev) { @@ -7902,6 +7922,12 @@ static int hclge_set_phy_loopback(struct hclge_dev *hdev, bool en) return -ENOTSUPP; } + duplex = en ? DUPLEX_FULL : hdev->hw.mac.duplex; + ret = hclge_cfg_mac_speed_dup_hw(hdev, hdev->hw.mac.speed, duplex, + hdev->hw.mac.lane_num); + if (ret) + return ret; + if (en) ret = hclge_enable_phy_loopback(hdev, phydev); else diff --git a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h index 032b472d2368..36f2b06fa17d 100644 --- a/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h +++ b/drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.h @@ -283,6 +283,7 @@ struct hclge_mac { u8 autoneg; u8 req_autoneg; u8 duplex; + u8 duplex_last; u8 req_duplex; u8 support_autoneg; u8 speed_type; /* 0: sfp speed, 1: active speed */ -- 2.33.0