]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
net: stmmac: convert to phylink PCS support
authorRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Thu, 16 Oct 2025 14:37:52 +0000 (15:37 +0100)
committerJakub Kicinski <kuba@kernel.org>
Tue, 21 Oct 2025 00:17:16 +0000 (17:17 -0700)
Now that stmmac's PCS support is much more simple - just a matter of
configuring the control register - the basic conversion to phylink PCS
support becomes straight forward.

Create the infrastructure to setup a phylink_pcs instance for the
integrated PCS:
- add a struct stmmac_pcs to encapsulate the phylink_pcs structure,
  pointer to stmmac_priv, and the core-specific base address of the PCS
  registers.
- modify stmmac_priv and stmmac_mac_select_pcs() to return the embedded
  phylink_pcs structure when setup and STMMAC_PCS_SGMII is in use, and
  move the comment from stmmac_hw_setup() to here.
- create stmmac_pcs.c, which contains the phylink_pcs_ops structure, a
  dummy .pcs_get_state() method which always reports link-down, and
  .pcs_config() method, moving the call to stmmac_pcs_ctrl_ane() here,
  but without indirecting through the dwmac specific core code. The
  link-down behaviour mentioned above maintains the current behaviour
  when phylink is used with inband but without a PCS.

This will ensure that the PCS control register is configured to the
same settings as before, but will now happen when the netdev is opened
or reusmed rather than only during probe time. However, this will be
before the .fix_mac_speed() method is called, which is critical for the
behaviour in dwmac-qcom-ethqos's ethqos_configure_sgmii() function to
be maintained.

Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk>
Tested-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
Tested-by: Lad Prabhakar <prabhakar.mahadev-lad.rj@bp.renesas.com>
Link: https://patch.msgid.link/E1v9P72-0000000AomR-3ro4@rmk-PC.armlinux.org.uk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/ethernet/stmicro/stmmac/Makefile
drivers/net/ethernet/stmicro/stmmac/dwmac1000_core.c
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
drivers/net/ethernet/stmicro/stmmac/stmmac.h
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c [new file with mode: 0644]
drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.h

index ec56bcf2db621c147fd29f8d90b346e18e736096..1681a8a2831354b15391fd6e38c6bdf551a1041f 100644 (file)
@@ -7,7 +7,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o  \
              dwmac4_dma.o dwmac4_lib.o dwmac4_core.o dwmac5.o hwif.o \
              stmmac_tc.o dwxgmac2_core.o dwxgmac2_dma.o dwxgmac2_descs.o \
              stmmac_xdp.o stmmac_est.o stmmac_fpe.o stmmac_vlan.o \
-             $(stmmac-y)
+             stmmac_pcs.o $(stmmac-y)
 
 stmmac-$(CONFIG_STMMAC_SELFTESTS) += stmmac_selftests.o
 
index d35db8958be15a3f469a8fd8f1d2a4b659f22d7c..571e4836244420c7a19004735756e402d953144b 100644 (file)
 #include "stmmac_ptp.h"
 #include "dwmac1000.h"
 
+static int dwmac1000_pcs_init(struct stmmac_priv *priv)
+{
+       if (!priv->dma_cap.pcs)
+               return 0;
+
+       return stmmac_integrated_pcs_init(priv, GMAC_PCS_BASE);
+}
+
 static void dwmac1000_core_init(struct mac_device_info *hw,
                                struct net_device *dev)
 {
@@ -435,6 +443,7 @@ static void dwmac1000_set_mac_loopback(void __iomem *ioaddr, bool enable)
 }
 
 const struct stmmac_ops dwmac1000_ops = {
+       .pcs_init = dwmac1000_pcs_init,
        .core_init = dwmac1000_core_init,
        .set_mac = stmmac_set_mac,
        .rx_ipc = dwmac1000_rx_ipc_enable,
index d855ab6b91458ec7b885cfb035a3f2d3a8975137..0b785389b7eff0dc19d796d7fcd8ee4f42f563b2 100644 (file)
 #include "dwmac4.h"
 #include "dwmac5.h"
 
+static int dwmac4_pcs_init(struct stmmac_priv *priv)
+{
+       if (!priv->dma_cap.pcs)
+               return 0;
+
+       return stmmac_integrated_pcs_init(priv, GMAC_PCS_BASE);
+}
+
 static void dwmac4_core_init(struct mac_device_info *hw,
                             struct net_device *dev)
 {
@@ -875,6 +883,7 @@ static int dwmac4_config_l4_filter(struct mac_device_info *hw, u32 filter_no,
 }
 
 const struct stmmac_ops dwmac4_ops = {
+       .pcs_init = dwmac4_pcs_init,
        .core_init = dwmac4_core_init,
        .update_caps = dwmac4_update_caps,
        .set_mac = stmmac_set_mac,
@@ -909,6 +918,7 @@ const struct stmmac_ops dwmac4_ops = {
 };
 
 const struct stmmac_ops dwmac410_ops = {
+       .pcs_init = dwmac4_pcs_init,
        .core_init = dwmac4_core_init,
        .update_caps = dwmac4_update_caps,
        .set_mac = stmmac_dwmac4_set_mac,
@@ -945,6 +955,7 @@ const struct stmmac_ops dwmac410_ops = {
 };
 
 const struct stmmac_ops dwmac510_ops = {
+       .pcs_init = dwmac4_pcs_init,
        .core_init = dwmac4_core_init,
        .update_caps = dwmac4_update_caps,
        .set_mac = stmmac_dwmac4_set_mac,
index ec8bddc1c37fe3cf3d22b1a397b07e2904c81ebc..aaeaf42084f0dd14ca1dadf31cd4facb4c914a37 100644 (file)
@@ -25,6 +25,8 @@
 #include <net/xdp.h>
 #include <uapi/linux/bpf.h>
 
+struct stmmac_pcs;
+
 struct stmmac_resources {
        void __iomem *addr;
        u8 mac[ETH_ALEN];
@@ -273,6 +275,8 @@ struct stmmac_priv {
        unsigned int pause_time;
        struct mii_bus *mii;
 
+       struct stmmac_pcs *integrated_pcs;
+
        struct phylink_config phylink_config;
        struct phylink *phylink;
 
index c041268d3a8d65b0bf42b5ae43ef709724d7fc92..5e6aaead589465ea43de707535422c2613812705 100644 (file)
@@ -46,6 +46,7 @@
 #include "stmmac_ptp.h"
 #include "stmmac_fpe.h"
 #include "stmmac.h"
+#include "stmmac_pcs.h"
 #include "stmmac_xdp.h"
 #include <linux/reset.h>
 #include <linux/of_mdio.h>
@@ -850,6 +851,13 @@ static struct phylink_pcs *stmmac_mac_select_pcs(struct phylink_config *config,
                        return pcs;
        }
 
+       /* The PCS control register is only relevant for SGMII, TBI and RTBI
+        * modes. We no longer support TBI or RTBI, so only configure this
+        * register when operating in SGMII mode with the integrated PCS.
+        */
+       if (priv->hw->pcs & STMMAC_PCS_SGMII && priv->integrated_pcs)
+               return &priv->integrated_pcs->pcs;
+
        return NULL;
 }
 
@@ -3487,13 +3495,6 @@ static int stmmac_hw_setup(struct net_device *dev)
                }
        }
 
-       /* The PCS control register is only relevant for SGMII, TBI and RTBI
-        * modes. We no longer support TBI or RTBI, so only configure this
-        * register when operating in SGMII mode with the integrated PCS.
-        */
-       if (priv->hw->pcs & STMMAC_PCS_SGMII)
-               stmmac_pcs_ctrl_ane(priv, 1, priv->hw->reverse_sgmii_enable);
-
        /* set TX and RX rings length */
        stmmac_set_rings_length(priv);
 
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pcs.c
new file mode 100644 (file)
index 0000000..50ea51d
--- /dev/null
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include "stmmac.h"
+#include "stmmac_pcs.h"
+
+static void dwmac_integrated_pcs_get_state(struct phylink_pcs *pcs,
+                                          unsigned int neg_mode,
+                                          struct phylink_link_state *state)
+{
+       state->link = false;
+}
+
+static int dwmac_integrated_pcs_config(struct phylink_pcs *pcs,
+                                      unsigned int neg_mode,
+                                      phy_interface_t interface,
+                                      const unsigned long *advertising,
+                                      bool permit_pause_to_mac)
+{
+       struct stmmac_pcs *spcs = phylink_pcs_to_stmmac_pcs(pcs);
+
+       dwmac_ctrl_ane(spcs->base, 0, 1, spcs->priv->hw->reverse_sgmii_enable);
+
+       return 0;
+}
+
+static const struct phylink_pcs_ops dwmac_integrated_pcs_ops = {
+       .pcs_get_state = dwmac_integrated_pcs_get_state,
+       .pcs_config = dwmac_integrated_pcs_config,
+};
+
+int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset)
+{
+       struct stmmac_pcs *spcs;
+
+       spcs = devm_kzalloc(priv->device, sizeof(*spcs), GFP_KERNEL);
+       if (!spcs)
+               return -ENOMEM;
+
+       spcs->priv = priv;
+       spcs->base = priv->ioaddr + offset;
+       spcs->pcs.ops = &dwmac_integrated_pcs_ops;
+
+       __set_bit(PHY_INTERFACE_MODE_SGMII, spcs->pcs.supported_interfaces);
+
+       priv->integrated_pcs = spcs;
+
+       return 0;
+}
index 5778f5b2f3139a48247d08deccd406dd67af634b..64397ac8ecab8ab173ffd54b6ab4c7b74c84aca8 100644 (file)
@@ -9,6 +9,7 @@
 #ifndef __STMMAC_PCS_H__
 #define __STMMAC_PCS_H__
 
+#include <linux/phylink.h>
 #include <linux/slab.h>
 #include <linux/io.h>
 #include "common.h"
 #define GMAC_ANE_RFE_SHIFT     12
 #define GMAC_ANE_ACK           BIT(14)
 
+struct stmmac_priv;
+
+struct stmmac_pcs {
+       struct stmmac_priv *priv;
+       void __iomem *base;
+       struct phylink_pcs pcs;
+};
+
+static inline struct stmmac_pcs *
+phylink_pcs_to_stmmac_pcs(struct phylink_pcs *pcs)
+{
+       return container_of(pcs, struct stmmac_pcs, pcs);
+}
+
+int stmmac_integrated_pcs_init(struct stmmac_priv *priv, unsigned int offset);
+
 /**
  * dwmac_pcs_isr - TBI, RTBI, or SGMII PHY ISR
  * @ioaddr: IO registers pointer