net: txgbe: Implement PHYLINK for AML 25G/10G devices
authorJiawen Wu <jiawenwu@trustnetic.com>
Wed, 21 May 2025 06:43:57 +0000 (14:43 +0800)
committerPaolo Abeni <pabeni@redhat.com>
Mon, 26 May 2025 15:25:42 +0000 (17:25 +0200)
There is a new PHY attached to AML 25G/10G NIC, which is different from
SP 10G/1G NIC. But the PHY configuration is handed over to firmware, and
also I2C is controlled by firmware. So the different PHYLINK fixed-link
mode is added for these devices.

Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/987B973A5929CD48+20250521064402.22348-5-jiawenwu@trustnetic.com
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
drivers/net/ethernet/wangxun/libwx/wx_hw.c
drivers/net/ethernet/wangxun/libwx/wx_hw.h
drivers/net/ethernet/wangxun/txgbe/Makefile
drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c [new file with mode: 0644]
drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h [new file with mode: 0644]
drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
drivers/net/ethernet/wangxun/txgbe/txgbe_type.h

index 7a3467b4152444fa25b0cd7c56d523bf2694cca5..c6744a363e978f0c0e4a8efa58cca68b77aa38d3 100644 (file)
@@ -2252,10 +2252,8 @@ int wx_stop_adapter(struct wx *wx)
 }
 EXPORT_SYMBOL(wx_stop_adapter);
 
-void wx_reset_misc(struct wx *wx)
+void wx_reset_mac(struct wx *wx)
 {
-       int i;
-
        /* receive packets that size > 2048 */
        wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_JE, WX_MAC_RX_CFG_JE);
 
@@ -2267,6 +2265,14 @@ void wx_reset_misc(struct wx *wx)
              WX_MAC_RX_FLOW_CTRL_RFE, WX_MAC_RX_FLOW_CTRL_RFE);
 
        wr32(wx, WX_MAC_PKT_FLT, WX_MAC_PKT_FLT_PR);
+}
+EXPORT_SYMBOL(wx_reset_mac);
+
+void wx_reset_misc(struct wx *wx)
+{
+       int i;
+
+       wx_reset_mac(wx);
 
        wr32m(wx, WX_MIS_RST_ST,
              WX_MIS_RST_ST_RST_INIT, 0x1E00);
index 91c1d6135045b3ead7819318e24fb82a311c1928..26a56cba60b991364726ea63965cd8d0b602cafc 100644 (file)
@@ -42,6 +42,7 @@ void wx_configure(struct wx *wx);
 void wx_start_hw(struct wx *wx);
 int wx_disable_pcie_master(struct wx *wx);
 int wx_stop_adapter(struct wx *wx);
+void wx_reset_mac(struct wx *wx);
 void wx_reset_misc(struct wx *wx);
 int wx_get_pcie_msix_counts(struct wx *wx, u16 *msix_count, u16 max_msix_count);
 int wx_sw_init(struct wx *wx);
index f74576fe7062fe126b31ece1eb8404deb2a54f52..c757fa95e58e1b608938aabf56e4a004845e9a40 100644 (file)
@@ -11,4 +11,5 @@ txgbe-objs := txgbe_main.o \
               txgbe_phy.o \
               txgbe_irq.o \
               txgbe_fdir.o \
-              txgbe_ethtool.o
+              txgbe_ethtool.o \
+              txgbe_aml.o
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c
new file mode 100644 (file)
index 0000000..49eb939
--- /dev/null
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#include <linux/phylink.h>
+#include <linux/iopoll.h>
+#include <linux/pci.h>
+#include <linux/phy.h>
+
+#include "../libwx/wx_type.h"
+#include "../libwx/wx_lib.h"
+#include "../libwx/wx_hw.h"
+#include "txgbe_type.h"
+#include "txgbe_aml.h"
+#include "txgbe_hw.h"
+
+static void txgbe_get_phy_link(struct wx *wx, int *speed)
+{
+       u32 status;
+
+       status = rd32(wx, TXGBE_CFG_PORT_ST);
+       if (!(status & TXGBE_CFG_PORT_ST_LINK_UP))
+               *speed = SPEED_UNKNOWN;
+       else if (status & TXGBE_CFG_PORT_ST_LINK_AML_25G)
+               *speed = SPEED_25000;
+       else if (status & TXGBE_CFG_PORT_ST_LINK_AML_10G)
+               *speed = SPEED_10000;
+       else
+               *speed = SPEED_UNKNOWN;
+}
+
+static void txgbe_get_link_state(struct phylink_config *config,
+                                struct phylink_link_state *state)
+{
+       struct wx *wx = phylink_to_wx(config);
+       int speed;
+
+       txgbe_get_phy_link(wx, &speed);
+       state->link = speed != SPEED_UNKNOWN;
+       state->speed = speed;
+       state->duplex = state->link ? DUPLEX_FULL : DUPLEX_UNKNOWN;
+}
+
+static void txgbe_reconfig_mac(struct wx *wx)
+{
+       u32 wdg, fc;
+
+       wdg = rd32(wx, WX_MAC_WDG_TIMEOUT);
+       fc = rd32(wx, WX_MAC_RX_FLOW_CTRL);
+
+       wr32(wx, WX_MIS_RST, TXGBE_MIS_RST_MAC_RST(wx->bus.func));
+       /* wait for MAC reset complete */
+       usleep_range(1000, 1500);
+
+       wr32m(wx, TXGBE_MAC_MISC_CTL, TXGBE_MAC_MISC_CTL_LINK_STS_MOD,
+             TXGBE_MAC_MISC_CTL_LINK_BOTH);
+       wx_reset_mac(wx);
+
+       wr32(wx, WX_MAC_WDG_TIMEOUT, wdg);
+       wr32(wx, WX_MAC_RX_FLOW_CTRL, fc);
+}
+
+static void txgbe_mac_link_up_aml(struct phylink_config *config,
+                                 struct phy_device *phy,
+                                 unsigned int mode,
+                                 phy_interface_t interface,
+                                 int speed, int duplex,
+                                 bool tx_pause, bool rx_pause)
+{
+       struct wx *wx = phylink_to_wx(config);
+       u32 txcfg;
+
+       wx_fc_enable(wx, tx_pause, rx_pause);
+
+       txgbe_reconfig_mac(wx);
+
+       txcfg = rd32(wx, TXGBE_AML_MAC_TX_CFG);
+       txcfg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;
+
+       switch (speed) {
+       case SPEED_25000:
+               txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_25G;
+               break;
+       case SPEED_10000:
+               txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_10G;
+               break;
+       default:
+               break;
+       }
+
+       wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, WX_MAC_RX_CFG_RE);
+       wr32(wx, TXGBE_AML_MAC_TX_CFG, txcfg | TXGBE_AML_MAC_TX_CFG_TE);
+
+       wx->speed = speed;
+}
+
+static void txgbe_mac_link_down_aml(struct phylink_config *config,
+                                   unsigned int mode,
+                                   phy_interface_t interface)
+{
+       struct wx *wx = phylink_to_wx(config);
+
+       wr32m(wx, TXGBE_AML_MAC_TX_CFG, TXGBE_AML_MAC_TX_CFG_TE, 0);
+       wr32m(wx, WX_MAC_RX_CFG, WX_MAC_RX_CFG_RE, 0);
+
+       wx->speed = SPEED_UNKNOWN;
+}
+
+static void txgbe_mac_config_aml(struct phylink_config *config, unsigned int mode,
+                                const struct phylink_link_state *state)
+{
+}
+
+static const struct phylink_mac_ops txgbe_mac_ops_aml = {
+       .mac_config = txgbe_mac_config_aml,
+       .mac_link_down = txgbe_mac_link_down_aml,
+       .mac_link_up = txgbe_mac_link_up_aml,
+};
+
+int txgbe_phylink_init_aml(struct txgbe *txgbe)
+{
+       struct phylink_link_state state;
+       struct phylink_config *config;
+       struct wx *wx = txgbe->wx;
+       phy_interface_t phy_mode;
+       struct phylink *phylink;
+       int err;
+
+       config = &wx->phylink_config;
+       config->dev = &wx->netdev->dev;
+       config->type = PHYLINK_NETDEV;
+       config->mac_capabilities = MAC_25000FD | MAC_10000FD |
+                                  MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
+       config->get_fixed_state = txgbe_get_link_state;
+
+       phy_mode = PHY_INTERFACE_MODE_25GBASER;
+       __set_bit(PHY_INTERFACE_MODE_25GBASER, config->supported_interfaces);
+       __set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
+
+       phylink = phylink_create(config, NULL, phy_mode, &txgbe_mac_ops_aml);
+       if (IS_ERR(phylink))
+               return PTR_ERR(phylink);
+
+       state.speed = SPEED_25000;
+       state.duplex = DUPLEX_FULL;
+       err = phylink_set_fixed_link(phylink, &state);
+       if (err) {
+               wx_err(wx, "Failed to set fixed link\n");
+               return err;
+       }
+
+       wx->phylink = phylink;
+
+       return 0;
+}
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.h
new file mode 100644 (file)
index 0000000..aa3b784
--- /dev/null
@@ -0,0 +1,9 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (c) 2015 - 2025 Beijing WangXun Technology Co., Ltd. */
+
+#ifndef _TXGBE_AML_H_
+#define _TXGBE_AML_H_
+
+int txgbe_phylink_init_aml(struct txgbe *txgbe);
+
+#endif /* _TXGBE_AML_H_ */
index ece378fa2620c4c8b13afb6c21229158ddaf8068..03f1b9bc604d5cded7aee574246275694ad7018b 100644 (file)
@@ -20,6 +20,7 @@
 #include "../libwx/wx_mbx.h"
 #include "../libwx/wx_hw.h"
 #include "txgbe_type.h"
+#include "txgbe_aml.h"
 #include "txgbe_phy.h"
 #include "txgbe_hw.h"
 
@@ -318,7 +319,10 @@ irqreturn_t txgbe_link_irq_handler(int irq, void *data)
        status = rd32(wx, TXGBE_CFG_PORT_ST);
        up = !!(status & TXGBE_CFG_PORT_ST_LINK_UP);
 
-       phylink_pcs_change(txgbe->pcs, up);
+       if (txgbe->pcs)
+               phylink_pcs_change(txgbe->pcs, up);
+       else
+               phylink_mac_change(wx->phylink, up);
 
        return IRQ_HANDLED;
 }
@@ -575,8 +579,9 @@ int txgbe_init_phy(struct txgbe *txgbe)
 
        switch (wx->mac.type) {
        case wx_mac_aml40:
-       case wx_mac_aml:
                return 0;
+       case wx_mac_aml:
+               return txgbe_phylink_init_aml(txgbe);
        case wx_mac_sp:
                if (wx->media_type == wx_media_copper)
                        return txgbe_ext_phy_init(txgbe);
@@ -648,7 +653,9 @@ void txgbe_remove_phy(struct txgbe *txgbe)
 {
        switch (txgbe->wx->mac.type) {
        case wx_mac_aml40:
+               return;
        case wx_mac_aml:
+               phylink_destroy(txgbe->wx->phylink);
                return;
        case wx_mac_sp:
                if (txgbe->wx->media_type == wx_media_copper) {
index 3b4e4361462a4288b5adb3769a33a26f95c88c7e..ca4da2696eed62faf5e3d5203afff9e1d2f35ce9 100644 (file)
@@ -50,6 +50,8 @@
 
 /**************** SP Registers ****************************/
 /* chip control Registers */
+#define TXGBE_MIS_RST                           0x1000C
+#define TXGBE_MIS_RST_MAC_RST(_i)               BIT(20 - (_i) * 3)
 #define TXGBE_MIS_PRB_CTL                       0x10010
 #define TXGBE_MIS_PRB_CTL_LAN_UP(_i)            BIT(1 - (_i))
 /* FMGR Registers */
 #define TXGBE_TS_CTL                            0x10300
 #define TXGBE_TS_CTL_EVAL_MD                    BIT(31)
 
+/* MAC Misc Registers */
+#define TXGBE_MAC_MISC_CTL                      0x11F00
+#define TXGBE_MAC_MISC_CTL_LINK_STS_MOD         BIT(0)
+#define TXGBE_MAC_MISC_CTL_LINK_PCS             FIELD_PREP(BIT(0), 0)
+#define TXGBE_MAC_MISC_CTL_LINK_BOTH            FIELD_PREP(BIT(0), 1)
 /* GPIO register bit */
 #define TXGBE_GPIOBIT_0                         BIT(0) /* I:tx fault */
 #define TXGBE_GPIOBIT_1                         BIT(1) /* O:tx disabled */
@@ -88,6 +95,8 @@
 /* Port cfg registers */
 #define TXGBE_CFG_PORT_ST                       0x14404
 #define TXGBE_CFG_PORT_ST_LINK_UP               BIT(0)
+#define TXGBE_CFG_PORT_ST_LINK_AML_25G          BIT(3)
+#define TXGBE_CFG_PORT_ST_LINK_AML_10G          BIT(4)
 #define TXGBE_CFG_VXLAN                         0x14410
 #define TXGBE_CFG_VXLAN_GPE                     0x14414
 #define TXGBE_CFG_GENEVE                        0x14418
 /*************************** Amber Lite Registers ****************************/
 #define TXGBE_PX_PF_BME                         0x4B8
 #define TXGBE_AML_MAC_TX_CFG                    0x11000
+#define TXGBE_AML_MAC_TX_CFG_TE                 BIT(0)
 #define TXGBE_AML_MAC_TX_CFG_SPEED_MASK         GENMASK(30, 27)
 #define TXGBE_AML_MAC_TX_CFG_SPEED_40G          FIELD_PREP(GENMASK(30, 27), 0)
 #define TXGBE_AML_MAC_TX_CFG_SPEED_25G          FIELD_PREP(GENMASK(30, 27), 2)
+#define TXGBE_AML_MAC_TX_CFG_SPEED_10G          FIELD_PREP(GENMASK(30, 27), 8)
 #define TXGBE_RDM_RSC_CTL                       0x1200C
 #define TXGBE_RDM_RSC_CTL_FREE_CTL              BIT(7)