net: hibmcge: Add pauseparam supported in this module
authorJijie Shao <shaojijie@huawei.com>
Mon, 16 Dec 2024 04:05:30 +0000 (12:05 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 18 Dec 2024 04:01:39 +0000 (20:01 -0800)
The MAC can automatically send or respond to pause frames.
This patch supports the function of enabling pause frames
by using ethtool.

Signed-off-by: Jijie Shao <shaojijie@huawei.com>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Link: https://patch.msgid.link/20241216040532.1566229-6-shaojijie@huawei.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/hisilicon/hibmcge/hbg_common.h
drivers/net/ethernet/hisilicon/hibmcge/hbg_ethtool.c
drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.c
drivers/net/ethernet/hisilicon/hibmcge/hbg_hw.h
drivers/net/ethernet/hisilicon/hibmcge/hbg_main.c
drivers/net/ethernet/hisilicon/hibmcge/hbg_mdio.c
drivers/net/ethernet/hisilicon/hibmcge/hbg_reg.h

index 9bb3abe8837735b98e790af3425a61574bc29b43..cc143a536713034197eddce5468bd91cf2a1784d 100644 (file)
@@ -115,6 +115,7 @@ struct hbg_mac {
        u32 duplex;
        u32 autoneg;
        u32 link_status;
+       u32 pause_autoneg;
 };
 
 struct hbg_mac_table_entry {
index e7f169d2abb7ef502a77ca63b03d0539bbe412e1..a821a92db43dbd566ec2506667e444a81da0a42e 100644 (file)
@@ -143,12 +143,37 @@ static void hbg_ethtool_get_regs(struct net_device *netdev,
        }
 }
 
+static void hbg_ethtool_get_pauseparam(struct net_device *net_dev,
+                                      struct ethtool_pauseparam *param)
+{
+       struct hbg_priv *priv = netdev_priv(net_dev);
+
+       param->autoneg = priv->mac.pause_autoneg;
+       hbg_hw_get_pause_enable(priv, &param->tx_pause, &param->rx_pause);
+}
+
+static int hbg_ethtool_set_pauseparam(struct net_device *net_dev,
+                                     struct ethtool_pauseparam *param)
+{
+       struct hbg_priv *priv = netdev_priv(net_dev);
+
+       priv->mac.pause_autoneg = param->autoneg;
+       phy_set_asym_pause(priv->mac.phydev, param->rx_pause, param->tx_pause);
+
+       if (!param->autoneg)
+               hbg_hw_set_pause_enable(priv, param->tx_pause, param->rx_pause);
+
+       return 0;
+}
+
 static const struct ethtool_ops hbg_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_link_ksettings     = phy_ethtool_get_link_ksettings,
        .set_link_ksettings     = phy_ethtool_set_link_ksettings,
        .get_regs_len           = hbg_ethtool_get_regs_len,
        .get_regs               = hbg_ethtool_get_regs,
+       .get_pauseparam         = hbg_ethtool_get_pauseparam,
+       .set_pauseparam         = hbg_ethtool_set_pauseparam,
 };
 
 void hbg_ethtool_set_ops(struct net_device *netdev)
index 29d66a0ea0a6c328c399af1fcce73e43b4ef8be4..0cbe9f7229b3423ddcf80890829880d40821e305 100644 (file)
@@ -220,6 +220,27 @@ void hbg_hw_set_mac_filter_enable(struct hbg_priv *priv, u32 enable)
                            HBG_REG_REC_FILT_CTRL_UC_MATCH_EN_B, enable);
 }
 
+void hbg_hw_set_pause_enable(struct hbg_priv *priv, u32 tx_en, u32 rx_en)
+{
+       hbg_reg_write_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
+                           HBG_REG_PAUSE_ENABLE_TX_B, tx_en);
+       hbg_reg_write_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
+                           HBG_REG_PAUSE_ENABLE_RX_B, rx_en);
+}
+
+void hbg_hw_get_pause_enable(struct hbg_priv *priv, u32 *tx_en, u32 *rx_en)
+{
+       *tx_en = hbg_reg_read_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
+                                   HBG_REG_PAUSE_ENABLE_TX_B);
+       *rx_en = hbg_reg_read_field(priv, HBG_REG_PAUSE_ENABLE_ADDR,
+                                   HBG_REG_PAUSE_ENABLE_RX_B);
+}
+
+void hbg_hw_set_rx_pause_mac_addr(struct hbg_priv *priv, u64 mac_addr)
+{
+       hbg_reg_write64(priv, HBG_REG_FD_FC_ADDR_LOW_ADDR, mac_addr);
+}
+
 static void hbg_hw_init_transmit_ctrl(struct hbg_priv *priv)
 {
        u32 ctrl = 0;
index 6eb4b7d2cba84e8ebc2c071857277d1570c1cbd4..a4a049b5121d302f3fb9f9833a9aeb80b773baa8 100644 (file)
@@ -56,5 +56,8 @@ u32 hbg_hw_get_fifo_used_num(struct hbg_priv *priv, enum hbg_dir dir);
 void hbg_hw_set_tx_desc(struct hbg_priv *priv, struct hbg_tx_desc *tx_desc);
 void hbg_hw_fill_buffer(struct hbg_priv *priv, u32 buffer_dma_addr);
 void hbg_hw_set_mac_filter_enable(struct hbg_priv *priv, u32 enable);
+void hbg_hw_set_pause_enable(struct hbg_priv *priv, u32 tx_en, u32 rx_en);
+void hbg_hw_get_pause_enable(struct hbg_priv *priv, u32 *tx_en, u32 *rx_en);
+void hbg_hw_set_rx_pause_mac_addr(struct hbg_priv *priv, u64 mac_addr);
 
 #endif
index 578ba8ee409be0175e84aae1a0ee68927bd297e9..8a2d63c0c19646c3f99d6c6f1b8ae13762872e1f 100644 (file)
@@ -191,6 +191,7 @@ static int hbg_net_set_mac_address(struct net_device *netdev, void *addr)
        if (exists)
                hbg_set_mac_to_mac_table(priv, index, NULL);
 
+       hbg_hw_set_rx_pause_mac_addr(priv, ether_addr_to_u64(mac_addr));
        dev_addr_set(netdev, mac_addr);
        return 0;
 }
index a3479fba8501646f74ac3aef868f05a046a64ed4..db6bc4cfb971f2cf55c9001403b71a5b138544aa 100644 (file)
@@ -114,6 +114,19 @@ static void hbg_mdio_init_hw(struct hbg_priv *priv)
        hbg_mdio_set_command(mac, cmd);
 }
 
+static void hbg_flowctrl_cfg(struct hbg_priv *priv)
+{
+       struct phy_device *phydev = priv->mac.phydev;
+       bool rx_pause;
+       bool tx_pause;
+
+       if (!priv->mac.pause_autoneg)
+               return;
+
+       phy_get_pause(phydev, &tx_pause, &rx_pause);
+       hbg_hw_set_pause_enable(priv, tx_pause, rx_pause);
+}
+
 static void hbg_phy_adjust_link(struct net_device *netdev)
 {
        struct hbg_priv *priv = netdev_priv(netdev);
@@ -140,6 +153,7 @@ static void hbg_phy_adjust_link(struct net_device *netdev)
                        priv->mac.duplex = phydev->duplex;
                        priv->mac.autoneg = phydev->autoneg;
                        hbg_hw_adjust_link(priv, speed, phydev->duplex);
+                       hbg_flowctrl_cfg(priv);
                }
 
                priv->mac.link_status = phydev->link;
@@ -168,6 +182,7 @@ static int hbg_phy_connect(struct hbg_priv *priv)
                return ret;
 
        phy_remove_link_mode(phydev, ETHTOOL_LINK_MODE_1000baseT_Half_BIT);
+       phy_support_asym_pause(phydev);
        phy_attached_info(phydev);
 
        return 0;
index 665666712c7cdda4013e5ad294bfd4f2b89829d7..f12efc12f3c54b028f2c0852837d19b694372182 100644 (file)
@@ -51,6 +51,8 @@
 #define HBG_REG_PORT_ENABLE_RX_B               BIT(1)
 #define HBG_REG_PORT_ENABLE_TX_B               BIT(2)
 #define HBG_REG_PAUSE_ENABLE_ADDR              (HBG_REG_SGMII_BASE + 0x0048)
+#define HBG_REG_PAUSE_ENABLE_RX_B              BIT(0)
+#define HBG_REG_PAUSE_ENABLE_TX_B              BIT(1)
 #define HBG_REG_AN_NEG_STATE_ADDR              (HBG_REG_SGMII_BASE + 0x0058)
 #define HBG_REG_TRANSMIT_CTRL_ADDR             (HBG_REG_SGMII_BASE + 0x0060)
 #define HBG_REG_TRANSMIT_CTRL_PAD_EN_B         BIT(7)