From: Jiawen Wu Date: Tue, 18 Nov 2025 08:02:57 +0000 (+0800) Subject: net: txgbe: improve functions of AML 40G devices X-Git-Tag: v6.19-rc1~170^2~115^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=57d39faed4c942ccd611588ce0065d1516778aab;p=thirdparty%2Fkernel%2Flinux.git 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 Link: https://patch.msgid.link/20251118080259.24676-4-jiawenwu@trustnetic.com Signed-off-by: Paolo Abeni --- diff --git a/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c b/drivers/net/ethernet/wangxun/libwx/wx_ethtool.c index 9aa3964187e1d..f362e51c73ee6 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 432880ccc6408..5725e95576691 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 d7f9053594588..f553ec5f8238d 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 3885283681ec7..aa14958d439a2 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 91d1b4e681265..0de051450a823 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 03f1b9bc604d5..8ea7aa07ae4e9 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 c115ed659544f..e72edb9ef0847 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)