net: hns3: add support for set_pauseparam
authorPeng Li <lipeng321@huawei.com>
Fri, 22 Dec 2017 04:21:51 +0000 (12:21 +0800)
committerDavid S. Miller <davem@davemloft.net>
Wed, 27 Dec 2017 15:41:47 +0000 (10:41 -0500)
This patch adds set_pauseparam support for ethtool cmd.

Signed-off-by: Peng Li <lipeng321@huawei.com>
Signed-off-by: Fuyun Liang <liangfuyun1@huawei.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
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 2fd26563349221712153ffe65aad5547e1c192e8..b829ec7246855e918c29f41a6a4eec358501bb88 100644 (file)
@@ -559,6 +559,18 @@ static void hns3_get_pauseparam(struct net_device *netdev,
                        &param->rx_pause, &param->tx_pause);
 }
 
+static int hns3_set_pauseparam(struct net_device *netdev,
+                              struct ethtool_pauseparam *param)
+{
+       struct hnae3_handle *h = hns3_get_handle(netdev);
+
+       if (h->ae_algo->ops->set_pauseparam)
+               return h->ae_algo->ops->set_pauseparam(h, param->autoneg,
+                                                      param->rx_pause,
+                                                      param->tx_pause);
+       return -EOPNOTSUPP;
+}
+
 static int hns3_get_link_ksettings(struct net_device *netdev,
                                   struct ethtool_link_ksettings *cmd)
 {
@@ -880,6 +892,7 @@ static const struct ethtool_ops hns3_ethtool_ops = {
        .get_ringparam = hns3_get_ringparam,
        .set_ringparam = hns3_set_ringparam,
        .get_pauseparam = hns3_get_pauseparam,
+       .set_pauseparam = hns3_set_pauseparam,
        .get_strings = hns3_get_strings,
        .get_ethtool_stats = hns3_get_stats,
        .get_sset_count = hns3_get_sset_count,
index 14e10548ab8c4f5e91a6a9025c8db26513f13da7..0f55ee6710cc570c7c8b405cf08b4cab9a8164e7 100644 (file)
@@ -4660,6 +4660,53 @@ static u32 hclge_get_fw_version(struct hnae3_handle *handle)
        return hdev->fw_version;
 }
 
+static void hclge_set_flowctrl_adv(struct hclge_dev *hdev, u32 rx_en, u32 tx_en)
+{
+       struct phy_device *phydev = hdev->hw.mac.phydev;
+
+       if (!phydev)
+               return;
+
+       phydev->advertising &= ~(ADVERTISED_Pause | ADVERTISED_Asym_Pause);
+
+       if (rx_en)
+               phydev->advertising |= ADVERTISED_Pause | ADVERTISED_Asym_Pause;
+
+       if (tx_en)
+               phydev->advertising ^= ADVERTISED_Asym_Pause;
+}
+
+static int hclge_cfg_pauseparam(struct hclge_dev *hdev, u32 rx_en, u32 tx_en)
+{
+       enum hclge_fc_mode fc_mode;
+       int ret;
+
+       if (rx_en && tx_en)
+               fc_mode = HCLGE_FC_FULL;
+       else if (rx_en && !tx_en)
+               fc_mode = HCLGE_FC_RX_PAUSE;
+       else if (!rx_en && tx_en)
+               fc_mode = HCLGE_FC_TX_PAUSE;
+       else
+               fc_mode = HCLGE_FC_NONE;
+
+       if (hdev->tm_info.fc_mode == HCLGE_FC_PFC) {
+               hdev->fc_mode_last_time = fc_mode;
+               return 0;
+       }
+
+       ret = hclge_mac_pause_en_cfg(hdev, tx_en, rx_en);
+       if (ret) {
+               dev_err(&hdev->pdev->dev, "configure pauseparam error, ret = %d.\n",
+                       ret);
+               return ret;
+       }
+
+       hdev->tm_info.fc_mode = fc_mode;
+
+       return 0;
+}
+
 static void hclge_get_pauseparam(struct hnae3_handle *handle, u32 *auto_neg,
                                 u32 *rx_en, u32 *tx_en)
 {
@@ -4689,6 +4736,41 @@ static void hclge_get_pauseparam(struct hnae3_handle *handle, u32 *auto_neg,
        }
 }
 
+static int hclge_set_pauseparam(struct hnae3_handle *handle, u32 auto_neg,
+                               u32 rx_en, u32 tx_en)
+{
+       struct hclge_vport *vport = hclge_get_vport(handle);
+       struct hclge_dev *hdev = vport->back;
+       struct phy_device *phydev = hdev->hw.mac.phydev;
+       u32 fc_autoneg;
+
+       /* Only support flow control negotiation for netdev with
+        * phy attached for now.
+        */
+       if (!phydev)
+               return -EOPNOTSUPP;
+
+       fc_autoneg = hclge_get_autoneg(handle);
+       if (auto_neg != fc_autoneg) {
+               dev_info(&hdev->pdev->dev,
+                        "To change autoneg please use: ethtool -s <dev> autoneg <on|off>\n");
+               return -EOPNOTSUPP;
+       }
+
+       if (hdev->tm_info.fc_mode == HCLGE_FC_PFC) {
+               dev_info(&hdev->pdev->dev,
+                        "Priority flow control enabled. Cannot set link flow control.\n");
+               return -EOPNOTSUPP;
+       }
+
+       hclge_set_flowctrl_adv(hdev, rx_en, tx_en);
+
+       if (!fc_autoneg)
+               return hclge_cfg_pauseparam(hdev, rx_en, tx_en);
+
+       return phy_start_aneg(phydev);
+}
+
 static void hclge_get_ksettings_an_result(struct hnae3_handle *handle,
                                          u8 *auto_neg, u32 *speed, u8 *duplex)
 {
@@ -5344,6 +5426,7 @@ static const struct hnae3_ae_ops hclge_ops = {
        .set_autoneg = hclge_set_autoneg,
        .get_autoneg = hclge_get_autoneg,
        .get_pauseparam = hclge_get_pauseparam,
+       .set_pauseparam = hclge_set_pauseparam,
        .set_mtu = hclge_set_mtu,
        .reset_queue = hclge_reset_tqp,
        .get_stats = hclge_get_stats,
index 7bfa2e5497cb768fe180f2e5956e00ee5f595e64..7cfe1ebb9d6fd3181c6d2966a458eca083192b48 100644 (file)
@@ -112,7 +112,7 @@ static int hclge_shaper_para_calc(u32 ir, u8 shaper_level,
        return 0;
 }
 
-static int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx)
+int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx)
 {
        struct hclge_desc desc;
 
index bf59961918ab589c0502cb4cd5ad815222663f00..16f413956f17815b8e447330a96025860bb5d96e 100644 (file)
@@ -118,4 +118,5 @@ void hclge_tm_schd_info_update(struct hclge_dev *hdev, u8 num_tc);
 int hclge_tm_dwrr_cfg(struct hclge_dev *hdev);
 int hclge_tm_map_cfg(struct hclge_dev *hdev);
 int hclge_tm_init_hw(struct hclge_dev *hdev);
+int hclge_mac_pause_en_cfg(struct hclge_dev *hdev, bool tx, bool rx);
 #endif