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);
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)
{
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;
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)
{
.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,
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;
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,