Thread (32 messages) 32 messages, 4 authors, 4d ago

Re: [PATCH net-next v9 00/12] net: pcs: Introduce support for fwnode PCS

From: Maxime Chevallier <maxime.chevallier@bootlin.com>
Date: 2026-07-21 11:58:46
Also in: linux-arm-kernel, linux-doc, linux-mediatek, lkml, netdev
Subsystem: marvell mvpp2 ethernet driver, networking drivers, the rest · Maintainers: Marcin Wojtas, Russell King, Andrew Lunn, "David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds

Hi Christian,

On 7/17/26 08:54, Christian Marangi wrote:
This series introduce a most awaited feature that is correctly
provide PCS with fwnode without having to use specific export symbol
and additional handling of PCS in phylink.
I was finally able to spend a bit of time digging deeper, I ported the
mvpp2 driver to your new API to test that dynamic PCS selection for
internal PCSs still works, and it's all good :)

Congrats on that work !

This didn't exercise all code paths, especially with the fwnode API but
you've tested that enough on your side :)

Maxime

The patch I used for testing if you're curious :

(I'll send that once this series land, or you can include it but I don't
want to delay your work in case the patch goes through rounds of reviews...)
--- 8>< -----------------------------------------------------------------
From 38ad94b1e62bf3523097983dfb515f59b1634477 Mon Sep 17 00:00:00 2001
From: Maxime Chevallier <maxime.chevallier@bootlin.com>
Date: Tue, 21 Jul 2026 13:52:57 +0200
Subject: [PATCH] net: marvell: mvpp2: Convert to the new PCS API

Following the introduction of the PCS framework, port mvpp2 to the new
PCS API.

Signed-off-by: Maxime Chevallier <maxime.chevallier@bootlin.com>
---
 .../net/ethernet/marvell/mvpp2/mvpp2_main.c   | 161 +++++++++++-------
 1 file changed, 95 insertions(+), 66 deletions(-)
diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
index ccc24a1301f2..8d9663c7a023 100644
--- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
+++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c
@@ -6499,21 +6499,6 @@ static void mvpp2_gmac_config(struct mvpp2_port *port, unsigned int mode,
 		writel(ctrl4, port->base + MVPP22_GMAC_CTRL_4_REG);
 }
 
-static struct phylink_pcs *mvpp2_select_pcs(struct phylink_config *config,
-					    phy_interface_t interface)
-{
-	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
-
-	/* Select the appropriate PCS operations depending on the
-	 * configured interface mode. We will only switch to a mode
-	 * that the validate() checks have already passed.
-	 */
-	if (mvpp2_is_xlg(interface))
-		return &port->pcs_xlg;
-	else
-		return &port->pcs_gmac;
-}
-
 static int mvpp2_mac_prepare(struct phylink_config *config, unsigned int mode,
 			     phy_interface_t interface)
 {
@@ -6786,7 +6771,6 @@ static int mvpp2_mac_enable_tx_lpi(struct phylink_config *config, u32 timer,
 }
 
 static const struct phylink_mac_ops mvpp2_phylink_ops = {
-	.mac_select_pcs = mvpp2_select_pcs,
 	.mac_prepare = mvpp2_mac_prepare,
 	.mac_config = mvpp2_mac_config,
 	.mac_finish = mvpp2_mac_finish,
@@ -6808,7 +6792,10 @@ static void mvpp2_acpi_start(struct mvpp2_port *port)
 	};
 	struct phylink_pcs *pcs;
 
-	pcs = mvpp2_select_pcs(&port->phylink_config, port->phy_interface);
+	if (mvpp2_is_xlg(port->phy_interface))
+		pcs = &port->pcs_xlg;
+	else
+		pcs = &port->pcs_gmac;
 
 	mvpp2_mac_prepare(&port->phylink_config, MLO_AN_INBAND,
 			  port->phy_interface);
@@ -6823,6 +6810,78 @@ static void mvpp2_acpi_start(struct mvpp2_port *port)
 			  SPEED_UNKNOWN, DUPLEX_UNKNOWN, false, false);
 }
 
+static int mvpp2_port_fill_pcs(struct phylink_config *config,
+			       struct phylink_pcs **available_pcs,
+			       unsigned int num_possible_pcs)
+{
+	struct mvpp2_port *port = mvpp2_phylink_to_port(config);
+
+	available_pcs[0] = &port->pcs_gmac;
+
+	if (mvpp2_port_supports_xlg(port)) {
+		if (num_possible_pcs < 2)
+			return -EINVAL;
+
+		available_pcs[1] = &port->pcs_xlg;
+	}
+
+	return 0;
+}
+
+static void mvpp2_port_init_pcs_xlg(struct phylink_pcs *pcs, bool has_comphy,
+				    phy_interface_t phy_mode)
+{
+	if (has_comphy) {
+		__set_bit(PHY_INTERFACE_MODE_5GBASER,
+			  pcs->supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_10GBASER,
+			  pcs->supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_XAUI,
+			  pcs->supported_interfaces);
+	} else if (phy_mode == PHY_INTERFACE_MODE_5GBASER) {
+		__set_bit(PHY_INTERFACE_MODE_5GBASER,
+			  pcs->supported_interfaces);
+	} else if (phy_mode == PHY_INTERFACE_MODE_10GBASER) {
+		__set_bit(PHY_INTERFACE_MODE_10GBASER,
+			  pcs->supported_interfaces);
+	} else if (phy_mode == PHY_INTERFACE_MODE_XAUI) {
+		__set_bit(PHY_INTERFACE_MODE_XAUI,
+			  pcs->supported_interfaces);
+	}
+}
+
+static void mvpp2_port_init_pcs_gmac(struct phylink_pcs *pcs, bool has_comphy,
+				     phy_interface_t phy_mode)
+{
+	if (has_comphy) {
+		/* If a COMPHY is present, we can support any of the
+		 * serdes modes and switch between them.
+		 */
+		__set_bit(PHY_INTERFACE_MODE_SGMII,
+			  pcs->supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_1000BASEX,
+			  pcs->supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_2500BASEX,
+			  pcs->supported_interfaces);
+	} else if (phy_mode == PHY_INTERFACE_MODE_2500BASEX) {
+		/* No COMPHY, with only 2500BASE-X mode supported */
+		__set_bit(PHY_INTERFACE_MODE_2500BASEX,
+			  pcs->supported_interfaces);
+	} else if (phy_mode == PHY_INTERFACE_MODE_1000BASEX ||
+		   phy_mode == PHY_INTERFACE_MODE_SGMII) {
+		/* No COMPHY, we can switch between 1000BASE-X and SGMII
+		 */
+		__set_bit(PHY_INTERFACE_MODE_1000BASEX,
+			  pcs->supported_interfaces);
+		__set_bit(PHY_INTERFACE_MODE_SGMII,
+			  pcs->supported_interfaces);
+	}
+
+	/* RGMII and MII are still routed through the gmac PCS */
+	phy_interface_set_rgmii(pcs->supported_interfaces);
+	__set_bit(PHY_INTERFACE_MODE_MII, pcs->supported_interfaces);
+}
+
 /* In order to ensure backward compatibility for ACPI, check if the port
  * firmware node comprises the necessary description allowing to use phylink.
  */
@@ -7082,28 +7141,17 @@ static int mvpp2_port_probe(struct platform_device *pdev,
 			port->phylink_config.mac_capabilities |=
 				MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
 
-		if (mvpp2_port_supports_xlg(port)) {
-			/* If a COMPHY is present, we can support any of
-			 * the serdes modes and switch between them.
-			 */
-			if (comphy) {
-				__set_bit(PHY_INTERFACE_MODE_5GBASER,
-					  port->phylink_config.supported_interfaces);
-				__set_bit(PHY_INTERFACE_MODE_10GBASER,
-					  port->phylink_config.supported_interfaces);
-				__set_bit(PHY_INTERFACE_MODE_XAUI,
-					  port->phylink_config.supported_interfaces);
-			} else if (phy_mode == PHY_INTERFACE_MODE_5GBASER) {
-				__set_bit(PHY_INTERFACE_MODE_5GBASER,
-					  port->phylink_config.supported_interfaces);
-			} else if (phy_mode == PHY_INTERFACE_MODE_10GBASER) {
-				__set_bit(PHY_INTERFACE_MODE_10GBASER,
-					  port->phylink_config.supported_interfaces);
-			} else if (phy_mode == PHY_INTERFACE_MODE_XAUI) {
-				__set_bit(PHY_INTERFACE_MODE_XAUI,
-					  port->phylink_config.supported_interfaces);
-			}
+		if (!mvpp2_port_supports_xlg(port))
+			port->phylink_config.num_possible_pcs = 1;
+		else
+			port->phylink_config.num_possible_pcs = 2;
+
+		port->phylink_config.fill_available_pcs = mvpp2_port_fill_pcs;
 
+		mvpp2_port_init_pcs_xlg(&port->pcs_xlg, comphy, phy_mode);
+		mvpp2_port_init_pcs_gmac(&port->pcs_gmac, comphy, phy_mode);
+
+		if (mvpp2_port_supports_xlg(port)) {
 			if (comphy)
 				port->phylink_config.mac_capabilities |=
 					MAC_10000FD | MAC_5000FD;
@@ -7115,35 +7163,16 @@ static int mvpp2_port_probe(struct platform_device *pdev,
 					MAC_10000FD;
 		}
 
-		if (mvpp2_port_supports_rgmii(port)) {
-			phy_interface_set_rgmii(port->phylink_config.supported_interfaces);
-			__set_bit(PHY_INTERFACE_MODE_MII,
-				  port->phylink_config.supported_interfaces);
-		}
+		phy_interface_copy(port->phylink_config.pcs_interfaces,
+				   port->pcs_gmac.supported_interfaces);
 
-		if (comphy) {
-			/* If a COMPHY is present, we can support any of the
-			 * serdes modes and switch between them.
-			 */
-			__set_bit(PHY_INTERFACE_MODE_SGMII,
-				  port->phylink_config.supported_interfaces);
-			__set_bit(PHY_INTERFACE_MODE_1000BASEX,
-				  port->phylink_config.supported_interfaces);
-			__set_bit(PHY_INTERFACE_MODE_2500BASEX,
-				  port->phylink_config.supported_interfaces);
-		} else if (phy_mode == PHY_INTERFACE_MODE_2500BASEX) {
-			/* No COMPHY, with only 2500BASE-X mode supported */
-			__set_bit(PHY_INTERFACE_MODE_2500BASEX,
-				  port->phylink_config.supported_interfaces);
-		} else if (phy_mode == PHY_INTERFACE_MODE_1000BASEX ||
-			   phy_mode == PHY_INTERFACE_MODE_SGMII) {
-			/* No COMPHY, we can switch between 1000BASE-X and SGMII
-			 */
-			__set_bit(PHY_INTERFACE_MODE_1000BASEX,
-				  port->phylink_config.supported_interfaces);
-			__set_bit(PHY_INTERFACE_MODE_SGMII,
-				  port->phylink_config.supported_interfaces);
-		}
+		if (mvpp2_port_supports_xlg(port))
+			phy_interface_or(port->phylink_config.pcs_interfaces,
+					 port->phylink_config.pcs_interfaces,
+					 port->pcs_xlg.supported_interfaces);
+
+		phy_interface_copy(port->phylink_config.supported_interfaces,
+				   port->phylink_config.pcs_interfaces);
 
 		phylink = phylink_create(&port->phylink_config, port_fwnode,
 					 phy_mode, &mvpp2_phylink_ops);
-- 
2.55.0

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help