]> www.infradead.org Git - users/willy/xarray.git/commitdiff
net: hns3: fix pause config problem after autoneg disabled
authorGuangbin Huang <huangguangbin2@huawei.com>
Wed, 27 Oct 2021 12:11:43 +0000 (20:11 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 27 Oct 2021 13:47:33 +0000 (14:47 +0100)
If a TP port is configured by follow steps:
1.ethtool -s ethx autoneg off speed 100 duplex full
2.ethtool -A ethx rx on tx on
3.ethtool -s ethx autoneg on(rx&tx negotiated pause results are off)
4.ethtool -s ethx autoneg off speed 100 duplex full

In step 3, driver will set rx&tx pause parameters of hardware to off as
pause parameters negotiated with link partner are off.

After step 4, the "ethtool -a ethx" command shows both rx and tx pause
parameters are on. However, pause parameters of hardware are still off
and port has no flow control function actually.

To fix this problem, if autoneg is disabled, driver uses its saved
parameters to restore pause of hardware. If the speed is not changed in
this case, there is no link state changed for phy, it will cause the pause
parameter is not taken effect, so we need to force phy to go down and up.

Fixes: aacbe27e82f0 ("net: hns3: modify how pause options is displayed")
Signed-off-by: Guangbin Huang <huangguangbin2@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/ethernet/hisilicon/hns3/hnae3.h
drivers/net/ethernet/hisilicon/hns3/hns3_ethtool.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_main.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.c
drivers/net/ethernet/hisilicon/hns3/hns3pf/hclge_tm.h

index d701451596c825e78b55bb3164b76790df3a578a..da3a593f6a5659a13946853be45ea1732cfc9658 100644 (file)
@@ -568,6 +568,7 @@ struct hnae3_ae_ops {
                               u32 *auto_neg, u32 *rx_en, u32 *tx_en);
        int (*set_pauseparam)(struct hnae3_handle *handle,
                              u32 auto_neg, u32 rx_en, u32 tx_en);
+       int (*restore_pauseparam)(struct hnae3_handle *handle);
 
        int (*set_autoneg)(struct hnae3_handle *handle, bool enable);
        int (*get_autoneg)(struct hnae3_handle *handle);
index 5ebd96f6833d6ebb8dc176af3374379d0556d35f..7d92dd273ed75357ff3a78a136fb746227db2c44 100644 (file)
@@ -824,6 +824,26 @@ static int hns3_check_ksettings_param(const struct net_device *netdev,
        return 0;
 }
 
+static int hns3_set_phy_link_ksettings(struct net_device *netdev,
+                                      const struct ethtool_link_ksettings *cmd)
+{
+       struct hnae3_handle *handle = hns3_get_handle(netdev);
+       const struct hnae3_ae_ops *ops = handle->ae_algo->ops;
+       int ret;
+
+       if (cmd->base.speed == SPEED_1000 &&
+           cmd->base.autoneg == AUTONEG_DISABLE)
+               return -EINVAL;
+
+       if (cmd->base.autoneg == AUTONEG_DISABLE && ops->restore_pauseparam) {
+               ret = ops->restore_pauseparam(handle);
+               if (ret)
+                       return ret;
+       }
+
+       return phy_ethtool_ksettings_set(netdev->phydev, cmd);
+}
+
 static int hns3_set_link_ksettings(struct net_device *netdev,
                                   const struct ethtool_link_ksettings *cmd)
 {
@@ -842,16 +862,11 @@ static int hns3_set_link_ksettings(struct net_device *netdev,
                  cmd->base.autoneg, cmd->base.speed, cmd->base.duplex);
 
        /* 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;
-
-               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) {
+       if (netdev->phydev)
+               return hns3_set_phy_link_ksettings(netdev, 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 (ae_dev->dev_version < HNAE3_DEVICE_VERSION_V2)
                return -EOPNOTSUPP;
index dcd40cc73082af46d663a466a24276b5986b6454..c6b9806c75a57cc8e60ed6c22634df685631a673 100644 (file)
@@ -11021,6 +11021,35 @@ static int hclge_set_pauseparam(struct hnae3_handle *handle, u32 auto_neg,
        return -EOPNOTSUPP;
 }
 
+static int hclge_restore_pauseparam(struct hnae3_handle *handle)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       u32 auto_neg, rx_pause, tx_pause;
+       int ret;
+
+       hclge_get_pauseparam(handle, &auto_neg, &rx_pause, &tx_pause);
+       /* when autoneg is disabled, the pause setting of phy has no effect
+        * unless the link goes down.
+        */
+       ret = phy_suspend(hdev->hw.mac.phydev);
+       if (ret)
+               return ret;
+
+       phy_set_asym_pause(hdev->hw.mac.phydev, rx_pause, tx_pause);
+
+       ret = phy_resume(hdev->hw.mac.phydev);
+       if (ret)
+               return ret;
+
+       ret = hclge_mac_pause_setup_hw(hdev);
+       if (ret)
+               dev_err(&hdev->pdev->dev,
+                       "restore pauseparam error, ret = %d.\n", ret);
+
+       return ret;
+}
+
 static void hclge_get_ksettings_an_result(struct hnae3_handle *handle,
                                          u8 *auto_neg, u32 *speed, u8 *duplex)
 {
@@ -12984,6 +13013,7 @@ static const struct hnae3_ae_ops hclge_ops = {
        .halt_autoneg = hclge_halt_autoneg,
        .get_pauseparam = hclge_get_pauseparam,
        .set_pauseparam = hclge_set_pauseparam,
+       .restore_pauseparam = hclge_restore_pauseparam,
        .set_mtu = hclge_set_mtu,
        .reset_queue = hclge_reset_tqp,
        .get_stats = hclge_get_stats,
index 95074e91a8466a3064eab898007511990acf9edf..124791e4bfeed70794c9e570fff38cf6703299e4 100644 (file)
@@ -1435,7 +1435,7 @@ static int hclge_bp_setup_hw(struct hclge_dev *hdev, u8 tc)
        return 0;
 }
 
-static int hclge_mac_pause_setup_hw(struct hclge_dev *hdev)
+int hclge_mac_pause_setup_hw(struct hclge_dev *hdev)
 {
        bool tx_en, rx_en;
 
index 2ee9b795f71dc48c3b83f5a974b52ef75e548253..4b2c3a7889800286d3556e75c05ea6808b306f45 100644 (file)
@@ -244,6 +244,7 @@ int hclge_tm_get_pri_weight(struct hclge_dev *hdev, u8 pri_id, u8 *weight);
 int hclge_tm_get_pri_shaper(struct hclge_dev *hdev, u8 pri_id,
                            enum hclge_opcode_type cmd,
                            struct hclge_tm_shaper_para *para);
+int hclge_mac_pause_setup_hw(struct hclge_dev *hdev);
 int hclge_tm_get_q_to_qs_map(struct hclge_dev *hdev, u16 q_id, u16 *qset_id);
 int hclge_tm_get_q_to_tc(struct hclge_dev *hdev, u16 q_id, u8 *tc_id);
 int hclge_tm_get_pg_to_pri_map(struct hclge_dev *hdev, u8 pg_id,