From 83957d6cae5b93849babf75f112bdc069871dc34 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 30 Jan 2026 11:10:26 +0000 Subject: [PATCH 1/3] net: stmmac: clear half-duplex caps where unsupported Where a core supports hardware features, but does not indicate support for half-duplex, clear phylink's half-duplex 1G, 100M and 10M capability bits to disallow half-duplex operation and advertisement of these link modes. This will avoid the need for special code in the PCS driver to do this based on the ESTATUS register bits, as the support in the PCS is dependent on the same synthesis choice as the MAC core. Signed-off-by: Russell King (Oracle) Tested-by: Maxime Chevallier Reviewed-by: Maxime Chevallier Tested-by: Mohd Ayaan Anwar Link: https://patch.msgid.link/E1vlmOQ-00000006zuz-0ffN@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c | 2 -- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 3 +++ 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c index ca81bb1cae39..49893b9fb88c 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwxgmac2_core.c @@ -46,8 +46,6 @@ static void dwxgmac2_update_caps(struct stmmac_priv *priv) { if (!priv->dma_cap.mbps_10_100) priv->hw->link.caps &= ~(MAC_10 | MAC_100); - else if (!priv->dma_cap.half_duplex) - priv->hw->link.caps &= ~(MAC_10HD | MAC_100HD); } static void dwxgmac2_set_mac(void __iomem *ioaddr, bool enable) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index 7a451ae19f50..fee5804e75c0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -906,6 +906,9 @@ static unsigned long stmmac_mac_get_caps(struct phylink_config *config, /* Refresh the MAC-specific capabilities */ stmmac_mac_update_caps(priv); + if (priv->hw_cap_support && !priv->dma_cap.half_duplex) + priv->hw->link.caps &= ~(MAC_1000HD | MAC_100HD | MAC_10HD); + config->mac_capabilities = priv->hw->link.caps; if (priv->plat->max_speed) From eb4a1fda2c2fc72a86a724030cfc519565486d04 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 30 Jan 2026 11:10:31 +0000 Subject: [PATCH 2/3] net: stmmac: move most PCS register definitions to stmmac_pcs.c Move most of the PCS register offset definitions to stmmac_pcs.c. Since stmmac_pcs.c only ever passes zero into the register offset macros, remove that ability, making them simple constant integer definitions. Add appropriate descriptions of the registers, pointing out their similarity with their IEEE 802.3 counterparts. Make use of the BMSR definitions for the GMAC_AN_STATUS register and remove the driver private versions. Note that BMSR_LSTATUS is non-low-latching, unlike it's 802.3z counterpart. Signed-off-by: Russell King (Oracle) Tested-by: Mohd Ayaan Anwar Link: https://patch.msgid.link/E1vlmOV-00000006zv5-1CwO@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- .../net/ethernet/stmicro/stmmac/stmmac_pcs.c | 22 +++++++++++++++---- .../net/ethernet/stmicro/stmmac/stmmac_pcs.h | 22 ------------------- 2 files changed, 18 insertions(+), 26 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c index 2f826fe7229b..e827c03ae932 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c @@ -2,6 +2,20 @@ #include "stmmac.h" #include "stmmac_pcs.h" +/* + * GMAC_AN_STATUS is equivalent to MII_BMSR + * GMAC_ANE_ADV is equivalent to 802.3z MII_ADVERTISE + * GMAC_ANE_LPA is equivalent to 802.3z MII_LPA + * GMAC_ANE_EXP is equivalent to MII_EXPANSION + * GMAC_TBI is equivalent to MII_ESTATUS + * + * ADV, LPA and EXP are only available for the TBI and RTBI modes. + */ +#define GMAC_AN_STATUS 0x04 /* AN status */ +#define GMAC_ANE_ADV 0x08 /* ANE Advertisement */ +#define GMAC_ANE_LPA 0x0c /* ANE link partener ability */ +#define GMAC_TBI 0x14 /* TBI extend status */ + static int dwmac_integrated_pcs_enable(struct phylink_pcs *pcs) { struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs); @@ -49,11 +63,11 @@ void stmmac_integrated_pcs_irq(struct stmmac_priv *priv, u32 status, struct stmmac_extra_stats *x) { struct stmmac_pcs *spcs = priv->integrated_pcs; - u32 val = readl(spcs->base + GMAC_AN_STATUS(0)); + u32 val = readl(spcs->base + GMAC_AN_STATUS); if (status & PCS_ANE_IRQ) { x->irq_pcs_ane_n++; - if (val & GMAC_AN_STATUS_ANC) + if (val & BMSR_ANEGCOMPLETE) dev_info(priv->device, "PCS ANE process completed\n"); } @@ -61,9 +75,9 @@ void stmmac_integrated_pcs_irq(struct stmmac_priv *priv, u32 status, if (status & PCS_LINK_IRQ) { x->irq_pcs_link_n++; dev_info(priv->device, "PCS Link %s\n", - val & GMAC_AN_STATUS_LS ? "Up" : "Down"); + val & BMSR_LSTATUS ? "Up" : "Down"); - phylink_pcs_change(&spcs->pcs, val & GMAC_AN_STATUS_LS); + phylink_pcs_change(&spcs->pcs, val & BMSR_LSTATUS); } } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h index c4e6b242d390..13ee5bd6c788 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -16,13 +16,6 @@ /* PCS registers (AN/TBI/SGMII/RGMII) offsets */ #define GMAC_AN_CTRL(x) (x) /* AN control */ -#define GMAC_AN_STATUS(x) (x + 0x4) /* AN status */ - -/* ADV, LPA and EXP are only available for the TBI and RTBI interfaces */ -#define GMAC_ANE_ADV(x) (x + 0x8) /* ANE Advertisement */ -#define GMAC_ANE_LPA(x) (x + 0xc) /* ANE link partener ability */ -#define GMAC_ANE_EXP(x) (x + 0x10) /* ANE expansion */ -#define GMAC_TBI(x) (x + 0x14) /* TBI extend status */ /* AN Configuration defines */ #define GMAC_AN_CTRL_RAN BIT_U32(9) /* Restart Auto-Negotiation */ @@ -32,21 +25,6 @@ #define GMAC_AN_CTRL_LR BIT_U32(17) /* Lock to Reference */ #define GMAC_AN_CTRL_SGMRAL BIT_U32(18) /* SGMII RAL Control */ -/* AN Status defines */ -#define GMAC_AN_STATUS_LS BIT_U32(2) /* Link Status 0:down 1:up */ -#define GMAC_AN_STATUS_ANA BIT_U32(3) /* Auto-Negotiation Ability */ -#define GMAC_AN_STATUS_ANC BIT_U32(5) /* Auto-Negotiation Complete */ -#define GMAC_AN_STATUS_ES BIT_U32(8) /* Extended Status */ - -/* ADV and LPA defines */ -#define GMAC_ANE_FD BIT_U32(5) -#define GMAC_ANE_HD BIT_U32(6) -#define GMAC_ANE_PSE GENMASK_U32(8, 7) -#define GMAC_ANE_PSE_SHIFT 7 -#define GMAC_ANE_RFE GENMASK_U32(13, 12) -#define GMAC_ANE_RFE_SHIFT 12 -#define GMAC_ANE_ACK BIT_U32(14) - struct stmmac_priv; struct stmmac_pcs { From 69a586e8866b0c49cfc5592da50d67b3cbfa45f4 Mon Sep 17 00:00:00 2001 From: "Russell King (Oracle)" Date: Fri, 30 Jan 2026 11:10:36 +0000 Subject: [PATCH 3/3] net: stmmac: handle integrated PCS phy_intf_sel separately The dwmac core has no support for SGMII without using its integrated PCS. Thus, PHY_INTF_SEL_SGMII is only supported when this block is present, and it makes no sense for stmmac_get_phy_intf_sel() to decode this. None of the platform glue users that use stmmac_get_phy_intf_sel() directly accept PHY_INTF_SEL_SGMII as a valid mode. Check whether a PCS will be used by the driver for the interface mode, and if it is the integrated PCS, query the integrated PCS for the phy_intf_sel_i value to use. Signed-off-by: Russell King (Oracle) Tested-by: Mohd Ayaan Anwar Link: https://patch.msgid.link/E1vlmOa-00000006zvB-1fIe@rmk-PC.armlinux.org.uk Signed-off-by: Jakub Kicinski --- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 15 ++++++++++++--- drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c | 9 +++++++++ drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h | 2 ++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c index fee5804e75c0..9500b332a152 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c @@ -3159,8 +3159,6 @@ int stmmac_get_phy_intf_sel(phy_interface_t interface) phy_intf_sel = PHY_INTF_SEL_GMII_MII; else if (phy_interface_mode_is_rgmii(interface)) phy_intf_sel = PHY_INTF_SEL_RGMII; - else if (interface == PHY_INTERFACE_MODE_SGMII) - phy_intf_sel = PHY_INTF_SEL_SGMII; else if (interface == PHY_INTERFACE_MODE_RMII) phy_intf_sel = PHY_INTF_SEL_RMII; else if (interface == PHY_INTERFACE_MODE_REVMII) @@ -3174,13 +3172,24 @@ static int stmmac_prereset_configure(struct stmmac_priv *priv) { struct plat_stmmacenet_data *plat_dat = priv->plat; phy_interface_t interface; + struct phylink_pcs *pcs; int phy_intf_sel, ret; if (!plat_dat->set_phy_intf_sel) return 0; interface = plat_dat->phy_interface; - phy_intf_sel = stmmac_get_phy_intf_sel(interface); + + /* Check whether this mode uses a PCS */ + pcs = stmmac_mac_select_pcs(&priv->phylink_config, interface); + if (priv->integrated_pcs && pcs == &priv->integrated_pcs->pcs) { + /* Request the phy_intf_sel from the integrated PCS */ + phy_intf_sel = stmmac_integrated_pcs_get_phy_intf_sel(pcs, + interface); + } else { + phy_intf_sel = stmmac_get_phy_intf_sel(interface); + } + if (phy_intf_sel < 0) { netdev_err(priv->dev, "failed to get phy_intf_sel for %s: %pe\n", diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c index e827c03ae932..88fa359ea716 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c @@ -81,6 +81,15 @@ void stmmac_integrated_pcs_irq(struct stmmac_priv *priv, u32 status, } } +int stmmac_integrated_pcs_get_phy_intf_sel(struct phylink_pcs *pcs, + phy_interface_t interface) +{ + if (interface == PHY_INTERFACE_MODE_SGMII) + return PHY_INTF_SEL_SGMII; + + return -EINVAL; +} + int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset, u32 int_mask) { diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h index 13ee5bd6c788..23bbd4f10bf8 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h @@ -42,6 +42,8 @@ phylink_pcs_to_stmmac_pcs(struct phylink_pcs *pcs) void stmmac_integrated_pcs_irq(struct stmmac_priv *priv, u32 status, struct stmmac_extra_stats *x); +int stmmac_integrated_pcs_get_phy_intf_sel(struct phylink_pcs *pcs, + phy_interface_t interface); int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset, u32 int_mask);