lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20251118080259.24676-4-jiawenwu@trustnetic.com>
Date: Tue, 18 Nov 2025 16:02:57 +0800
From: Jiawen Wu <jiawenwu@...stnetic.com>
To: netdev@...r.kernel.org,
	Andrew Lunn <andrew+netdev@...n.ch>,
	"David S. Miller" <davem@...emloft.net>,
	Eric Dumazet <edumazet@...gle.com>,
	Jakub Kicinski <kuba@...nel.org>,
	Paolo Abeni <pabeni@...hat.com>,
	Simon Horman <horms@...nel.org>,
	Russell King <linux@...linux.org.uk>,
	Jacob Keller <jacob.e.keller@...el.com>,
	Vadim Fedorenko <vadim.fedorenko@...ux.dev>
Cc: Mengyuan Lou <mengyuanlou@...-swift.com>,
	Jiawen Wu <jiawenwu@...stnetic.com>
Subject: [PATCH net-next v2 3/5] net: txgbe: improve functions of AML 40G devices

Support to identify QSFP modules for AML 40G devices. The definition of
GPIO pins follows the design of the QSFP modules, and TXGBE_GPIOBIT_4 is
used for module present.

Meanwhile, implement phylink in XLGMII mode by default, and get the link
state from MAC link.

Signed-off-by: Jiawen Wu <jiawenwu@...stnetic.com>
---
 .../net/ethernet/wangxun/libwx/wx_ethtool.c   |  12 --
 .../net/ethernet/wangxun/txgbe/txgbe_aml.c    | 136 ++++++++++++++++--
 .../ethernet/wangxun/txgbe/txgbe_ethtool.c    |   3 -
 .../net/ethernet/wangxun/txgbe/txgbe_irq.c    |  10 +-
 .../net/ethernet/wangxun/txgbe/txgbe_main.c   |  11 +-
 .../net/ethernet/wangxun/txgbe/txgbe_phy.c    |   2 -
 .../net/ethernet/wangxun/txgbe/txgbe_type.h   |  11 ++
 7 files changed, 137 insertions(+), 48 deletions(-)

diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
index 9aa3964187e1..f362e51c73ee 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
+++ b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c
@@ -240,9 +240,6 @@ int wx_nway_reset(struct net_device *netdev)
 {
 	struct wx *wx = netdev_priv(netdev);
 
-	if (wx->mac.type == wx_mac_aml40)
-		return -EOPNOTSUPP;
-
 	return phylink_ethtool_nway_reset(wx->phylink);
 }
 EXPORT_SYMBOL(wx_nway_reset);
@@ -261,9 +258,6 @@ int wx_set_link_ksettings(struct net_device *netdev,
 {
 	struct wx *wx = netdev_priv(netdev);
 
-	if (wx->mac.type == wx_mac_aml40)
-		return -EOPNOTSUPP;
-
 	return phylink_ethtool_ksettings_set(wx->phylink, cmd);
 }
 EXPORT_SYMBOL(wx_set_link_ksettings);
@@ -273,9 +267,6 @@ void wx_get_pauseparam(struct net_device *netdev,
 {
 	struct wx *wx = netdev_priv(netdev);
 
-	if (wx->mac.type == wx_mac_aml40)
-		return;
-
 	phylink_ethtool_get_pauseparam(wx->phylink, pause);
 }
 EXPORT_SYMBOL(wx_get_pauseparam);
@@ -285,9 +276,6 @@ int wx_set_pauseparam(struct net_device *netdev,
 {
 	struct wx *wx = netdev_priv(netdev);
 
-	if (wx->mac.type == wx_mac_aml40)
-		return -EOPNOTSUPP;
-
 	return phylink_ethtool_set_pauseparam(wx->phylink, pause);
 }
 EXPORT_SYMBOL(wx_set_pauseparam);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c
index 432880ccc640..5725e9557669 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_aml.c
@@ -17,10 +17,15 @@
 
 void txgbe_gpio_init_aml(struct wx *wx)
 {
-	u32 status;
+	u32 status, mod_rst;
+
+	if (wx->mac.type == wx_mac_aml40)
+		mod_rst = TXGBE_GPIOBIT_4;
+	else
+		mod_rst = TXGBE_GPIOBIT_2;
 
-	wr32(wx, WX_GPIO_INTTYPE_LEVEL, TXGBE_GPIOBIT_2);
-	wr32(wx, WX_GPIO_INTEN, TXGBE_GPIOBIT_2);
+	wr32(wx, WX_GPIO_INTTYPE_LEVEL, mod_rst);
+	wr32(wx, WX_GPIO_INTEN, mod_rst);
 
 	status = rd32(wx, WX_GPIO_INTSTATUS);
 	for (int i = 0; i < 6; i++) {
@@ -33,13 +38,18 @@ irqreturn_t txgbe_gpio_irq_handler_aml(int irq, void *data)
 {
 	struct txgbe *txgbe = data;
 	struct wx *wx = txgbe->wx;
-	u32 status;
+	u32 status, mod_rst;
+
+	if (wx->mac.type == wx_mac_aml40)
+		mod_rst = TXGBE_GPIOBIT_4;
+	else
+		mod_rst = TXGBE_GPIOBIT_2;
 
 	wr32(wx, WX_GPIO_INTMASK, 0xFF);
 	status = rd32(wx, WX_GPIO_INTSTATUS);
-	if (status & TXGBE_GPIOBIT_2) {
+	if (status & mod_rst) {
 		set_bit(WX_FLAG_NEED_MODULE_RESET, wx->flags);
-		wr32(wx, WX_GPIO_EOI, TXGBE_GPIOBIT_2);
+		wr32(wx, WX_GPIO_EOI, mod_rst);
 		wx_service_event_schedule(wx);
 	}
 
@@ -51,7 +61,7 @@ int txgbe_test_hostif(struct wx *wx)
 {
 	struct txgbe_hic_ephy_getlink buffer;
 
-	if (wx->mac.type != wx_mac_aml)
+	if (wx->mac.type == wx_mac_sp)
 		return 0;
 
 	buffer.hdr.cmd = FW_PHY_GET_LINK_CMD;
@@ -86,6 +96,9 @@ static int txgbe_set_phy_link_hostif(struct wx *wx, int speed, int autoneg, int
 	buffer.hdr.cmd_or_resp.cmd_resv = FW_CEM_CMD_RESERVED;
 
 	switch (speed) {
+	case SPEED_40000:
+		buffer.speed = TXGBE_LINK_SPEED_40GB_FULL;
+		break;
 	case SPEED_25000:
 		buffer.speed = TXGBE_LINK_SPEED_25GB_FULL;
 		break;
@@ -110,7 +123,9 @@ static void txgbe_get_link_capabilities(struct wx *wx, int *speed,
 {
 	struct txgbe *txgbe = wx->priv;
 
-	if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->link_interfaces))
+	if (test_bit(PHY_INTERFACE_MODE_XLGMII, txgbe->link_interfaces))
+		*speed = SPEED_40000;
+	else if (test_bit(PHY_INTERFACE_MODE_25GBASER, txgbe->link_interfaces))
 		*speed = SPEED_25000;
 	else if (test_bit(PHY_INTERFACE_MODE_10GBASER, txgbe->link_interfaces))
 		*speed = SPEED_10000;
@@ -128,6 +143,8 @@ static void txgbe_get_mac_link(struct wx *wx, int *speed)
 	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_40G)
+		*speed = SPEED_40000;
 	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_25G)
 		*speed = SPEED_25000;
 	else if (status & TXGBE_CFG_PORT_ST_LINK_AML_10G)
@@ -218,15 +235,86 @@ static int txgbe_sfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
 	return 0;
 }
 
+static int txgbe_qsfp_to_linkmodes(struct wx *wx, struct txgbe_sff_id *id)
+{
+	__ETHTOOL_DECLARE_LINK_MODE_MASK(modes) = { 0, };
+	DECLARE_PHY_INTERFACE_MASK(interfaces);
+	struct txgbe *txgbe = wx->priv;
+
+	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_CR4) {
+		txgbe->link_port = PORT_DA;
+		phylink_set(modes, Autoneg);
+		phylink_set(modes, 40000baseCR4_Full);
+		phylink_set(modes, 10000baseCR_Full);
+		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
+		__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+	}
+	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_SR4) {
+		txgbe->link_port = PORT_FIBRE;
+		phylink_set(modes, 40000baseSR4_Full);
+		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
+	}
+	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_LR4) {
+		txgbe->link_port = PORT_FIBRE;
+		phylink_set(modes, 40000baseLR4_Full);
+		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
+	}
+	if (id->transceiver_type & TXGBE_SFF_ETHERNET_40G_ACTIVE) {
+		txgbe->link_port = PORT_DA;
+		phylink_set(modes, Autoneg);
+		phylink_set(modes, 40000baseCR4_Full);
+		__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
+	}
+	if (id->transceiver_type & TXGBE_SFF_ETHERNET_RSRVD) {
+		if (id->sff_opt1 & TXGBE_SFF_ETHERNET_100G_CR4) {
+			txgbe->link_port = PORT_DA;
+			phylink_set(modes, Autoneg);
+			phylink_set(modes, 40000baseCR4_Full);
+			phylink_set(modes, 25000baseCR_Full);
+			phylink_set(modes, 10000baseCR_Full);
+			__set_bit(PHY_INTERFACE_MODE_XLGMII, interfaces);
+			__set_bit(PHY_INTERFACE_MODE_25GBASER, interfaces);
+			__set_bit(PHY_INTERFACE_MODE_10GBASER, interfaces);
+		}
+	}
+
+	if (phy_interface_empty(interfaces)) {
+		wx_err(wx, "unsupported QSFP module\n");
+		return -EINVAL;
+	}
+
+	phylink_set(modes, Pause);
+	phylink_set(modes, Asym_Pause);
+	phylink_set(modes, FIBRE);
+
+	if (!linkmode_equal(txgbe->link_support, modes)) {
+		linkmode_copy(txgbe->link_support, modes);
+		phy_interface_and(txgbe->link_interfaces,
+				  wx->phylink_config.supported_interfaces,
+				  interfaces);
+		linkmode_copy(txgbe->advertising, modes);
+
+		set_bit(WX_FLAG_NEED_LINK_CONFIG, wx->flags);
+	}
+
+	return 0;
+}
+
 int txgbe_identify_module(struct wx *wx)
 {
 	struct txgbe_hic_get_module_info buffer;
 	struct txgbe_sff_id *id;
 	int err = 0;
+	u32 mod_abs;
 	u32 gpio;
 
+	if (wx->mac.type == wx_mac_aml40)
+		mod_abs = TXGBE_GPIOBIT_4;
+	else
+		mod_abs = TXGBE_GPIOBIT_2;
+
 	gpio = rd32(wx, WX_GPIO_EXT);
-	if (gpio & TXGBE_GPIOBIT_2)
+	if (gpio & mod_abs)
 		return -ENODEV;
 
 	err = txgbe_identify_module_hostif(wx, &buffer);
@@ -236,12 +324,18 @@ int txgbe_identify_module(struct wx *wx)
 	}
 
 	id = &buffer.id;
-	if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP) {
-		wx_err(wx, "Invalid SFP module\n");
+	if (id->identifier != TXGBE_SFF_IDENTIFIER_SFP &&
+	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP &&
+	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP_PLUS &&
+	    id->identifier != TXGBE_SFF_IDENTIFIER_QSFP28) {
+		wx_err(wx, "Invalid module\n");
 		return -ENODEV;
 	}
 
-	return txgbe_sfp_to_linkmodes(wx, id);
+	if (id->transceiver_type == 0xFF)
+		return txgbe_sfp_to_linkmodes(wx, id);
+
+	return txgbe_qsfp_to_linkmodes(wx, id);
 }
 
 void txgbe_setup_link(struct wx *wx)
@@ -304,6 +398,9 @@ static void txgbe_mac_link_up_aml(struct phylink_config *config,
 	txcfg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;
 
 	switch (speed) {
+	case SPEED_40000:
+		txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_40G;
+		break;
 	case SPEED_25000:
 		txcfg |= TXGBE_AML_MAC_TX_CFG_SPEED_25G;
 		break;
@@ -368,7 +465,18 @@ int txgbe_phylink_init_aml(struct txgbe *txgbe)
 				   MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
 	config->get_fixed_state = txgbe_get_link_state;
 
-	phy_mode = PHY_INTERFACE_MODE_25GBASER;
+	if (wx->mac.type == wx_mac_aml40) {
+		config->mac_capabilities |= MAC_40000FD;
+		phy_mode = PHY_INTERFACE_MODE_XLGMII;
+		__set_bit(PHY_INTERFACE_MODE_XLGMII, config->supported_interfaces);
+		state.speed = SPEED_40000;
+		state.duplex = DUPLEX_FULL;
+	} else {
+		phy_mode = PHY_INTERFACE_MODE_25GBASER;
+		state.speed = SPEED_25000;
+		state.duplex = DUPLEX_FULL;
+	}
+
 	__set_bit(PHY_INTERFACE_MODE_25GBASER, config->supported_interfaces);
 	__set_bit(PHY_INTERFACE_MODE_10GBASER, config->supported_interfaces);
 
@@ -376,8 +484,6 @@ int txgbe_phylink_init_aml(struct txgbe *txgbe)
 	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");
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
index d7f905359458..f553ec5f8238 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_ethtool.c
@@ -19,9 +19,6 @@ int txgbe_get_link_ksettings(struct net_device *netdev,
 	struct txgbe *txgbe = wx->priv;
 	int err;
 
-	if (wx->mac.type == wx_mac_aml40)
-		return -EOPNOTSUPP;
-
 	err = wx_get_link_ksettings(netdev, cmd);
 	if (err)
 		return err;
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c
index 3885283681ec..aa14958d439a 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_irq.c
@@ -23,7 +23,7 @@ void txgbe_irq_enable(struct wx *wx, bool queues)
 {
 	u32 misc_ien = TXGBE_PX_MISC_IEN_MASK;
 
-	if (wx->mac.type == wx_mac_aml) {
+	if (wx->mac.type != wx_mac_sp) {
 		misc_ien |= TXGBE_PX_MISC_GPIO;
 		txgbe_gpio_init_aml(wx);
 	}
@@ -201,10 +201,7 @@ static void txgbe_del_irq_domain(struct txgbe *txgbe)
 
 void txgbe_free_misc_irq(struct txgbe *txgbe)
 {
-	if (txgbe->wx->mac.type == wx_mac_aml40)
-		return;
-
-	if (txgbe->wx->mac.type == wx_mac_aml)
+	if (txgbe->wx->mac.type != wx_mac_sp)
 		free_irq(txgbe->gpio_irq, txgbe);
 
 	free_irq(txgbe->link_irq, txgbe);
@@ -219,9 +216,6 @@ int txgbe_setup_misc_irq(struct txgbe *txgbe)
 	struct wx *wx = txgbe->wx;
 	int hwirq, err;
 
-	if (wx->mac.type == wx_mac_aml40)
-		goto skip_sp_irq;
-
 	txgbe->misc.nirqs = TXGBE_IRQ_MAX;
 	txgbe->misc.domain = irq_domain_create_simple(NULL, txgbe->misc.nirqs, 0,
 						      &txgbe_misc_irq_domain_ops, txgbe);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 91d1b4e68126..0de051450a82 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -144,7 +144,6 @@ static void txgbe_init_service(struct wx *wx)
 static void txgbe_up_complete(struct wx *wx)
 {
 	struct net_device *netdev = wx->netdev;
-	u32 reg;
 
 	wx_control_hw(wx, true);
 	wx_configure_vectors(wx);
@@ -155,12 +154,8 @@ static void txgbe_up_complete(struct wx *wx)
 
 	switch (wx->mac.type) {
 	case wx_mac_aml40:
-		reg = rd32(wx, TXGBE_AML_MAC_TX_CFG);
-		reg &= ~TXGBE_AML_MAC_TX_CFG_SPEED_MASK;
-		reg |= TXGBE_AML_MAC_TX_CFG_SPEED_40G;
-		wr32(wx, WX_MAC_TX_CFG, reg);
-		txgbe_enable_sec_tx_path(wx);
-		netif_carrier_on(wx->netdev);
+		txgbe_setup_link(wx);
+		phylink_start(wx->phylink);
 		break;
 	case wx_mac_aml:
 		/* Enable TX laser */
@@ -276,7 +271,7 @@ void txgbe_down(struct wx *wx)
 
 	switch (wx->mac.type) {
 	case wx_mac_aml40:
-		netif_carrier_off(wx->netdev);
+		phylink_stop(wx->phylink);
 		break;
 	case wx_mac_aml:
 		phylink_stop(wx->phylink);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 03f1b9bc604d..8ea7aa07ae4e 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -579,7 +579,6 @@ int txgbe_init_phy(struct txgbe *txgbe)
 
 	switch (wx->mac.type) {
 	case wx_mac_aml40:
-		return 0;
 	case wx_mac_aml:
 		return txgbe_phylink_init_aml(txgbe);
 	case wx_mac_sp:
@@ -653,7 +652,6 @@ 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;
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
index c115ed659544..e72edb9ef084 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_type.h
@@ -98,6 +98,7 @@
 /* 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_40G          BIT(2)
 #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
@@ -317,8 +318,12 @@ void txgbe_do_reset(struct net_device *netdev);
 #define TXGBE_LINK_SPEED_UNKNOWN        0
 #define TXGBE_LINK_SPEED_10GB_FULL      4
 #define TXGBE_LINK_SPEED_25GB_FULL      0x10
+#define TXGBE_LINK_SPEED_40GB_FULL      0x20
 
 #define TXGBE_SFF_IDENTIFIER_SFP        0x3
+#define TXGBE_SFF_IDENTIFIER_QSFP       0xC
+#define TXGBE_SFF_IDENTIFIER_QSFP_PLUS  0xD
+#define TXGBE_SFF_IDENTIFIER_QSFP28     0x11
 #define TXGBE_SFF_DA_PASSIVE_CABLE      0x4
 #define TXGBE_SFF_DA_ACTIVE_CABLE       0x8
 #define TXGBE_SFF_DA_SPEC_ACTIVE_LIMIT  0x4
@@ -331,6 +336,12 @@ void txgbe_do_reset(struct net_device *netdev);
 #define TXGBE_SFF_25GBASECR_91FEC       0xB
 #define TXGBE_SFF_25GBASECR_74FEC       0xC
 #define TXGBE_SFF_25GBASECR_NOFEC       0xD
+#define TXGBE_SFF_ETHERNET_RSRVD        BIT(7)
+#define TXGBE_SFF_ETHERNET_40G_CR4      BIT(3)
+#define TXGBE_SFF_ETHERNET_40G_SR4      BIT(2)
+#define TXGBE_SFF_ETHERNET_40G_LR4      BIT(1)
+#define TXGBE_SFF_ETHERNET_40G_ACTIVE   BIT(0)
+#define TXGBE_SFF_ETHERNET_100G_CR4     0xB
 
 #define TXGBE_PHY_FEC_RS                BIT(0)
 #define TXGBE_PHY_FEC_BASER             BIT(1)
-- 
2.48.1


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ