Skip to contentSkip to conversation

net: dsa: always use phylink

RFC PATCH Superseded Russell King (Oracle) 9 participants 33 messages Jul 5, 2022 – Jul 8, 2022

Subsystems (18)
lore
Share & tools
lore

Russell King (Oracle)

author maintainer
#0 lore raw

v2 cover net: dsa: always use phylink

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

3. Patch 5 - now also removes the port_max_speed_mode() method

 drivers/net/dsa/b53/b53_common.c       |   3 +-
 drivers/net/dsa/bcm_sf2.c              |   3 +-
 drivers/net/dsa/hirschmann/hellcreek.c |   3 +-
 drivers/net/dsa/lantiq_gswip.c         |   6 +-
 drivers/net/dsa/microchip/ksz_common.c |   3 +-
 drivers/net/dsa/mt7530.c               |   3 +-
 drivers/net/dsa/mv88e6xxx/chip.c       | 136 +++++++++++++++---------------
 drivers/net/dsa/mv88e6xxx/chip.h       |   6 +-
 drivers/net/dsa/mv88e6xxx/port.c       |  32 -------
 drivers/net/dsa/mv88e6xxx/port.h       |   5 --
 drivers/net/dsa/ocelot/felix.c         |   3 +-
 drivers/net/dsa/qca/ar9331.c           |   3 +-
 drivers/net/dsa/qca8k.c                |   3 +-
 drivers/net/dsa/realtek/rtl8365mb.c    |   3 +-
 drivers/net/dsa/sja1105/sja1105_main.c |   3 +-
 drivers/net/dsa/xrs700x/xrs700x.c      |   3 +-
 drivers/net/phy/phylink.c              | 150 ++++++++++++++++++++++++++++++---
 include/linux/phylink.h                |   5 ++
 include/net/dsa.h                      |   3 +-
 net/dsa/port.c                         |  47 +++++++----
 20 files changed, 270 insertions(+), 153 deletions(-)
Quoted 102 lines · Russell King (Oracle)

Mostly the same as the previous RFC, except:

1) incldues the phylink_validate_mask_caps() function
2) has Marek's idea of searching the supported_interfaces bitmap for the fastest interface we can use
3) includes a final patch to add a print which will be useful to hear from people testing it.

Some of the questions from the original RFC remain though, so I've included that text below. I'm guessing as they remain unanswered that no one has any opinions on them?

 drivers/net/dsa/b53/b53_common.c       |   3 +-
 drivers/net/dsa/bcm_sf2.c              |   3 +-
 drivers/net/dsa/hirschmann/hellcreek.c |   3 +-
 drivers/net/dsa/lantiq_gswip.c         |   6 +-
 drivers/net/dsa/microchip/ksz_common.c |   3 +-
 drivers/net/dsa/mt7530.c               |   3 +-
 drivers/net/dsa/mv88e6xxx/chip.c       |  53 ++++--------
 drivers/net/dsa/ocelot/felix.c         |   3 +-
 drivers/net/dsa/qca/ar9331.c           |   3 +-
 drivers/net/dsa/qca8k.c                |   3 +-
 drivers/net/dsa/realtek/rtl8365mb.c    |   3 +-
 drivers/net/dsa/sja1105/sja1105_main.c |   3 +-
 drivers/net/dsa/xrs700x/xrs700x.c      |   3 +-
 drivers/net/phy/phylink.c              | 148 ++++++++++++++++++++++++++++++---
 include/linux/phylink.h                |   5 ++
 include/net/dsa.h                      |   3 +-
 net/dsa/port.c                         |  47 +++++++----
 17 files changed, 215 insertions(+), 80 deletions(-)
Quoted 65 lines · Russell King (Oracle)

Hi,

Currently, the core DSA code conditionally uses phylink for CPU and DSA ports depending on whether the firmware specifies a fixed-link or a PHY. If either of these are specified, then phylink is used for these ports, otherwise phylink is not, and we rely on the DSA drivers to "do the right thing". However, this detail is not mentioned in the DT binding, but Andrew has said that this behaviour has always something that DSA wants.

mv88e6xxx has had support for this for a long time with its "SPEED_MAX" thing, which I recently reworked to make use of the mac_capabilities in preparation to solving this more fully.

This series is an experiment to solve this properly, and it does this in two steps.

The first step consists of the first two patches. Phylink needs to know the PHY interface mode that is being used so it can (a) pass the right mode into the MAC/PCS etc and (b) know the properties of the link and therefore which speeds can be supported across it.

In order to achieve this, the DSA phylink_get_caps() method has an extra argument added to it so that DSA drivers can report the interface mode that they will be using for this port back to the core DSA code, thereby allowing phylink to be initialised with the correct interface mode.

Note that this can only be used for CPU and DSA ports as "user" ports need a different behaviour - they rely on getting the interface mode from phylib, which will only happen if phylink is initialised with PHY_INTERFACE_MODE_NA. Unfortunately, changing this behaviour is likely to cause widespread regressions.

Obvious questions:
1. Should phylink_get_caps() be augmented in this way, or should it be a separate method?

2. DSA has traditionally used "interface mode for the maximum supported speed on this port" where the interface mode is programmable (via its internal port_max_speed_mode() method) but this is only present for a few of the sub-drivers. Is reporting the current interface mode correct where this method is not implemented?

The second step is to introduce a function that allows phylink to be reconfigured after creation time to operate at max-speed fixed-link mode for the PHY interface mode, also using the MAC capabilities to determine the speed and duplex mode we should be using.

Obvious questions:
1. Should we be allowing half-duplex for this?
2. If we do allow half-duplex, should we prefer fastest speed over duplex setting, or should we prefer fastest full-duplex speed over any half-duplex?
3. How do we sanely switch DSA from its current behaviour to always using phylink for these ports without breakage - this is the difficult one, because it's not obvious which drivers have been coded to either work around this quirk of the DSA implementation. For example, if we start forcing the link down before calling dsa_port_phylink_create(), and we then fail to set max-fixed-link, then the CPU/DSA port is going to fail, and we're going to have lots of regressions.

Please look at the patches and make suggestions on how we can proceed to clean up this quirk of DSA.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
#1 lore raw

RFC PATCH 1/5 net: dsa: add support for retrieving the interface mode

DSA port bindings allow for an optional phy interface mode. When an interface mode is not specified, DSA uses the NA interface mode type.

However, phylink needs to know the parameters of the link, and this will become especially important when using phylink for ports that are devoid of all properties except the required "reg" property, so that phylink can select the maximum supported link settings. Without knowing the interface mode, phylink can't truely know the maximum link speed.

Update the prototype for the phylink_get_caps method to allow drivers to report this information back to DSA, and update all DSA implementations function declarations to cater for this change. No code is added to the implementations.

---
 drivers/net/dsa/b53/b53_common.c       |  3 ++-
 drivers/net/dsa/bcm_sf2.c              |  3 ++-
 drivers/net/dsa/hirschmann/hellcreek.c |  3 ++-
 drivers/net/dsa/lantiq_gswip.c         |  6 ++++--
 drivers/net/dsa/microchip/ksz_common.c |  3 ++-
 drivers/net/dsa/mt7530.c               |  3 ++-
 drivers/net/dsa/mv88e6xxx/chip.c       |  3 ++-
 drivers/net/dsa/ocelot/felix.c         |  3 ++-
 drivers/net/dsa/qca/ar9331.c           |  3 ++-
 drivers/net/dsa/qca8k.c                |  3 ++-
 drivers/net/dsa/realtek/rtl8365mb.c    |  3 ++-
 drivers/net/dsa/sja1105/sja1105_main.c |  3 ++-
 drivers/net/dsa/xrs700x/xrs700x.c      |  3 ++-
 include/net/dsa.h                      |  3 ++-
 net/dsa/port.c                         | 23 +++++++++++++++++------
 15 files changed, 47 insertions(+), 21 deletions(-)
drivers/net/dsa/b53/b53_common.c +2 -1
index 48cf344750ff..fe75b84ab791 100644
@@ -1310,7 +1310,8 @@ void b53_port_event(struct dsa_switch *ds, int port)
 EXPORT_SYMBOL(b53_port_event);
 
 static void b53_phylink_get_caps(struct dsa_switch *ds, int port,
-				 struct phylink_config *config)
+				 struct phylink_config *config,
+				 phy_interface_t *default_interface)
 {
 	struct b53_device *dev = ds->priv;
 
drivers/net/dsa/bcm_sf2.c +2 -1
index be0edfa093d0..18a3847bd82b 100644
@@ -713,7 +713,8 @@ static u32 bcm_sf2_sw_get_phy_flags(struct dsa_switch *ds, int port)
 }
 
 static void bcm_sf2_sw_get_caps(struct dsa_switch *ds, int port,
-				struct phylink_config *config)
+				struct phylink_config *config,
+				phy_interface_t *default_interface)
 {
 	unsigned long *interfaces = config->supported_interfaces;
 	struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds);
drivers/net/dsa/hirschmann/hellcreek.c +2 -1
index ac1f3b3a7040..ff78f580bb14 100644
@@ -1462,7 +1462,8 @@ static void hellcreek_teardown(struct dsa_switch *ds)
 }
 
 static void hellcreek_phylink_get_caps(struct dsa_switch *ds, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	struct hellcreek *hellcreek = ds->priv;
 
drivers/net/dsa/lantiq_gswip.c +4 -2
index e531b93f3cb2..a43dabfa5453 100644
@@ -1492,7 +1492,8 @@ static int gswip_port_change_mtu(struct dsa_switch *ds, int port, int new_mtu)
 }
 
 static void gswip_xrx200_phylink_get_caps(struct dsa_switch *ds, int port,
-					  struct phylink_config *config)
+					  struct phylink_config *config,
+					  phy_interface_t *default_interface)
 {
 	switch (port) {
 	case 0:
@@ -1525,7 +1526,8 @@ static void gswip_xrx200_phylink_get_caps(struct dsa_switch *ds, int port,
 }
 
 static void gswip_xrx300_phylink_get_caps(struct dsa_switch *ds, int port,
-					  struct phylink_config *config)
+					  struct phylink_config *config,
+					  phy_interface_t *default_interface)
 {
 	switch (port) {
 	case 0:
drivers/net/dsa/microchip/ksz_common.c +2 -1
index 28d7cb2ce98f..4329e29a1695 100644
@@ -721,7 +721,8 @@ static int ksz_check_device_id(struct ksz_device *dev)
 }
 
 static void ksz_phylink_get_caps(struct dsa_switch *ds, int port,
-				 struct phylink_config *config)
+				 struct phylink_config *config,
+				 phy_interface_t *default_interface)
 {
 	struct ksz_device *dev = ds->priv;
 
drivers/net/dsa/mt7530.c +2 -1
index 835807911be0..dab308e454e3 100644
@@ -2914,7 +2914,8 @@ mt7531_cpu_port_config(struct dsa_switch *ds, int port)
 }
 
 static void mt753x_phylink_get_caps(struct dsa_switch *ds, int port,
-				    struct phylink_config *config)
+				    struct phylink_config *config,
+				    phy_interface_t *default_interface)
 {
 	struct mt7530_priv *priv = ds->priv;
 
drivers/net/dsa/mv88e6xxx/chip.c +2 -1
index 37b649501500..f98be98551ef 100644
@@ -819,7 +819,8 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
 }
 
 static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
-			       struct phylink_config *config)
+			       struct phylink_config *config,
+			       phy_interface_t *default_interface)
 {
 	struct mv88e6xxx_chip *chip = ds->priv;
 
drivers/net/dsa/ocelot/felix.c +2 -1
index 859196898a7d..0c1ac902b110 100644
@@ -937,7 +937,8 @@ static int felix_vlan_del(struct dsa_switch *ds, int port,
 }
 
 static void felix_phylink_get_caps(struct dsa_switch *ds, int port,
-				   struct phylink_config *config)
+				   struct phylink_config *config,
+				   phy_interface_t *default_interface)
 {
 	struct ocelot *ocelot = ds->priv;
 
drivers/net/dsa/qca/ar9331.c +2 -1
index 0796b7cf8cae..19e95dabe5b9 100644
@@ -501,7 +501,8 @@ static enum dsa_tag_protocol ar9331_sw_get_tag_protocol(struct dsa_switch *ds,
 }
 
 static void ar9331_sw_phylink_get_caps(struct dsa_switch *ds, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	config->mac_capabilities = MAC_ASYM_PAUSE | MAC_SYM_PAUSE |
 		MAC_10 | MAC_100;
drivers/net/dsa/qca8k.c +2 -1
index 1cbb05b0323f..beccd8338c81 100644
@@ -1749,7 +1749,8 @@ qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
 }
 
 static void qca8k_phylink_get_caps(struct dsa_switch *ds, int port,
-				   struct phylink_config *config)
+				   struct phylink_config *config,
+				   phy_interface_t *default_interface)
 {
 	switch (port) {
 	case 0: /* 1st CPU port */
drivers/net/dsa/realtek/rtl8365mb.c +2 -1
index da31d8b839ac..7bf420c2b083 100644
@@ -1024,7 +1024,8 @@ static int rtl8365mb_ext_config_forcemode(struct realtek_priv *priv, int port,
 }
 
 static void rtl8365mb_phylink_get_caps(struct dsa_switch *ds, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	const struct rtl8365mb_extint *extint =
 		rtl8365mb_get_port_extint(ds->priv, port);
drivers/net/dsa/sja1105/sja1105_main.c +2 -1
index b253e27bcfb4..e15033177643 100644
@@ -1390,7 +1390,8 @@ static void sja1105_mac_link_up(struct dsa_switch *ds, int port,
 }
 
 static void sja1105_phylink_get_caps(struct dsa_switch *ds, int port,
-				     struct phylink_config *config)
+				     struct phylink_config *config,
+				     phy_interface_t *default_interface)
 {
 	struct sja1105_private *priv = ds->priv;
 	struct sja1105_xmii_params_entry *mii;
drivers/net/dsa/xrs700x/xrs700x.c +2 -1
index 3887ed33c5fe..214a1dd670c2 100644
@@ -443,7 +443,8 @@ static void xrs700x_teardown(struct dsa_switch *ds)
 }
 
 static void xrs700x_phylink_get_caps(struct dsa_switch *ds, int port,
-				     struct phylink_config *config)
+				     struct phylink_config *config,
+				     phy_interface_t *default_interface)
 {
 	switch (port) {
 	case 0:
include/net/dsa.h +2 -1
index b902b31bebce..7c6870d2c607 100644
@@ -852,7 +852,8 @@ struct dsa_switch_ops {
 	 * PHYLINK integration
 	 */
 	void	(*phylink_get_caps)(struct dsa_switch *ds, int port,
-				    struct phylink_config *config);
+				    struct phylink_config *config,
+				    phy_interface_t *default_interface);
 	void	(*phylink_validate)(struct dsa_switch *ds, int port,
 				    unsigned long *supported,
 				    struct phylink_link_state *state);
net/dsa/port.c +17 -6
index 3738f2d40a0b..35b4e1f8dc05 100644
@@ -1524,13 +1524,9 @@ static const struct phylink_mac_ops dsa_port_phylink_mac_ops = {
 int dsa_port_phylink_create(struct dsa_port *dp)
 {
 	struct dsa_switch *ds = dp->ds;
-	phy_interface_t mode;
+	phy_interface_t mode, def_mode;
 	int err;
 
-	err = of_get_phy_mode(dp->dn, &mode);
-	if (err)
-		mode = PHY_INTERFACE_MODE_NA;
-
 	/* Presence of phylink_mac_link_state or phylink_mac_an_restart is
 	 * an indicator of a legacy phylink driver.
 	 */
@@ -1538,8 +1534,23 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 	    ds->ops->phylink_mac_an_restart)
 		dp->pl_config.legacy_pre_march2020 = true;
 
+	def_mode = PHY_INTERFACE_MODE_NA;
 	if (ds->ops->phylink_get_caps)
-		ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config);
+		ds->ops->phylink_get_caps(ds, dp->index, &dp->pl_config,
+					  &def_mode);
+
+	err = of_get_phy_mode(dp->dn, &mode);
+	if (err) {
+		/* We must not set the default mode for user ports as a PHY
+		 * overrides the NA mode in phylink. Setting it here would
+		 * prevent the interface mode being updated.
+		 */
+		if (dp->type == DSA_PORT_TYPE_CPU ||
+		    dp->type == DSA_PORT_TYPE_DSA)
+			mode = def_mode;
+		else
+			mode = PHY_INTERFACE_MODE_NA;
+	}
 
 	dp->pl = phylink_create(&dp->pl_config, of_fwnode_handle(dp->dn),
 				mode, &dsa_port_phylink_mac_ops);
Signature · 1 line
2.30.2
#2 lore raw

RFC PATCH 2/5 net: dsa: mv88e6xxx: report the default interface mode for the port

In reply to Russell King (Oracle)

Report the maximum speed interface mode for the port, or if we don't have that information, the hardware configured interface mode for the port.

This allows phylink to know which interface mode CPU and DSA ports are operating, which will be necessary when we want to select the maximum speed for the port (required for such ports without a PHY or fixed-link specified in firmware.)

---
 drivers/net/dsa/mv88e6xxx/chip.c | 83 +++++++++++++++++++++++---------
 drivers/net/dsa/mv88e6xxx/chip.h |  3 +-
 2 files changed, 62 insertions(+), 24 deletions(-)
drivers/net/dsa/mv88e6xxx/chip.c +60 -23
index f98be98551ef..877407bc09de 100644
@@ -578,7 +578,8 @@ static const u8 mv88e6185_phy_interface_modes[] = {
 };
 
 static void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	u8 cmode = chip->ports[port].cmode;
 
@@ -588,23 +589,29 @@ static void mv88e6095_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
 		__set_bit(PHY_INTERFACE_MODE_MII, config->supported_interfaces);
 	} else {
 		if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
-		    mv88e6185_phy_interface_modes[cmode])
+		    mv88e6185_phy_interface_modes[cmode]) {
 			__set_bit(mv88e6185_phy_interface_modes[cmode],
 				  config->supported_interfaces);
+			*default_interface =
+				mv88e6185_phy_interface_modes[cmode];
+		}
 
 		config->mac_capabilities |= MAC_1000FD;
 	}
 }
 
 static void mv88e6185_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	u8 cmode = chip->ports[port].cmode;
 
 	if (cmode < ARRAY_SIZE(mv88e6185_phy_interface_modes) &&
-	    mv88e6185_phy_interface_modes[cmode])
+	    mv88e6185_phy_interface_modes[cmode]) {
 		__set_bit(mv88e6185_phy_interface_modes[cmode],
 			  config->supported_interfaces);
+		*default_interface = mv88e6185_phy_interface_modes[cmode];
+	}
 
 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
 				   MAC_1000FD;
@@ -616,6 +623,7 @@ static const u8 mv88e6xxx_phy_interface_modes[] = {
 	[MV88E6XXX_PORT_STS_CMODE_GMII]		= PHY_INTERFACE_MODE_GMII,
 	[MV88E6XXX_PORT_STS_CMODE_RMII_PHY]	= PHY_INTERFACE_MODE_RMII,
 	[MV88E6XXX_PORT_STS_CMODE_RMII]		= PHY_INTERFACE_MODE_RMII,
+	[MV88E6XXX_PORT_STS_CMODE_RGMII]	= PHY_INTERFACE_MODE_RGMII,
 	[MV88E6XXX_PORT_STS_CMODE_100BASEX]	= PHY_INTERFACE_MODE_100BASEX,
 	[MV88E6XXX_PORT_STS_CMODE_1000BASEX]	= PHY_INTERFACE_MODE_1000BASEX,
 	[MV88E6XXX_PORT_STS_CMODE_SGMII]	= PHY_INTERFACE_MODE_SGMII,
@@ -625,22 +633,32 @@ static const u8 mv88e6xxx_phy_interface_modes[] = {
 	 */
 };
 
-static void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported)
+static void mv88e6xxx_translate_cmode(u8 cmode, unsigned long *supported,
+				      phy_interface_t *default_interface)
 {
+	phy_interface_t interface;
+
 	if (cmode < ARRAY_SIZE(mv88e6xxx_phy_interface_modes) &&
-	    mv88e6xxx_phy_interface_modes[cmode])
-		__set_bit(mv88e6xxx_phy_interface_modes[cmode], supported);
-	else if (cmode == MV88E6XXX_PORT_STS_CMODE_RGMII)
-		phy_interface_set_rgmii(supported);
+	    mv88e6xxx_phy_interface_modes[cmode]) {
+		interface = mv88e6xxx_phy_interface_modes[cmode];
+		if (interface == PHY_INTERFACE_MODE_RGMII)
+			phy_interface_set_rgmii(supported);
+		else
+			__set_bit(interface, supported);
+		if (default_interface)
+			*default_interface = interface;
+	}
 }
 
 static void mv88e6250_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	unsigned long *supported = config->supported_interfaces;
 
 	/* Translate the default cmode */
-	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
+	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported,
+				  default_interface);
 
 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100;
 }
@@ -676,13 +694,15 @@ static int mv88e6352_get_port4_serdes_cmode(struct mv88e6xxx_chip *chip)
 }
 
 static void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	unsigned long *supported = config->supported_interfaces;
 	int err, cmode;
 
 	/* Translate the default cmode */
-	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
+	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported,
+				  default_interface);
 
 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
 				   MAC_1000FD;
@@ -702,19 +722,21 @@ static void mv88e6352_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
 			dev_err(chip->dev, "p%d: failed to read serdes cmode\n",
 				port);
 		else
-			mv88e6xxx_translate_cmode(cmode, supported);
+			mv88e6xxx_translate_cmode(cmode, supported, NULL);
 unlock:
 		mv88e6xxx_reg_unlock(chip);
 	}
 }
 
 static void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	unsigned long *supported = config->supported_interfaces;
 
 	/* Translate the default cmode */
-	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
+	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported,
+				  default_interface);
 
 	/* No ethtool bits for 200Mbps */
 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
@@ -726,17 +748,21 @@ static void mv88e6341_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
 		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
 		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
 
+		*default_interface = PHY_INTERFACE_MODE_2500BASEX;
+
 		config->mac_capabilities |= MAC_2500FD;
 	}
 }
 
 static void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-				       struct phylink_config *config)
+				       struct phylink_config *config,
+				       phy_interface_t *default_interface)
 {
 	unsigned long *supported = config->supported_interfaces;
 
 	/* Translate the default cmode */
-	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
+	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported,
+				  default_interface);
 
 	/* No ethtool bits for 200Mbps */
 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
@@ -748,16 +774,19 @@ static void mv88e6390_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
 		__set_bit(PHY_INTERFACE_MODE_1000BASEX, supported);
 		__set_bit(PHY_INTERFACE_MODE_2500BASEX, supported);
 
+		*default_interface = PHY_INTERFACE_MODE_2500BASEX;
+
 		config->mac_capabilities |= MAC_2500FD;
 	}
 }
 
 static void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-					struct phylink_config *config)
+					struct phylink_config *config,
+					phy_interface_t *default_interface)
 {
 	unsigned long *supported = config->supported_interfaces;
 
-	mv88e6390_phylink_get_caps(chip, port, config);
+	mv88e6390_phylink_get_caps(chip, port, config, default_interface);
 
 	/* For the 6x90X, ports 2-7 can be in automedia mode.
 	 * (Note that 6x90 doesn't support RXAUI nor XAUI).
@@ -783,18 +812,22 @@ static void mv88e6390x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
 		__set_bit(PHY_INTERFACE_MODE_XAUI, supported);
 		__set_bit(PHY_INTERFACE_MODE_RXAUI, supported);
 
+		*default_interface = PHY_INTERFACE_MODE_XAUI;
+
 		config->mac_capabilities |= MAC_10000FD;
 	}
 }
 
 static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
-					struct phylink_config *config)
+					struct phylink_config *config,
+					phy_interface_t *default_interface)
 {
 	unsigned long *supported = config->supported_interfaces;
 	bool is_6191x =
 		chip->info->prod_num == MV88E6XXX_PORT_SWITCH_ID_PROD_6191X;
 
-	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported);
+	mv88e6xxx_translate_cmode(chip->ports[port].cmode, supported,
+				  default_interface);
 
 	config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 |
 				   MAC_1000FD;
@@ -812,6 +845,8 @@ static void mv88e6393x_phylink_get_caps(struct mv88e6xxx_chip *chip, int port,
 			/* FIXME: USXGMII is not supported yet */
 			/* __set_bit(PHY_INTERFACE_MODE_USXGMII, supported); */
 
+			*default_interface = PHY_INTERFACE_MODE_10GBASER;
+
 			config->mac_capabilities |= MAC_2500FD | MAC_5000FD |
 				MAC_10000FD;
 		}
@@ -823,8 +858,10 @@ static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
 			       phy_interface_t *default_interface)
 {
 	struct mv88e6xxx_chip *chip = ds->priv;
+	u8 cmode = chip->ports[port].cmode;
 
-	chip->info->ops->phylink_get_caps(chip, port, config);
+	chip->info->ops->phylink_get_caps(chip, port, config,
+					  default_interface);
 
 	/* Internal ports need GMII for PHYLIB */
 	if (mv88e6xxx_phy_is_internal(ds, port))
drivers/net/dsa/mv88e6xxx/chip.h +2 -1
index e693154cf803..4518c17c1b9b 100644
@@ -643,7 +643,8 @@ struct mv88e6xxx_ops {
 
 	/* Phylink */
 	void (*phylink_get_caps)(struct mv88e6xxx_chip *chip, int port,
-				 struct phylink_config *config);
+				 struct phylink_config *config,
+				 phy_interface_t *default_interface);
 
 	/* Max Frame Size */
 	int (*set_max_frame_size)(struct mv88e6xxx_chip *chip, int mtu);
Signature · 1 line
2.30.2
Reviewed-by on v1 2/5
#3 lore raw

Re: [PATCH RFC net-next 2/5] net: dsa: mv88e6xxx: report the default interface mode for the port

Quoted 10 lines · On Tue, 05 Jul 2022 10:47:52 +0100 "Russell King (Oracle)"…

Report the maximum speed interface mode for the port, or if we don't have that information, the hardware configured interface mode for the port.

This allows phylink to know which interface mode CPU and DSA ports are operating, which will be necessary when we want to select the maximum speed for the port (required for such ports without a PHY or fixed-link specified in firmware.)

#4 lore raw

Re: [PATCH RFC net-next 2/5] net: dsa: mv88e6xxx: report the default interface mode for the port

In reply to Russell King (Oracle)
reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross #…

Hi "Russell,

[FYI, it's a private test report for your RFC patch.] [auto build test WARNING on net-next/master]

url:    https://github.com/intel-lab-lkp/linux/commits/Russell-King-Oracle/net-dsa-add-support-for-retrieving-the-interface-mode/20220705-175304
base:   https://git.kernel.org/pub/scm/linux/kernel/git/davem/net-next.git 874bdbfe624e577687c2053a26aab44715c68453
config: x86_64-randconfig-a012-20220704 (https://download.01.org/0day-ci/archive/20220706/[email protected]/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project f553287b588916de09c66e3e32bf75e5060f967f)

reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/9423b094f4b1e0c313bbdd0e65cd0824b51e3016
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Russell-King-Oracle/net-dsa-add-support-for-retrieving-the-interface-mode/20220705-175304 git checkout 9423b094f4b1e0c313bbdd0e65cd0824b51e3016
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=x86_64 SHELL=/bin/bash drivers/net/dsa/mv88e6xxx/

If you fix the issue, kindly add following tag where applicable

All warnings (new ones prefixed by >>):

>> drivers/net/dsa/mv88e6xxx/chip.c:861:5: warning: unused variable 'cmode' [-Wunused-variable]
           u8 cmode = chip->ports[port].cmode;
              ^

1 warning generated.

vim +/cmode +861 drivers/net/dsa/mv88e6xxx/chip.c

855
856 static void mv88e6xxx_get_caps(struct dsa_switch *ds, int port,
857 struct phylink_config *config,
858 phy_interface_t *default_interface)
859 {
860 struct mv88e6xxx_chip *chip = ds->priv;

 > 861		u8 cmode = chip->ports[port].cmode;

862
863 chip->info->ops->phylink_get_caps(chip, port, config,
864 default_interface);
865
866 /* Internal ports need GMII for PHYLIB */
867 if (mv88e6xxx_phy_is_internal(ds, port))
868 __set_bit(PHY_INTERFACE_MODE_GMII,
869 config->supported_interfaces);
870 }
871

Signature · 2 lines
0-DAY CI Kernel Test Service
https://01.org/lkp
#5 lore raw

RFC PATCH 3/5 net: phylink: split out interface to caps translation

In reply to Russell King (Oracle)

phylink_get_linkmodes() translates the interface mode into a set of speed and duplex capabilities which are masked with the MAC modes to then derive the link modes that are available.

Split out the initial transformation into a new function phylink_interface_to_caps(), which will be useful when setting the maximum fixed link speed.

---
 drivers/net/phy/phylink.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)
drivers/net/phy/phylink.c +19 -12
index 48f0b9b39491..2069fc902e19 100644
@@ -296,18 +296,7 @@ static void phylink_caps_to_linkmodes(unsigned long *linkmodes,
 	}
 }
 
-/**
- * phylink_get_linkmodes() - get acceptable link modes
- * @linkmodes: ethtool linkmode mask (must be already initialised)
- * @interface: phy interface mode defined by &typedef phy_interface_t
- * @mac_capabilities: bitmask of MAC capabilities
- *
- * Set all possible pause, speed and duplex linkmodes in @linkmodes that
- * are supported by the @interface mode and @mac_capabilities. @linkmodes
- * must have been initialised previously.
- */
-void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface,
-			   unsigned long mac_capabilities)
+static unsigned long phylink_interface_to_caps(phy_interface_t interface)
 {
 	unsigned long caps = MAC_SYM_PAUSE | MAC_ASYM_PAUSE;
 
@@ -381,6 +370,24 @@ void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface,
 		break;
 	}
 
+	return caps;
+}
+
+/**
+ * phylink_get_linkmodes() - get acceptable link modes
+ * @linkmodes: ethtool linkmode mask (must be already initialised)
+ * @interface: phy interface mode defined by &typedef phy_interface_t
+ * @mac_capabilities: bitmask of MAC capabilities
+ *
+ * Set all possible pause, speed and duplex linkmodes in @linkmodes that
+ * are supported by the @interface mode and @mac_capabilities. @linkmodes
+ * must have been initialised previously.
+ */
+void phylink_get_linkmodes(unsigned long *linkmodes, phy_interface_t interface,
+			   unsigned long mac_capabilities)
+{
+	unsigned long caps = phylink_interface_to_caps(interface);
+
 	phylink_caps_to_linkmodes(linkmodes, caps & mac_capabilities);
 }
 EXPORT_SYMBOL_GPL(phylink_get_linkmodes);
Signature · 1 line
2.30.2
#6 lore raw

RFC PATCH 4/5 net: phylink: add phylink_set_max_fixed_link()

In reply to Russell King (Oracle)

Add a function for DSA to use to configure phylink, in the absence of any other configuration, to a fixed link operating at the maximum supported link speed.

This is needed so we can support phylink usage on CPU and DSA ports.

We use the default interface that the DSA driver provides (if any) otherwise we attempt to find the first supported interface that gives the maximum speed for the link.

---
 drivers/net/phy/phylink.c | 119 ++++++++++++++++++++++++++++++++++++++
 include/linux/phylink.h   |   5 ++
 2 files changed, 124 insertions(+)
drivers/net/phy/phylink.c +119 -0
index 2069fc902e19..7ed3b2c3a359 100644
@@ -1333,6 +1333,125 @@ void phylink_destroy(struct phylink *pl)
 }
 EXPORT_SYMBOL_GPL(phylink_destroy);
 
+static struct {
+	unsigned long fd_mask;
+	unsigned long hd_mask;
+	int speed;
+} phylink_caps_speeds[] = {
+	{ MAC_400000FD, 0,          SPEED_400000 },
+	{ MAC_200000FD, 0,          SPEED_200000 },
+	{ MAC_100000FD, 0,          SPEED_100000 },
+	{ MAC_56000FD,  0,          SPEED_56000  },
+	{ MAC_50000FD,  0,          SPEED_50000  },
+	{ MAC_40000FD,  0,          SPEED_40000  },
+	{ MAC_25000FD,  0,          SPEED_40000  },
+	{ MAC_20000FD,  0,          SPEED_20000  },
+	{ MAC_10000FD,  0,          SPEED_10000  },
+	{ MAC_5000FD,   0,          SPEED_5000   },
+	{ MAC_2500FD,   0,          SPEED_2500   },
+	{ MAC_1000FD,   MAC_1000HD, SPEED_1000   },
+	{ MAC_100FD,    MAC_100HD,  SPEED_100    },
+	{ MAC_10FD,     MAC_10HD,   SPEED_10     },
+};
+
+/**
+ * phylink_set_max_fixed_link() - set a fixed link configuration for phylink
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ *
+ * Set a maximum speed fixed-link configuration for the chosen interface
+ * mode and MAC capabilities for the phylink instance. If the interface mode
+ * is PHY_INTERFACE_MODE_NA, then search the supported interfaces bitmap for
+ * the first interface that gives the fastest supported speed.
+ *
+ * This is only valid for use immediately after phylink_create(). Must not
+ * be used at any other time.
+ *
+ * The user must have initialised mac_capabilities and set a valid interface.
+ */
+int phylink_set_max_fixed_link(struct phylink *pl)
+{
+	phy_interface_t intf, interface;
+	unsigned long caps, max_caps;
+	unsigned long *interfaces;
+	int speed, duplex;
+	int i;
+
+	interface = pl->link_interface;
+
+	phylink_dbg(pl, "sif=%*pbl if=%d(%s) cap=%lx\n",
+		    (int)PHY_INTERFACE_MODE_MAX,
+		    pl->config->supported_interfaces,
+		    interface, phy_modes(interface),
+		    pl->config->mac_capabilities);
+
+	/* If we are not in PHY mode, or have a PHY, or have a SFP bus,
+	 * then we must not default to a fixed link.
+	 */
+	if (pl->cfg_link_an_mode != MLO_AN_PHY || pl->phydev || pl->sfp_bus)
+		return -EBUSY;
+
+	if (interface != PHY_INTERFACE_MODE_NA) {
+		/* Get the speed/duplex capabilities and reduce according to the
+		 * specified interface mode.
+		 */
+		caps = pl->config->mac_capabilities;
+		caps &= phylink_interface_to_caps(interface);
+	} else {
+		interfaces = pl->config->supported_interfaces;
+		max_caps = 0;
+
+		/* Find the supported interface mode which gives the maximum
+		 * speed.
+		 */
+		for_each_set_bit(intf, interfaces, PHY_INTERFACE_MODE_MAX) {
+			caps = pl->config->mac_capabilities;
+			caps &= phylink_interface_to_caps(intf);
+			if (caps > max_caps) {
+				max_caps = caps;
+				interface = intf;
+			}
+		}
+
+		caps = max_caps;
+	}
+
+	caps &= ~(MAC_SYM_PAUSE | MAC_ASYM_PAUSE);
+
+	/* If there are no capabilities, then we are not using this default. */
+	if (!caps)
+		return -EINVAL;
+
+	/* Decode to fastest speed and duplex */
+	duplex = DUPLEX_UNKNOWN;
+	speed = SPEED_UNKNOWN;
+	for (i = 0; i < ARRAY_SIZE(phylink_caps_speeds); i++) {
+		if (caps & phylink_caps_speeds[i].fd_mask) {
+			duplex = DUPLEX_FULL;
+			speed = phylink_caps_speeds[i].speed;
+			break;
+		} else if (caps & phylink_caps_speeds[i].hd_mask) {
+			duplex = DUPLEX_HALF;
+			speed = phylink_caps_speeds[i].speed;
+			break;
+		}
+	}
+
+	/* If we didn't find anything, bail. */
+	if (speed == SPEED_UNKNOWN)
+		return -EINVAL;
+
+	pl->link_interface = interface;
+	pl->link_config.interface = interface;
+	pl->link_config.speed = speed;
+	pl->link_config.duplex = duplex;
+	pl->link_config.link = 1;
+	pl->cfg_link_an_mode = MLO_AN_FIXED;
+	pl->cur_link_an_mode = MLO_AN_FIXED;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(phylink_set_max_fixed_link);
+
 static void phylink_phy_change(struct phy_device *phydev, bool up)
 {
 	struct phylink *pl = phydev->phylink;
include/linux/phylink.h +5 -0
index 6d06896fc20d..9e2fb476d19c 100644
@@ -23,6 +23,9 @@ enum {
 
 	MAC_SYM_PAUSE	= BIT(0),
 	MAC_ASYM_PAUSE	= BIT(1),
+	/* These speed bits must be sorted according to speed for
+	 * phylink_set_max_fixed_link()
+	 */
 	MAC_10HD	= BIT(2),
 	MAC_10FD	= BIT(3),
 	MAC_10		= MAC_10HD | MAC_10FD,
@@ -529,6 +532,8 @@ struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
 			       const struct phylink_mac_ops *mac_ops);
 void phylink_destroy(struct phylink *);
 
+int phylink_set_max_fixed_link(struct phylink *pl);
+
 int phylink_connect_phy(struct phylink *, struct phy_device *);
 int phylink_of_phy_connect(struct phylink *, struct device_node *, u32 flags);
 int phylink_fwnode_phy_connect(struct phylink *pl,
Signature · 1 line
2.30.2
Reviewed-by on v1 4/5
#7 lore raw

Re: [PATCH RFC net-next 4/5] net: phylink: add phylink_set_max_fixed_link()

Quoted 11 lines · On Tue, 05 Jul 2022 10:48:02 +0100 "Russell King (Oracle)"…

Add a function for DSA to use to configure phylink, in the absence of any other configuration, to a fixed link operating at the maximum supported link speed.

This is needed so we can support phylink usage on CPU and DSA ports.

We use the default interface that the DSA driver provides (if any) otherwise we attempt to find the first supported interface that gives the maximum speed for the link.

#8 lore raw

RFC PATCH 5/5 net: dsa: always use phylink for CPU and DSA ports

In reply to Russell King (Oracle)

Currently, we only use phylink for CPU and DSA ports if there is a fixed-link specification, or a PHY specified. The reason for this behaviour is that when neither is specified, there was no way for phylink to know the link parameters.

Now that we have phylink_set_max_link_speed() (which has become possible through the addition of mac_capabilities) we now have the ability to know the maximum link speed for a specific link, and can use phylink for this case as well.

However, we need all DSA drivers to provide mac_capabilities for this to work, and either report the default interface to be used for a port or have filled in supported_interfaces, so that we can select a maximum speed appropriate for the interface mode that hardware may have configured for the port. Any drivers that do not meet these requirements are likely to break.

This is especially important with the conversion of DSA drivers to phylink_pcs, as the PCS code only gets called if we are using phylink for the port.

---
 drivers/net/dsa/mv88e6xxx/chip.c | 50 ++++----------------------------
 drivers/net/dsa/mv88e6xxx/chip.h |  3 --
 drivers/net/dsa/mv88e6xxx/port.c | 32 --------------------
 drivers/net/dsa/mv88e6xxx/port.h |  5 ----
 net/dsa/port.c                   | 24 ++++++++-------
 5 files changed, 18 insertions(+), 96 deletions(-)
drivers/net/dsa/mv88e6xxx/chip.c +5 -45
index 877407bc09de..7fd89239a7a7 100644
@@ -3315,9 +3315,8 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
 {
 	struct device_node *phy_handle = NULL;
 	struct dsa_switch *ds = chip->ds;
-	phy_interface_t mode;
 	struct dsa_port *dp;
-	int tx_amp, speed;
+	int tx_amp;
 	int err;
 	u16 reg;
 
@@ -3326,40 +3325,10 @@ static int mv88e6xxx_setup_port(struct mv88e6xxx_chip *chip, int port)
 
 	dp = dsa_to_port(ds, port);
 
-	/* MAC Forcing register: don't force link, speed, duplex or flow control
-	 * state to any particular values on physical ports, but force the CPU
-	 * port and all DSA ports to their maximum bandwidth and full duplex.
-	 */
-	if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
-		unsigned long caps = dp->pl_config.mac_capabilities;
-
-		if (chip->info->ops->port_max_speed_mode)
-			mode = chip->info->ops->port_max_speed_mode(port);
-		else
-			mode = PHY_INTERFACE_MODE_NA;
-
-		if (caps & MAC_10000FD)
-			speed = SPEED_10000;
-		else if (caps & MAC_5000FD)
-			speed = SPEED_5000;
-		else if (caps & MAC_2500FD)
-			speed = SPEED_2500;
-		else if (caps & MAC_1000)
-			speed = SPEED_1000;
-		else if (caps & MAC_100)
-			speed = SPEED_100;
-		else
-			speed = SPEED_10;
-
-		err = mv88e6xxx_port_setup_mac(chip, port, LINK_FORCED_UP,
-					       speed, DUPLEX_FULL,
-					       PAUSE_OFF, mode);
-	} else {
-		err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
-					       SPEED_UNFORCED, DUPLEX_UNFORCED,
-					       PAUSE_ON,
-					       PHY_INTERFACE_MODE_NA);
-	}
+	err = mv88e6xxx_port_setup_mac(chip, port, LINK_UNFORCED,
+				       SPEED_UNFORCED, DUPLEX_UNFORCED,
+				       PAUSE_ON,
+				       PHY_INTERFACE_MODE_NA);
 	if (err)
 		return err;
 
@@ -4307,7 +4276,6 @@ static const struct mv88e6xxx_ops mv88e6141_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
 	.port_tag_remap = mv88e6095_port_tag_remap,
 	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
@@ -4700,7 +4668,6 @@ static const struct mv88e6xxx_ops mv88e6190_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
 	.port_tag_remap = mv88e6390_port_tag_remap,
 	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
@@ -4763,7 +4730,6 @@ static const struct mv88e6xxx_ops mv88e6190x_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
 	.port_tag_remap = mv88e6390_port_tag_remap,
 	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
@@ -4826,7 +4792,6 @@ static const struct mv88e6xxx_ops mv88e6191_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
 	.port_tag_remap = mv88e6390_port_tag_remap,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
 	.port_set_ucast_flood = mv88e6352_port_set_ucast_flood,
@@ -4991,7 +4956,6 @@ static const struct mv88e6xxx_ops mv88e6290_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
 	.port_tag_remap = mv88e6390_port_tag_remap,
 	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
@@ -5142,7 +5106,6 @@ static const struct mv88e6xxx_ops mv88e6341_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6341_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6341_port_max_speed_mode,
 	.port_tag_remap = mv88e6095_port_tag_remap,
 	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
@@ -5365,7 +5328,6 @@ static const struct mv88e6xxx_ops mv88e6390_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6390_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6390_port_max_speed_mode,
 	.port_tag_remap = mv88e6390_port_tag_remap,
 	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
@@ -5432,7 +5394,6 @@ static const struct mv88e6xxx_ops mv88e6390x_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6390x_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6390x_port_max_speed_mode,
 	.port_tag_remap = mv88e6390_port_tag_remap,
 	.port_set_policy = mv88e6352_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
@@ -5498,7 +5459,6 @@ static const struct mv88e6xxx_ops mv88e6393x_ops = {
 	.port_sync_link = mv88e6xxx_port_sync_link,
 	.port_set_rgmii_delay = mv88e6390_port_set_rgmii_delay,
 	.port_set_speed_duplex = mv88e6393x_port_set_speed_duplex,
-	.port_max_speed_mode = mv88e6393x_port_max_speed_mode,
 	.port_tag_remap = mv88e6390_port_tag_remap,
 	.port_set_policy = mv88e6393x_port_set_policy,
 	.port_set_frame_mode = mv88e6351_port_set_frame_mode,
drivers/net/dsa/mv88e6xxx/chip.h +0 -3
index 4518c17c1b9b..a3b7cfe3eb23 100644
@@ -502,9 +502,6 @@ struct mv88e6xxx_ops {
 	int (*port_set_speed_duplex)(struct mv88e6xxx_chip *chip, int port,
 				     int speed, int duplex);
 
-	/* What interface mode should be used for maximum speed? */
-	phy_interface_t (*port_max_speed_mode)(int port);
-
 	int (*port_tag_remap)(struct mv88e6xxx_chip *chip, int port);
 
 	int (*port_set_policy)(struct mv88e6xxx_chip *chip, int port,
drivers/net/dsa/mv88e6xxx/port.c +0 -32
index 90c55f23b7c9..47e21f3c437a 100644
@@ -333,14 +333,6 @@ int mv88e6341_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 					       duplex);
 }
 
-phy_interface_t mv88e6341_port_max_speed_mode(int port)
-{
-	if (port == 5)
-		return PHY_INTERFACE_MODE_2500BASEX;
-
-	return PHY_INTERFACE_MODE_NA;
-}
-
 /* Support 10, 100, 200, 1000 Mbps (e.g. 88E6352 family) */
 int mv88e6352_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 				    int speed, int duplex)
@@ -372,14 +364,6 @@ int mv88e6390_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 					       duplex);
 }
 
-phy_interface_t mv88e6390_port_max_speed_mode(int port)
-{
-	if (port == 9 || port == 10)
-		return PHY_INTERFACE_MODE_2500BASEX;
-
-	return PHY_INTERFACE_MODE_NA;
-}
-
 /* Support 10, 100, 200, 1000, 2500, 10000 Mbps (e.g. 88E6190X) */
 int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 				     int speed, int duplex)
@@ -394,14 +378,6 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 					       duplex);
 }
 
-phy_interface_t mv88e6390x_port_max_speed_mode(int port)
-{
-	if (port == 9 || port == 10)
-		return PHY_INTERFACE_MODE_XAUI;
-
-	return PHY_INTERFACE_MODE_NA;
-}
-
 /* Support 10, 100, 200, 1000, 2500, 5000, 10000 Mbps (e.g. 88E6393X)
  * Function mv88e6xxx_port_set_speed_duplex() can't be used as the register
  * values for speeds 2500 & 5000 conflict.
@@ -491,14 +467,6 @@ int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 	return 0;
 }
 
-phy_interface_t mv88e6393x_port_max_speed_mode(int port)
-{
-	if (port == 0 || port == 9 || port == 10)
-		return PHY_INTERFACE_MODE_10GBASER;
-
-	return PHY_INTERFACE_MODE_NA;
-}
-
 static int mv88e6xxx_port_set_cmode(struct mv88e6xxx_chip *chip, int port,
 				    phy_interface_t mode, bool force)
 {
drivers/net/dsa/mv88e6xxx/port.h +0 -5
index cb04243f37c1..2a5741a44e97 100644
@@ -357,11 +357,6 @@ int mv88e6390x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 int mv88e6393x_port_set_speed_duplex(struct mv88e6xxx_chip *chip, int port,
 				     int speed, int duplex);
 
-phy_interface_t mv88e6341_port_max_speed_mode(int port);
-phy_interface_t mv88e6390_port_max_speed_mode(int port);
-phy_interface_t mv88e6390x_port_max_speed_mode(int port);
-phy_interface_t mv88e6393x_port_max_speed_mode(int port);
-
 int mv88e6xxx_port_set_state(struct mv88e6xxx_chip *chip, int port, u8 state);
 
 int mv88e6xxx_port_set_vlan_map(struct mv88e6xxx_chip *chip, int port, u16 map);
net/dsa/port.c +13 -11
index 35b4e1f8dc05..34487e62eb03 100644
@@ -1525,6 +1525,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 {
 	struct dsa_switch *ds = dp->ds;
 	phy_interface_t mode, def_mode;
+	struct device_node *phy_np;
 	int err;
 
 	/* Presence of phylink_mac_link_state or phylink_mac_an_restart is
@@ -1559,6 +1560,13 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 		return PTR_ERR(dp->pl);
 	}
 
+	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) {
+		phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
+		of_node_put(phy_np);
+		if (!phy_np)
+			err = phylink_set_max_fixed_link(dp->pl);
+	}
+
 	return 0;
 }
 
@@ -1663,20 +1671,14 @@ static int dsa_port_phylink_register(struct dsa_port *dp)
 int dsa_port_link_register_of(struct dsa_port *dp)
 {
 	struct dsa_switch *ds = dp->ds;
-	struct device_node *phy_np;
 	int port = dp->index;
 
 	if (!ds->ops->adjust_link) {
-		phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
-		if (of_phy_is_fixed_link(dp->dn) || phy_np) {
-			if (ds->ops->phylink_mac_link_down)
-				ds->ops->phylink_mac_link_down(ds, port,
-					MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
-			of_node_put(phy_np);
-			return dsa_port_phylink_register(dp);
-		}
-		of_node_put(phy_np);
-		return 0;
+		if (ds->ops->phylink_mac_link_down)
+			ds->ops->phylink_mac_link_down(ds, port,
+				MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
+
+		return dsa_port_phylink_register(dp);
 	}
 
 	dev_warn(ds->dev,
Signature · 1 line
2.30.2
maintainer
#9 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Hello,

Quoted 13 lines · Russell King (Oracle)
net/dsa/port.c +1 -0
index 35b4e1f8dc05..34487e62eb03 100644
@@ -1525,6 +1525,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 {
 	struct dsa_switch *ds = dp->ds;
 	phy_interface_t mode, def_mode;
+	struct device_node *phy_np;
 	int err;
 
 	/* Presence of phylink_mac_link_state or phylink_mac_an_restart is

net/dsa/port.c int dsa_port_phylink_create(struct dsa_port *dp) · line 1567

Quoted 8 lines
net/dsa/port.c +5 -0
@@ -1559,6 +1560,13 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 		return PTR_ERR(dp->pl);
 	}
 
+	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) {
+		phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
+		of_node_put(phy_np);
+		if (!phy_np)
+			err = phylink_set_max_fixed_link(dp->pl);

Can we please limit phylink_set_max_link_speed() to just the CPU ports where a fixed-link property is also missing, not just a phy-handle? Although to be entirely correct, we can also have MLO_AN_INBAND, which wouldn't be covered by these 2 checks and would still represent a valid DT binding.

Quoted 16 lines
net/dsa/port.c +2 -4
+	}
+
 	return 0;
 }
 
@@ -1663,20 +1671,14 @@ static int dsa_port_phylink_register(struct dsa_port *dp)
 int dsa_port_link_register_of(struct dsa_port *dp)
 {
 	struct dsa_switch *ds = dp->ds;
-	struct device_node *phy_np;
 	int port = dp->index;
 
 	if (!ds->ops->adjust_link) {
-		phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
-		if (of_phy_is_fixed_link(dp->dn) || phy_np) {
-			if (ds->ops->phylink_mac_link_down)

net/dsa/port.c static int dsa_port_phylink_register(struct dsa_port *dp) · line 1679

Quoted 10 lines
net/dsa/port.c +3 -7
-				ds->ops->phylink_mac_link_down(ds, port,
-					MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);
-			of_node_put(phy_np);
-			return dsa_port_phylink_register(dp);
-		}
-		of_node_put(phy_np);
-		return 0;
+		if (ds->ops->phylink_mac_link_down)
+			ds->ops->phylink_mac_link_down(ds, port,
+				MLO_AN_FIXED, PHY_INTERFACE_MODE_NA);

Can you please align these arguments to the open bracket?

Quoted 8 lines
net/dsa/port.c +2 -0
+
+		return dsa_port_phylink_register(dp);
 	}
 
 	dev_warn(ds->dev,
Signature · 1 line
2.30.2
author maintainer
#10 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 19 lines · Vladimir Oltean

Hello,

Quoted 16 lines · Russell King (Oracle)
net/dsa/port.c +1 -0
index 35b4e1f8dc05..34487e62eb03 100644
@@ -1525,6 +1525,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 {
 	struct dsa_switch *ds = dp->ds;
 	phy_interface_t mode, def_mode;
+	struct device_node *phy_np;
 	int err;
 
 	/* Presence of phylink_mac_link_state or phylink_mac_an_restart is
@@ -1559,6 +1560,13 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 		return PTR_ERR(dp->pl);
 	}
 
Quoted 11 lines

net/dsa/port.c int dsa_port_phylink_create(struct dsa_port *dp) · line 1567

Quoted 5 lines
net/dsa/port.c +5 -0
+	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) {
+		phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
+		of_node_put(phy_np);
+		if (!phy_np)
+			err = phylink_set_max_fixed_link(dp->pl);

Can we please limit phylink_set_max_link_speed() to just the CPU ports where a fixed-link property is also missing, not just a phy-handle? Although to be entirely correct, we can also have MLO_AN_INBAND, which wouldn't be covered by these 2 checks and would still represent a valid DT binding.

phylink_set_max_fixed_link() already excludes itself:

        if (pl->cfg_link_an_mode != MLO_AN_PHY || pl->phydev || pl->sfp_bus)
                return -EBUSY;

intentionally so that if there is anything specified for the port, be that a fixed link or in-band, then phylink_set_max_fixed_link() errors out with -EBUSY.

The only case that it can't detect is if there is a PHY that may be added to phylink at a later time, and that is what the check above is for.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
author maintainer
#11 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 12 lines · Russell King (Oracle)
Quoted 5 lines · Vladimir Oltean

Can we please limit phylink_set_max_link_speed() to just the CPU ports where a fixed-link property is also missing, not just a phy-handle? Although to be entirely correct, we can also have MLO_AN_INBAND, which wouldn't be covered by these 2 checks and would still represent a valid DT binding.

phylink_set_max_fixed_link() already excludes itself:

        if (pl->cfg_link_an_mode != MLO_AN_PHY || pl->phydev || pl->sfp_bus)
                return -EBUSY;
Quoted 7 lines

intentionally so that if there is anything specified for the port, be that a fixed link or in-band, then phylink_set_max_fixed_link() errors out with -EBUSY.

The only case that it can't detect is if there is a PHY that may be added to phylink at a later time, and that is what the check above is for.

I've updated the function description to mention this detail:

+/**
+ * phylink_set_max_fixed_link() - set a fixed link configuration for phylink
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ *
+ * Set a maximum speed fixed-link configuration for the chosen interface mode
+ * and MAC capabilities for the phylink instance if the instance has not
+ * already been configured with a SFP, fixed link, or in-band AN mode. If the
+ * interface mode is PHY_INTERFACE_MODE_NA, then search the supported
+ * interfaces bitmap for the first interface that gives the fastest supported
+ * speed.

Does this address your concern?

Thanks.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
maintainer
#12 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 11 lines · Russell King (Oracle)
Quoted 10 lines · Russell King (Oracle)
Quoted 5 lines · Vladimir Oltean

Can we please limit phylink_set_max_link_speed() to just the CPU ports where a fixed-link property is also missing, not just a phy-handle? Although to be entirely correct, we can also have MLO_AN_INBAND, which wouldn't be covered by these 2 checks and would still represent a valid DT binding.

phylink_set_max_fixed_link() already excludes itself:

        if (pl->cfg_link_an_mode != MLO_AN_PHY || pl->phydev || pl->sfp_bus)
                                                      ~~~~~~~~~~

If not NULL, this is an SFP PHY, right? In other words, it's supposed to protect from phylink_sfp_connect_phy() - code involuntarily triggered by phylink_create() -> phylink_register_sfp() - and not from calls to phylink_{,fwnode_}connect_phy() that were initiated by the phylink user between phylink_create() and phylink_set_max_fixed_link(), correct? Those are specified as invalid in the kerneldoc and that's about it - that's not what the checking is for, correct?

But if so, why even check for pl->phydev, if you check for pl->sfp_bus?

Quoted 9 lines
Quoted 9 lines
                return -EBUSY;

intentionally so that if there is anything specified for the port, be that a fixed link or in-band, then phylink_set_max_fixed_link() errors out with -EBUSY.

The only case that it can't detect is if there is a PHY that may be added to phylink at a later time, and that is what the check above is for.

Here by "PHY added at a later time", you do mean calling phylink_{,fwnode_}connect_phy() after phylink_set_max_fixed_link(), right?

So this is what I don't understand. If we've called phylink_set_max_fixed_link() we've changed pl->cfg_link_an_mode to MLO_AN_FIXED and this will silently break future calls to phylink_{,fwnode_}connect_phy(), so DSA predicts if it's going to call either of those connect_phy() functions, and calls phylink_set_max_fixed_link() only if it won't. Right?

You've structured the checks in this "distributed" way because phylink can't really predict whether phylink_{,fwnode_}connect_phy() will be called after phylink_set_max_fixed_link(), right? I mean, it can probably predict the fwnode_ variant, but not phylink_connect_phy, and this is why it is up to the caller to decide when to call and when not to.

Quoted 13 lines

I've updated the function description to mention this detail:

+/**
+ * phylink_set_max_fixed_link() - set a fixed link configuration for phylink
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ *
+ * Set a maximum speed fixed-link configuration for the chosen interface mode
+ * and MAC capabilities for the phylink instance if the instance has not
+ * already been configured with a SFP, fixed link, or in-band AN mode. If the
+ * interface mode is PHY_INTERFACE_MODE_NA, then search the supported
+ * interfaces bitmap for the first interface that gives the fastest supported
+ * speed.

Quoted 3 lines

Does this address your concern?

Thanks.

Not really, no, sorry, it just confuses me more. It should maybe also say that this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later.

Can phylink absorb all this logic, and automatically call phylink_set_max_fixed_link() based on the following?

(1) struct phylink_config gets extended with a bool fallback_max_fixed_link.
(2) DSA CPU and DSA ports set this to true in dsa_port_phylink_register().
(3) phylink_set_max_fixed_link() is hooked into this -ENODEV error

    condition from phylink_fwnode_phy_connect():

	phy_fwnode = fwnode_get_phy_node(fwnode);
	if (IS_ERR(phy_fwnode)) {
		if (pl->cfg_link_an_mode == MLO_AN_PHY)
			return -ENODEV; <- here
		return 0;
	}
author maintainer
#13 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 12 lines · Vladimir Oltean
Quoted 11 lines · Russell King (Oracle)
Quoted 10 lines · Russell King (Oracle)
Quoted 5 lines · Vladimir Oltean

Can we please limit phylink_set_max_link_speed() to just the CPU ports where a fixed-link property is also missing, not just a phy-handle? Although to be entirely correct, we can also have MLO_AN_INBAND, which wouldn't be covered by these 2 checks and would still represent a valid DT binding.

phylink_set_max_fixed_link() already excludes itself:

        if (pl->cfg_link_an_mode != MLO_AN_PHY || pl->phydev || pl->sfp_bus)
Quoted 8 lines
                                                      ~~~~~~~~~~

If not NULL, this is an SFP PHY, right? In other words, it's supposed to protect from phylink_sfp_connect_phy() - code involuntarily triggered by phylink_create() -> phylink_register_sfp() - and not from calls to phylink_{,fwnode_}connect_phy() that were initiated by the phylink user between phylink_create() and phylink_set_max_fixed_link(), correct? Those are specified as invalid in the kerneldoc and that's about it - that's not what the checking is for, correct?

No, it's not to do with sfps at all, but to do with enforcing the pre-conditions for the function - that entire line is checking that
(a) we are in a sane state to be called, and (b) there is no configuration initialisation beyond the default done by phylink_create() - in other words, there is no in-band or fixed-link specified.

Let's go through this step by step.

1. pl->cfg_link_an_mode != MLO_AN_PHY
The default value for cfg_link_an_mode is MLO_AN_PHY. If it's anything other than that, then a fixed-link or in-band mode has been specified, and we don't want to override that. So this call needs to fail.

2. pl->phydev
If a PHY has been attached, then the pre-condition for calling this function immediately after phylink_create() has been violated, because the only way it can be non-NULL is if someone's called one of the phylink functions that connects a PHY. Note: SFPs will not set their PHY here, because, for them to discover that there's a PHY, the network interface needs to be up, and it will never be up here... but in any case...

3. pl->sfp_bus
If we have a SFP bus, then we definitely are not going to be operating in this default fixed-link mode - because the SFP is going to want to set its own parameters.

Quoted 6 lines
Quoted 6 lines
Quoted 6 lines
                return -EBUSY;

intentionally so that if there is anything specified for the port, be that a fixed link or in-band, then phylink_set_max_fixed_link() errors out with -EBUSY.

Quoted 6 lines
Quoted 3 lines
Quoted 3 lines

The only case that it can't detect is if there is a PHY that may be added to phylink at a later time, and that is what the check above is for.

Here by "PHY added at a later time", you do mean calling phylink_{,fwnode_}connect_phy() after phylink_set_max_fixed_link(), right?

Correct.

Quoted 11 lines

So this is what I don't understand. If we've called phylink_set_max_fixed_link() we've changed pl->cfg_link_an_mode to MLO_AN_FIXED and this will silently break future calls to phylink_{,fwnode_}connect_phy(), so DSA predicts if it's going to call either of those connect_phy() functions, and calls phylink_set_max_fixed_link() only if it won't. Right?

You've structured the checks in this "distributed" way because phylink can't really predict whether phylink_{,fwnode_}connect_phy() will be called after phylink_set_max_fixed_link(), right? I mean, it can probably predict the fwnode_ variant, but not phylink_connect_phy, and this is why it is up to the caller to decide when to call and when not to.

phylink has no idea whether phylink_fwnode_connect_phy() will be called with the same fwnode as phylink_create(), so it really can't make any assumptions about whether there will be a PHY or not.

Quoted 14 lines
Quoted 14 lines

I've updated the function description to mention this detail:

+/**
+ * phylink_set_max_fixed_link() - set a fixed link configuration for phylink
+ * @pl: a pointer to a &struct phylink returned from phylink_create()
+ *
+ * Set a maximum speed fixed-link configuration for the chosen interface mode
+ * and MAC capabilities for the phylink instance if the instance has not
+ * already been configured with a SFP, fixed link, or in-band AN mode. If the
+ * interface mode is PHY_INTERFACE_MODE_NA, then search the supported
+ * interfaces bitmap for the first interface that gives the fastest supported
+ * speed.

Quoted 5 lines
Quoted 3 lines

Does this address your concern?

Thanks.

Not really, no, sorry, it just confuses me more.

I find that happens a lot when I try to add more documentation to clarify things. I sometimes get to the point of deciding its better _not_ to write any documentation, because documentation just ends up being confusing and people want more and more detail.

I've got to the point in some case where I've had to spell out which keys to press on the keyboard for people to formulate the "[PATCH ...]" thing correctly, because if you put it in quotes, you get people who will include the quotes even if you tell them not to.

I hate documentation, I seem incapable of writing it in a way people can understand.

Quoted 3 lines

It should maybe also
say that this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later.

It's already a precondition that phylink_{,fwnode_}connect_phy() fail if we're in fixed-link mode (because PHYs have never been supported when in fixed-link mode - if one remembers, the old fixed-link code used to provide its own emulation of a PHY to make fixed-links work.) So PHYs and fixed-links have always been mutually exclusive before phylink, and continue to be so with phylink.

Quoted 6 lines

Can phylink absorb all this logic, and automatically call phylink_set_max_fixed_link() based on the following?

(1) struct phylink_config gets extended with a bool fallback_max_fixed_link.
(2) DSA CPU and DSA ports set this to true in dsa_port_phylink_register().
(3) phylink_set_max_fixed_link() is hooked into this -ENODEV error

Quoted 8 lines
    condition from phylink_fwnode_phy_connect():

	phy_fwnode = fwnode_get_phy_node(fwnode);
	if (IS_ERR(phy_fwnode)) {
		if (pl->cfg_link_an_mode == MLO_AN_PHY)
			return -ENODEV; <- here
		return 0;
	}

My question in response would be - why should this DSA specific behaviour be handled completely internally within phylink, when it's a DSA specific behaviour? Why do we need boolean flags for this?

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
maintainer
#14 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 29 lines · Russell King (Oracle)
Quoted 12 lines · Vladimir Oltean
Quoted 11 lines · Russell King (Oracle)
Quoted 10 lines · Russell King (Oracle)
Quoted 5 lines · Vladimir Oltean

Can we please limit phylink_set_max_link_speed() to just the CPU ports where a fixed-link property is also missing, not just a phy-handle? Although to be entirely correct, we can also have MLO_AN_INBAND, which wouldn't be covered by these 2 checks and would still represent a valid DT binding.

phylink_set_max_fixed_link() already excludes itself:

        if (pl->cfg_link_an_mode != MLO_AN_PHY || pl->phydev || pl->sfp_bus)
Quoted 8 lines
                                                      ~~~~~~~~~~

If not NULL, this is an SFP PHY, right? In other words, it's supposed to protect from phylink_sfp_connect_phy() - code involuntarily triggered by phylink_create() -> phylink_register_sfp() - and not from calls to phylink_{,fwnode_}connect_phy() that were initiated by the phylink user between phylink_create() and phylink_set_max_fixed_link(), correct? Those are specified as invalid in the kerneldoc and that's about it - that's not what the checking is for, correct?

No, it's not to do with sfps at all, but to do with enforcing the pre-conditions for the function - that entire line is checking that
(a) we are in a sane state to be called, and (b) there is no configuration initialisation beyond the default done by phylink_create() - in other words, there is no in-band or fixed-link specified.

Quoted 7 lines

Let's go through this step by step.

1. pl->cfg_link_an_mode != MLO_AN_PHY
The default value for cfg_link_an_mode is MLO_AN_PHY. If it's anything other than that, then a fixed-link or in-band mode has been specified, and we don't want to override that. So this call needs to fail.

Thanks for the explanation.

Yes, I noticed that phylink_set_max_fixed_link() relies on the fact that pl->cfg_link_an_mode has the unset value of 0, which coincidentally is MLO_AN_PHY.

Quoted 8 lines

2. pl->phydev
If a PHY has been attached, then the pre-condition for calling this function immediately after phylink_create() has been violated, because the only way it can be non-NULL is if someone's called one of the phylink functions that connects a PHY. Note: SFPs will not set their PHY here, because, for them to discover that there's a PHY, the network interface needs to be up, and it will never be up here... but in any case...

Ok, so this does check for a precondition that the caller did something correctly. But it doesn't (and can't) check that all preconditions and postconditions are satisfied. That's one of my irks, why bother checking the easy to satisfy precondition (which depends on the code organization, static information, easy to check), and give up on the hard one (which depends on the device tree blob, dynamic information, not so easy).

Quoted 12 lines
Quoted 11 lines

So this is what I don't understand. If we've called phylink_set_max_fixed_link() we've changed pl->cfg_link_an_mode to MLO_AN_FIXED and this will silently break future calls to phylink_{,fwnode_}connect_phy(), so DSA predicts if it's going to call either of those connect_phy() functions, and calls phylink_set_max_fixed_link() only if it won't. Right?

You've structured the checks in this "distributed" way because phylink can't really predict whether phylink_{,fwnode_}connect_phy() will be called after phylink_set_max_fixed_link(), right? I mean, it can probably predict the fwnode_ variant, but not phylink_connect_phy, and this is why it is up to the caller to decide when to call and when not to.

Quoted 3 lines

phylink has no idea whether phylink_fwnode_connect_phy() will be called with the same fwnode as phylink_create(), so it really can't make any assumptions about whether there will be a PHY or not.

This is interesting. Is there a use case for passing a different fwnode_handle to the 2 functions?

Quoted 10 lines
Quoted 3 lines

It should maybe also
say that this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later.

It's already a precondition that phylink_{,fwnode_}connect_phy() fail if we're in fixed-link mode (because PHYs have never been supported when in fixed-link mode - if one remembers, the old fixed-link code used to provide its own emulation of a PHY to make fixed-links work.) So PHYs and fixed-links have always been mutually exclusive before phylink, and continue to be so with phylink.

Define "fail" exactly, because if I look in phylink_fwnode_phy_connect(), I see:

	/* Fixed links and 802.3z are handled without needing a PHY */
	if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
	    (pl->cfg_link_an_mode == MLO_AN_INBAND &&
	     phy_interface_mode_is_8023z(pl->link_interface)))
		return 0; <- does this count as failure?

This is why dsa_port_phylink_register() calls phylink_of_phy_connect() without checking whether it has a fixed-link or a PHY, because it doesn't fail even if it doesn't do anything.

In fact I've wanted to make a correction to my previous phrasing that "this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later". The correction is "... with a phy-handle".

Quoted 15 lines
Quoted 6 lines

Can phylink absorb all this logic, and automatically call phylink_set_max_fixed_link() based on the following?

(1) struct phylink_config gets extended with a bool fallback_max_fixed_link.
(2) DSA CPU and DSA ports set this to true in dsa_port_phylink_register().
(3) phylink_set_max_fixed_link() is hooked into this -ENODEV error

Quoted 8 lines
    condition from phylink_fwnode_phy_connect():

	phy_fwnode = fwnode_get_phy_node(fwnode);
	if (IS_ERR(phy_fwnode)) {
		if (pl->cfg_link_an_mode == MLO_AN_PHY)
			return -ENODEV; <- here
		return 0;
	}
Quoted 3 lines

My question in response would be - why should this DSA specific behaviour be handled completely internally within phylink, when it's a DSA specific behaviour? Why do we need boolean flags for this?

Because the end result will be simpler if we respect the separation of concerns that continues to exist, and it's still phylink's business to say what is and isn't valid. DSA still isn't aware of the bindings required by phylink, it just passes its fwnode to it. Practically speaking, I wouldn't be scratching my head as to why we're checking for half the prerequisites of phylink_set_max_fixed_link() in one place and for the other half in another.

True, through this patch set DSA is creating its own context specific extension of phylink bindings, but arguably those existed before DSA was even integrated with phylink, and we're just fixing something now we didn't realize at the time we'd need to do.

I can reverse the question, why would phylink even want to be involved in how the max fixed link parameters are deduced, and it doesn't just require that a fixed-link software node is constructed somehow (irrelevant to phylink how), and phylink is just modified to find and work with that if it exists? Isn't it for the exact same reason, separation of concerns, that it's easiest for phylink to figure out what is the most appropriate maximum fixed-link configuration?

author maintainer
#15 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 24 lines · Vladimir Oltean
Quoted 7 lines · Russell King (Oracle)

Let's go through this step by step.

1. pl->cfg_link_an_mode != MLO_AN_PHY
The default value for cfg_link_an_mode is MLO_AN_PHY. If it's anything other than that, then a fixed-link or in-band mode has been specified, and we don't want to override that. So this call needs to fail.

Thanks for the explanation.

Yes, I noticed that phylink_set_max_fixed_link() relies on the fact that pl->cfg_link_an_mode has the unset value of 0, which coincidentally is MLO_AN_PHY.

Quoted 8 lines

2. pl->phydev
If a PHY has been attached, then the pre-condition for calling this function immediately after phylink_create() has been violated, because the only way it can be non-NULL is if someone's called one of the phylink functions that connects a PHY. Note: SFPs will not set their PHY here, because, for them to discover that there's a PHY, the network interface needs to be up, and it will never be up here... but in any case...

Quoted 6 lines

Ok, so this does check for a precondition that the caller did something correctly. But it doesn't (and can't) check that all preconditions and postconditions are satisfied. That's one of my irks, why bother checking the easy to satisfy precondition (which depends on the code organization, static information, easy to check), and give up on the hard one (which depends on the device tree blob, dynamic information, not so easy).

So what you're asking is: why bother doing any checks if you can't do all of them?

My response would be: isn't best effort better than doing nothing?

In my mind, it is best effort, because:

a) if you've called it when the preconditions (with the exception of a future PHY) are not satisfied, then it fails with -EBUSY.
b) if this call succeeds, then it locks out the future ability to bind a PHY.

So, if one forgets to check whether there'll be a future PHY, and call this anyway, then a future attempt to bind a PHY to phylink fails and you get a failure.

Considering that we are only talking about DSA making use of this (no other network driver has this behaviour) and this is being handled by core DSA code, we could label this up as "this is for DSA use only."

Quoted 12 lines
Quoted 12 lines
Quoted 11 lines

So this is what I don't understand. If we've called phylink_set_max_fixed_link() we've changed pl->cfg_link_an_mode to MLO_AN_FIXED and this will silently break future calls to phylink_{,fwnode_}connect_phy(), so DSA predicts if it's going to call either of those connect_phy() functions, and calls phylink_set_max_fixed_link() only if it won't. Right?

You've structured the checks in this "distributed" way because phylink can't really predict whether phylink_{,fwnode_}connect_phy() will be called after phylink_set_max_fixed_link(), right? I mean, it can probably predict the fwnode_ variant, but not phylink_connect_phy, and this is why it is up to the caller to decide when to call and when not to.

Quoted 6 lines
Quoted 3 lines

phylink has no idea whether phylink_fwnode_connect_phy() will be called with the same fwnode as phylink_create(), so it really can't make any assumptions about whether there will be a PHY or not.

This is interesting. Is there a use case for passing a different fwnode_handle to the 2 functions?

That depends on the driver. It looks like drivers/net/ethernet/ti/am65-cpsw-nuss.c may well pass in different nodes in the firmware tree.

Quoted 11 lines
Quoted 10 lines
Quoted 3 lines

It should maybe also
say that this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later.

It's already a precondition that phylink_{,fwnode_}connect_phy() fail if we're in fixed-link mode (because PHYs have never been supported when in fixed-link mode - if one remembers, the old fixed-link code used to provide its own emulation of a PHY to make fixed-links work.) So PHYs and fixed-links have always been mutually exclusive before phylink, and continue to be so with phylink.

Quoted 7 lines

Define "fail" exactly, because if I look in phylink_fwnode_phy_connect(), I see:

	/* Fixed links and 802.3z are handled without needing a PHY */
	if (pl->cfg_link_an_mode == MLO_AN_FIXED ||
	    (pl->cfg_link_an_mode == MLO_AN_INBAND &&
	     phy_interface_mode_is_8023z(pl->link_interface)))
		return 0; <- does this count as failure?

Sorry, yes, that is correct - it ignores the attempt (so drivers don't have to conditionalise the call for this everywhere.)

Quoted 7 lines

This is why dsa_port_phylink_register() calls phylink_of_phy_connect() without checking whether it has a fixed-link or a PHY, because it doesn't fail even if it doesn't do anything.

In fact I've wanted to make a correction to my previous phrasing that "this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later". The correction is "... with a phy-handle".

I'm not sure that clarification makes sense when talking about phylink_connect_phy(), so I think if you're clarifying it with a firmware property, you're only talking about phylink_fwnode_connect_phy() now?

Quoted 32 lines
Quoted 15 lines
Quoted 6 lines

Can phylink absorb all this logic, and automatically call phylink_set_max_fixed_link() based on the following?

(1) struct phylink_config gets extended with a bool fallback_max_fixed_link.
(2) DSA CPU and DSA ports set this to true in dsa_port_phylink_register().
(3) phylink_set_max_fixed_link() is hooked into this -ENODEV error

Quoted 8 lines
    condition from phylink_fwnode_phy_connect():

	phy_fwnode = fwnode_get_phy_node(fwnode);
	if (IS_ERR(phy_fwnode)) {
		if (pl->cfg_link_an_mode == MLO_AN_PHY)
			return -ENODEV; <- here
		return 0;
	}
Quoted 3 lines

My question in response would be - why should this DSA specific behaviour be handled completely internally within phylink, when it's a DSA specific behaviour? Why do we need boolean flags for this?

Because the end result will be simpler if we respect the separation of concerns that continues to exist, and it's still phylink's business to say what is and isn't valid. DSA still isn't aware of the bindings required by phylink, it just passes its fwnode to it. Practically speaking, I wouldn't be scratching my head as to why we're checking for half the prerequisites of phylink_set_max_fixed_link() in one place and for the other half in another.

True, through this patch set DSA is creating its own context specific extension of phylink bindings, but arguably those existed before DSA was even integrated with phylink, and we're just fixing something now we didn't realize at the time we'd need to do.

Quoted 7 lines

I can reverse the question, why would phylink even want to be involved in how the max fixed link parameters are deduced, and it doesn't just require that a fixed-link software node is constructed somehow (irrelevant to phylink how), and phylink is just modified to find and work with that if it exists? Isn't it for the exact same reason, separation of concerns, that it's easiest for phylink to figure out what is the most appropriate maximum fixed-link configuration?

If that could be done, I'd love it, because then we don't have this in phylink at all, and it can all be a DSA problem to solve. It also means that others won't be tempted to use the interface incorrectly.

I'm not sure how practical that is when we have both DT and ACPI to deal with, and ACPI is certainly out of my knowledge area to be able to construct a software node to specify a fixed-link. Maybe it can be done at the fwnode layer? I don't know.

Do you have a handy example of what you're suggesting?

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
maintainer
#16 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 4 lines · Russell King (Oracle)
Quoted 4 lines

This is why dsa_port_phylink_register() calls phylink_of_phy_connect() without checking whether it has a fixed-link or a PHY, because it doesn't fail even if it doesn't do anything.

Quoted 8 lines
Quoted 3 lines

In fact I've wanted to make a correction to my previous phrasing that "this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later". The correction is "... with a phy-handle".

I'm not sure that clarification makes sense when talking about phylink_connect_phy(), so I think if you're clarifying it with a firmware property, you're only talking about phylink_fwnode_connect_phy() now?

Yes, it's super hard to verbalize, and this is the reason why I didn't add "... with a phy-handle" in the first place.

I wanted to say: phylink_connect_phy(), OR phylink_fwnode_connect_phy() WITH a phy-handle. I shouldn't have conflated them in the first place.

Quoted 40 lines
Quoted 32 lines
Quoted 15 lines
Quoted 6 lines

Can phylink absorb all this logic, and automatically call phylink_set_max_fixed_link() based on the following?

(1) struct phylink_config gets extended with a bool fallback_max_fixed_link.
(2) DSA CPU and DSA ports set this to true in dsa_port_phylink_register().
(3) phylink_set_max_fixed_link() is hooked into this -ENODEV error

Quoted 8 lines
    condition from phylink_fwnode_phy_connect():

	phy_fwnode = fwnode_get_phy_node(fwnode);
	if (IS_ERR(phy_fwnode)) {
		if (pl->cfg_link_an_mode == MLO_AN_PHY)
			return -ENODEV; <- here
		return 0;
	}
Quoted 3 lines

My question in response would be - why should this DSA specific behaviour be handled completely internally within phylink, when it's a DSA specific behaviour? Why do we need boolean flags for this?

Because the end result will be simpler if we respect the separation of concerns that continues to exist, and it's still phylink's business to say what is and isn't valid. DSA still isn't aware of the bindings required by phylink, it just passes its fwnode to it. Practically speaking, I wouldn't be scratching my head as to why we're checking for half the prerequisites of phylink_set_max_fixed_link() in one place and for the other half in another.

True, through this patch set DSA is creating its own context specific extension of phylink bindings, but arguably those existed before DSA was even integrated with phylink, and we're just fixing something now we didn't realize at the time we'd need to do.

Quoted 7 lines

I can reverse the question, why would phylink even want to be involved in how the max fixed link parameters are deduced, and it doesn't just require that a fixed-link software node is constructed somehow (irrelevant to phylink how), and phylink is just modified to find and work with that if it exists? Isn't it for the exact same reason, separation of concerns, that it's easiest for phylink to figure out what is the most appropriate maximum fixed-link configuration?

Quoted 8 lines

If that could be done, I'd love it, because then we don't have this in phylink at all, and it can all be a DSA problem to solve. It also means that others won't be tempted to use the interface incorrectly.

I'm not sure how practical that is when we have both DT and ACPI to deal with, and ACPI is certainly out of my knowledge area to be able to construct a software node to specify a fixed-link. Maybe it can be done at the fwnode layer? I don't know.

I don't want to be misunderstood. I brought up software nodes because I'm sure you must have thought about this too, before proposing what you did here. And unless there's a technical reason against software nodes (which there doesn't appear to be, but I don't want to get ahead of myself), I figured you must be OK with phylink absorbing the logic, case in which I just don't understand why you are pushing back on a proposal how to make phylink absorb the logic completely.

Quoted 1 line

Do you have a handy example of what you're suggesting?

No, I didn't, but I thought, how hard can it be, and here's a hacked up attempt on one of my boards:

From 5d002f03c91b357be304d41f7422969d0dd89f5b Mon Sep 17 00:00:00 2001
From: Vladimir Oltean <[email protected]>
Date: Thu, 7 Jul 2022 21:04:32 +0300
Subject: [PATCH] dsa_port_fixup_broken_dt

---
 arch/arm/boot/dts/ls1021a-tsn.dts      |  5 --
 drivers/base/swnode.c                  | 14 +++-
 drivers/net/dsa/sja1105/sja1105_main.c |  4 +-
 include/linux/property.h               |  4 ++
 net/dsa/dsa_priv.h                     |  2 +-
 net/dsa/port.c                         | 99 +++++++++++++++++++++-----
 net/dsa/slave.c                        |  2 +-
 7 files changed, 100 insertions(+), 30 deletions(-)
arch/arm/boot/dts/ls1021a-tsn.dts +0 -5
index 1ea32fff4120..c577f90057c7 100644
@@ -94,11 +94,6 @@ port@4 {
 				rx-internal-delay-ps = <0>;
 				tx-internal-delay-ps = <0>;
 				reg = <4>;
-
-				fixed-link {
-					speed = <1000>;
-					full-duplex;
-				};
 			};
 		};
 	};
drivers/base/swnode.c +12 -2
index 0a482212c7e8..b2ea08f0e898 100644
@@ -972,8 +972,9 @@ void software_node_unregister(const struct software_node *node)
 EXPORT_SYMBOL_GPL(software_node_unregister);
 
 struct fwnode_handle *
-fwnode_create_software_node(const struct property_entry *properties,
-			    const struct fwnode_handle *parent)
+fwnode_create_named_software_node(const struct property_entry *properties,
+				  const struct fwnode_handle *parent,
+				  const char *name)
 {
 	struct fwnode_handle *fwnode;
 	struct software_node *node;
@@ -991,6 +992,7 @@ fwnode_create_software_node(const struct property_entry *properties,
 		return ERR_CAST(node);
 
 	node->parent = p ? p->node : NULL;
+	node->name = name;
 
 	fwnode = swnode_register(node, p, 1);
 	if (IS_ERR(fwnode))
@@ -998,6 +1000,14 @@ fwnode_create_software_node(const struct property_entry *properties,
 
 	return fwnode;
 }
+EXPORT_SYMBOL_GPL(fwnode_create_named_software_node);
+
+struct fwnode_handle *
+fwnode_create_software_node(const struct property_entry *properties,
+			    const struct fwnode_handle *parent)
+{
+	return fwnode_create_named_software_node(properties, parent, NULL);
+}
 EXPORT_SYMBOL_GPL(fwnode_create_software_node);
 
 void fwnode_remove_software_node(struct fwnode_handle *fwnode)
drivers/net/dsa/sja1105/sja1105_main.c +2 -2
index b253e27bcfb4..6c7deebc8d76 100644
@@ -1218,8 +1218,8 @@ static int sja1105_parse_ports_node(struct sja1105_private *priv,
 			if (!of_phy_is_fixed_link(child)) {
 				dev_err(dev, "phy-handle or fixed-link "
 					"properties missing!\n");
-				of_node_put(child);
-				return -ENODEV;
+//				of_node_put(child);
+//				return -ENODEV;
 			}
 			/* phy-handle is missing, but fixed-link isn't.
 			 * So it's a fixed link. Default to PHY role.
include/linux/property.h +4 -0
index a5b429d623f6..23330ae2b1fa 100644
@@ -492,6 +492,10 @@ void software_node_unregister(const struct software_node *node);
 struct fwnode_handle *
 fwnode_create_software_node(const struct property_entry *properties,
 			    const struct fwnode_handle *parent);
+struct fwnode_handle *
+fwnode_create_named_software_node(const struct property_entry *properties,
+				  const struct fwnode_handle *parent,
+				  const char *name);
 void fwnode_remove_software_node(struct fwnode_handle *fwnode);
 
 int device_add_software_node(struct device *dev, const struct software_node *node);
net/dsa/dsa_priv.h +1 -1
index d9722e49864b..95c4e13e2dbf 100644
@@ -284,7 +284,7 @@ int dsa_port_mrp_add_ring_role(const struct dsa_port *dp,
 			       const struct switchdev_obj_ring_role_mrp *mrp);
 int dsa_port_mrp_del_ring_role(const struct dsa_port *dp,
 			       const struct switchdev_obj_ring_role_mrp *mrp);
-int dsa_port_phylink_create(struct dsa_port *dp);
+int dsa_port_phylink_create(struct dsa_port *dp, struct fwnode_handle *fwnode);
 int dsa_port_link_register_of(struct dsa_port *dp);
 void dsa_port_link_unregister_of(struct dsa_port *dp);
 int dsa_port_hsr_join(struct dsa_port *dp, struct net_device *hsr);
net/dsa/port.c +80 -19

142 lines not on this page · raw message

net/dsa/slave.c +1 -1
index ad6a6663feeb..f243e73cb522 100644
@@ -2245,7 +2245,7 @@ static int dsa_slave_phy_setup(struct net_device *slave_dev)
 		dp->pl_config.poll_fixed_state = true;
 	}
 
-	ret = dsa_port_phylink_create(dp);
+	ret = dsa_port_phylink_create(dp, of_fwnode_handle(dp->dn));
 	if (ret)
 		return ret;
 
Signature · 32 lines
2.25.1


It boots and works:

[    4.315754] sja1105 spi0.1: configuring for fixed/rgmii link mode
[    4.322653] sja1105 spi0.1 swp5 (uninitialized): PHY [mdio@2d24000:06] driver [Broadcom BCM5464] (irq=POLL)
[    4.334796] sja1105 spi0.1 swp2 (uninitialized): PHY [mdio@2d24000:03] driver [Broadcom BCM5464] (irq=POLL)
[    4.345853] sja1105 spi0.1 swp3 (uninitialized): PHY [mdio@2d24000:04] driver [Broadcom BCM5464] (irq=POLL)
[    4.356859] sja1105 spi0.1 swp4 (uninitialized): PHY [mdio@2d24000:05] driver [Broadcom BCM5464] (irq=POLL)
[    4.367245] device eth2 entered promiscuous mode
[    4.371864] DSA: tree 0 setup
[    4.376971] sja1105 spi0.1: Link is Up - 1Gbps/Full - flow control off
(...)
root@black:~# ip link set swp2 up && dhclient -i swp2 && ip addr show swp2
[   64.762756] fsl-gianfar soc:ethernet@2d90000 eth2: Link is Up - 1Gbps/Full - flow control off
[   64.771530] sja1105 spi0.1 swp2: configuring for phy/rgmii-id link mode
[   68.955048] sja1105 spi0.1 swp2: Link is Up - 1Gbps/Full - flow control off
12: swp2@eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:1f:7b:63:02:48 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.68/24 brd 10.0.0.255 scope global dynamic swp2
       valid_lft 600sec preferred_lft 600sec

It's by far the messiest patch I've posted to the list (in the interest
of responding quickly), but if you study the code you can obviously see
what's missing, basically I've hardcoded the speed to 1000 and I'm
copying the phy-mode from the real DT node.

Unfortunately I don't have the time (and most importantly the interest)
in pushing this any further than that. If you want to take this from
here and integrate it with phylink_get_caps() I'd be glad to review
the result. Otherwise, feel free to continue with phylink_set_max_fixed_link().
author maintainer
#17 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 14 lines · Vladimir Oltean
Quoted 4 lines · Russell King (Oracle)
Quoted 4 lines

This is why dsa_port_phylink_register() calls phylink_of_phy_connect() without checking whether it has a fixed-link or a PHY, because it doesn't fail even if it doesn't do anything.

Quoted 8 lines
Quoted 3 lines

In fact I've wanted to make a correction to my previous phrasing that "this function shouldn't be called if phylink_{,fwnode_}connect_phy() is going to be called later". The correction is "... with a phy-handle".

I'm not sure that clarification makes sense when talking about phylink_connect_phy(), so I think if you're clarifying it with a firmware property, you're only talking about phylink_fwnode_connect_phy() now?

Quoted 5 lines

Yes, it's super hard to verbalize, and this is the reason why I didn't add "... with a phy-handle" in the first place.

I wanted to say: phylink_connect_phy(), OR phylink_fwnode_connect_phy() WITH a phy-handle. I shouldn't have conflated them in the first place.

Ah, right, because I interpreted it quite differently!

Quoted 49 lines
Quoted 40 lines
Quoted 32 lines
Quoted 15 lines
Quoted 6 lines

Can phylink absorb all this logic, and automatically call phylink_set_max_fixed_link() based on the following?

(1) struct phylink_config gets extended with a bool fallback_max_fixed_link.
(2) DSA CPU and DSA ports set this to true in dsa_port_phylink_register().
(3) phylink_set_max_fixed_link() is hooked into this -ENODEV error

Quoted 8 lines
    condition from phylink_fwnode_phy_connect():

	phy_fwnode = fwnode_get_phy_node(fwnode);
	if (IS_ERR(phy_fwnode)) {
		if (pl->cfg_link_an_mode == MLO_AN_PHY)
			return -ENODEV; <- here
		return 0;
	}
Quoted 3 lines

My question in response would be - why should this DSA specific behaviour be handled completely internally within phylink, when it's a DSA specific behaviour? Why do we need boolean flags for this?

Because the end result will be simpler if we respect the separation of concerns that continues to exist, and it's still phylink's business to say what is and isn't valid. DSA still isn't aware of the bindings required by phylink, it just passes its fwnode to it. Practically speaking, I wouldn't be scratching my head as to why we're checking for half the prerequisites of phylink_set_max_fixed_link() in one place and for the other half in another.

True, through this patch set DSA is creating its own context specific extension of phylink bindings, but arguably those existed before DSA was even integrated with phylink, and we're just fixing something now we didn't realize at the time we'd need to do.

Quoted 7 lines

I can reverse the question, why would phylink even want to be involved in how the max fixed link parameters are deduced, and it doesn't just require that a fixed-link software node is constructed somehow (irrelevant to phylink how), and phylink is just modified to find and work with that if it exists? Isn't it for the exact same reason, separation of concerns, that it's easiest for phylink to figure out what is the most appropriate maximum fixed-link configuration?

Quoted 8 lines

If that could be done, I'd love it, because then we don't have this in phylink at all, and it can all be a DSA problem to solve. It also means that others won't be tempted to use the interface incorrectly.

I'm not sure how practical that is when we have both DT and ACPI to deal with, and ACPI is certainly out of my knowledge area to be able to construct a software node to specify a fixed-link. Maybe it can be done at the fwnode layer? I don't know.

Quoted 7 lines

I don't want to be misunderstood. I brought up software nodes because I'm sure you must have thought about this too, before proposing what you did here. And unless there's a technical reason against software nodes (which there doesn't appear to be, but I don't want to get ahead of myself), I figured you must be OK with phylink absorbing the logic, case in which I just don't understand why you are pushing back on a proposal how to make phylink absorb the logic completely.

The reason I hadn't is because switching DSA to fwnode brings with it issues for ACPI, and Andrew wants to be very careful about ACPI in networking - and I think quite rightly. As soon as one switches from DT APIs to fwnode APIs, you basically permit people an easy path to re-use DT properties in ACPI-land without the ACPI issues being first considered.

So, I think if we did go this route, we need Andrew's input.

Quoted 4 lines
Quoted 1 line

Do you have a handy example of what you're suggesting?

No, I didn't, but I thought, how hard can it be, and here's a hacked up attempt on one of my boards:

Thanks - that looks like something that should be possible to do, and way better than trying to shoe-horn this into phylink.

My only comment would be that Andrew would disagree with you about this being "fixing up broken DT" - he has actively encouraged some drivers to adopt this "default" mode, which means it's anything but "broken" but it really is part of the DSA firmware description.

Quoted 18 lines
[    4.315754] sja1105 spi0.1: configuring for fixed/rgmii link mode
[    4.322653] sja1105 spi0.1 swp5 (uninitialized): PHY [mdio@2d24000:06] driver [Broadcom BCM5464] (irq=POLL)
[    4.334796] sja1105 spi0.1 swp2 (uninitialized): PHY [mdio@2d24000:03] driver [Broadcom BCM5464] (irq=POLL)
[    4.345853] sja1105 spi0.1 swp3 (uninitialized): PHY [mdio@2d24000:04] driver [Broadcom BCM5464] (irq=POLL)
[    4.356859] sja1105 spi0.1 swp4 (uninitialized): PHY [mdio@2d24000:05] driver [Broadcom BCM5464] (irq=POLL)
[    4.367245] device eth2 entered promiscuous mode
[    4.371864] DSA: tree 0 setup
[    4.376971] sja1105 spi0.1: Link is Up - 1Gbps/Full - flow control off
(...)
root@black:~# ip link set swp2 up && dhclient -i swp2 && ip addr show swp2
[   64.762756] fsl-gianfar soc:ethernet@2d90000 eth2: Link is Up - 1Gbps/Full - flow control off
[   64.771530] sja1105 spi0.1 swp2: configuring for phy/rgmii-id link mode
[   68.955048] sja1105 spi0.1 swp2: Link is Up - 1Gbps/Full - flow control off
12: swp2@eth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether 00:1f:7b:63:02:48 brd ff:ff:ff:ff:ff:ff
    inet 10.0.0.68/24 brd 10.0.0.255 scope global dynamic swp2
       valid_lft 600sec preferred_lft 600sec
Quoted 4 lines

It's by far the messiest patch I've posted to the list (in the interest of responding quickly), but if you study the code you can obviously see what's missing, basically I've hardcoded the speed to 1000 and I'm copying the phy-mode from the real DT node.

Yep - there's at least one other property we need to carry over from the DT node, which is the "ethernet" property.

Quoted 4 lines

Unfortunately I don't have the time (and most importantly the interest) in pushing this any further than that. If you want to take this from here and integrate it with phylink_get_caps() I'd be glad to review the result. Otherwise, feel free to continue with phylink_set_max_fixed_link().

I think this could be a much better solution to this problem, quite simply because we then don't end up with phylink_set_max_fixed_link() which could be abused - and this keeps the complexity where it should be, in the DSA code.

As I say, though, I think we need Andrew's input on this. Andrew?

I'll look at turning this into a proper solution tomorrow if Andrew is okay with the fwnode change.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
maintainer
#18 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 13 lines · Russell King (Oracle)
Quoted 5 lines
Quoted 4 lines

I'm not sure how practical that is when we have both DT and ACPI to deal with, and ACPI is certainly out of my knowledge area to be able to construct a software node to specify a fixed-link. Maybe it can be done at the fwnode layer? I don't know.

Quoted 7 lines

I don't want to be misunderstood. I brought up software nodes because I'm sure you must have thought about this too, before proposing what you did here. And unless there's a technical reason against software nodes (which there doesn't appear to be, but I don't want to get ahead of myself), I figured you must be OK with phylink absorbing the logic, case in which I just don't understand why you are pushing back on a proposal how to make phylink absorb the logic completely.

Quoted 8 lines

The reason I hadn't is because switching DSA to fwnode brings with it issues for ACPI, and Andrew wants to be very careful about ACPI in networking - and I think quite rightly. As soon as one switches from DT APIs to fwnode APIs, you basically permit people an easy path to re-use DT properties in ACPI-land without the ACPI issues being first considered.
Yep - there's at least one other property we need to carry over from the DT node, which is the "ethernet" property.

I've cropped only these segments because there is something I apparently need to highlight. What my patch does is _not_ at the device fwnode level (in fact, DSA ports do not have a struct device, only the switch does), but indeed at the most crude fwnode_handle level. And the fwnode_handles I'm creating using the software_node API are not connected in any way with the device. I'm not replacing the device's fwnodes with prosthetic ones. The fact that I wrote "dn->fwnode.secondary = new_port_fwnode;" is just a cheap hack to minimize the patch delta so I wouldn't have to transport the software fwnode_handle from one place to another within dsa_port_link_register_of(). This should definitely dissapear in the final solution. In fact, as long as phylink doesn't keep a reference on the fwnode after phylink_create() or phylink_fwnode_phy_connect(), I'm pretty sure that the software node can even be deallocated during the probing stage, no need to keep it for the entire lifetime of the device.

Therefore, no, we don't need the "ethernet" phandle in the software node we create, because we just use that to pass it to phylink. We still keep our original OF node for the rest of the activities. We don't even need the "reg" u32 property, I just added that for no reason (I wasn't completely sure what the API offers, then I didn't remove it).

So the concern that this software node can be abused for a transition to ACPI is quite overestimated. Nothing in DSA is "switched to fwnode" per se, and the creation of a fwnode is just part of "speaking the software node language", which phylink already happily understands and so, needs no change. Just my 2 cents.

author maintainer
#19 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

In reply to Vladimir Oltean

Hi,

Quoted 1 line · Vladimir Oltean

+static int dsa_port_fixup_broken_dt(struct dsa_port *dp)

As I mentioned, I doubt that Andrew considers this "broken DT" as he's been promoting this as a standard DSA feature.

Quoted 11 lines
net/dsa/port.c +11 -0
+{
+	struct property_entry fixed_link_props[] = {
+		PROPERTY_ENTRY_BOOL("full-duplex"),
+		PROPERTY_ENTRY_U32("speed", 1000), /* TODO determine actual speed */
+		{},
+	};
+	struct property_entry port_props[3] = {};
+	struct fwnode_handle *fixed_link_fwnode;
+	struct fwnode_handle *new_port_fwnode;
+	struct device_node *dn = dp->dn;
+	phy_interface_t mode;

net/dsa/port.c static int dsa_port_phylink_register(struct dsa_port *dp) · line 1675

Quoted 10 lines
net/dsa/port.c +10 -0
+	int err;
+
+	if (of_parse_phandle(dn, "phy-handle", 0) ||
+	    of_phy_is_fixed_link(dn))
+		/* Nothing broken, nothing to fix.
+		 * TODO: As discussed with Russell, maybe phylink could provide
+		 * a more comprehensive helper to determine what constitutes a
+		 * valid fwnode binding than this guerilla kludge.
+		 */
+		return 0;

I think this is sufficient. Yes, phylink accepts "phy" and "phy-device" because it has to for compatibility with other drivers, but the binding document for DSA quite clearly states that "phy-handle" is what DSA accepts, so DT in the kernel will be validated against the yaml file and enforce correctness here.

We do need to check for "sfp" being present as well.

net/dsa/port.c static int dsa_port_phylink_register(struct dsa_port *dp) · line 1682

Quoted 7 lines
net/dsa/port.c +7 -0
+
+	err = of_get_phy_mode(dn, &mode);
+	if (err)
+		/* TODO this may be missing too, ask the driver for the
+		 * max-speed interface mode for this port
+		 */
+		mode = PHY_INTERFACE_MODE_NA;

I think it would be easier to omit the phy-mode property in the swnode if it isn't present in DT, because then we can handle that in dsa_port_phylink_create() as I've done in my patch series via the ds->ops->phylink_get_caps() method.

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+	port_props[0] = PROPERTY_ENTRY_U32("reg", dp->index);

You said in one of your other replies that this node we're constructing is only for phylink, do we need the "reg" property? phylink doesn't care about it.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
#20 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 51 lines · On Fri, 8 Jul 2022 16:25:03 +0100 "Russell King (Oracle)"…

Hi,

Quoted 1 line · Vladimir Oltean

+static int dsa_port_fixup_broken_dt(struct dsa_port *dp)

As I mentioned, I doubt that Andrew considers this "broken DT" as he's been promoting this as a standard DSA feature.

Quoted 11 lines
net/dsa/port.c +11 -0
+{
+	struct property_entry fixed_link_props[] = {
+		PROPERTY_ENTRY_BOOL("full-duplex"),
+		PROPERTY_ENTRY_U32("speed", 1000), /* TODO determine actual speed */
+		{},
+	};
+	struct property_entry port_props[3] = {};
+	struct fwnode_handle *fixed_link_fwnode;
+	struct fwnode_handle *new_port_fwnode;
+	struct device_node *dn = dp->dn;
+	phy_interface_t mode;

net/dsa/port.c static int dsa_port_phylink_register(struct dsa_port *dp) · line 1675

Quoted 10 lines
net/dsa/port.c +10 -0
+	int err;
+
+	if (of_parse_phandle(dn, "phy-handle", 0) ||
+	    of_phy_is_fixed_link(dn))
+		/* Nothing broken, nothing to fix.
+		 * TODO: As discussed with Russell, maybe phylink could provide
+		 * a more comprehensive helper to determine what constitutes a
+		 * valid fwnode binding than this guerilla kludge.
+		 */
+		return 0;  

I think this is sufficient. Yes, phylink accepts "phy" and "phy-device" because it has to for compatibility with other drivers, but the binding document for DSA quite clearly states that "phy-handle" is what DSA accepts, so DT in the kernel will be validated against the yaml file and enforce correctness here.

We do need to check for "sfp" being present as well.

net/dsa/port.c static int dsa_port_phylink_register(struct dsa_port *dp) · line 1682

Quoted 7 lines
net/dsa/port.c +7 -0
+
+	err = of_get_phy_mode(dn, &mode);
+	if (err)
+		/* TODO this may be missing too, ask the driver for the
+		 * max-speed interface mode for this port
+		 */
+		mode = PHY_INTERFACE_MODE_NA;  

I think it would be easier to omit the phy-mode property in the swnode if it isn't present in DT, because then we can handle that in dsa_port_phylink_create() as I've done in my patch series via the ds->ops->phylink_get_caps() method.

Quoted 6 lines

Review

Quoted 2 lines
(quoted diff) +2 -0
+
+	port_props[0] = PROPERTY_ENTRY_U32("reg", dp->index);  

You said in one of your other replies that this node we're constructing is only for phylink, do we need the "reg" property? phylink doesn't care about it.

We don't. Vladimir wrote: "We don't even need the "reg" u32 property, I just added that for no reason (I wasn't completely sure what the API offers, then I didn't remove it)."

Marek

author maintainer
#21 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

In reply to Vladimir Oltean
Quoted 19 lines · Vladimir Oltean

Hello,

Quoted 16 lines · Russell King (Oracle)
net/dsa/port.c +1 -0
index 35b4e1f8dc05..34487e62eb03 100644
@@ -1525,6 +1525,7 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 {
 	struct dsa_switch *ds = dp->ds;
 	phy_interface_t mode, def_mode;
+	struct device_node *phy_np;
 	int err;
 
 	/* Presence of phylink_mac_link_state or phylink_mac_an_restart is
@@ -1559,6 +1560,13 @@ int dsa_port_phylink_create(struct dsa_port *dp)
 		return PTR_ERR(dp->pl);
 	}
 
Quoted 11 lines

net/dsa/port.c int dsa_port_phylink_create(struct dsa_port *dp) · line 1567

Quoted 5 lines
net/dsa/port.c +5 -0
+	if (dp->type == DSA_PORT_TYPE_CPU || dp->type == DSA_PORT_TYPE_DSA) {
+		phy_np = of_parse_phandle(dp->dn, "phy-handle", 0);
+		of_node_put(phy_np);
+		if (!phy_np)
+			err = phylink_set_max_fixed_link(dp->pl);

Can we please limit phylink_set_max_link_speed() to just the CPU ports where a fixed-link property is also missing, not just a phy-handle? Although to be entirely correct, we can also have MLO_AN_INBAND, which wouldn't be covered by these 2 checks and would still represent a valid DT binding.

More importantly, we need your input on Ocelot, which you are listed as a maintainer for, and Ocelot is the only DSA driver that does stuff differently (due to the rate adapting PCS). It doesn't set mac_capabilities, and therefore phylink_set_max_fixed_link() will not work here.

Has Ocelot ever made use of this DSA feature where, when nothing is specified for a CPU or DSA port, we use an effective fixed-link setup with an interface mode that gives the highest speed? Or does this not apply to this DSA driver?

Thanks.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
maintainer
#22 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 6 lines · Russell King (Oracle)

More importantly, we need your input on Ocelot, which you are listed as a maintainer for, and Ocelot is the only DSA driver that does stuff differently (due to the rate adapting PCS). It doesn't set mac_capabilities, and therefore phylink_set_max_fixed_link() will not work here.

Quoted 6 lines

Has Ocelot ever made use of this DSA feature where, when nothing is specified for a CPU or DSA port, we use an effective fixed-link setup with an interface mode that gives the highest speed? Or does this not apply to this DSA driver?

Thanks.

I'm fine with both the ocelot and sja1105 drivers.

The ocelot driver has 3 users:

- felix_vsc9959 (arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi) on NXP LS1028A, where the CPU ports have and have always had a fixed-link node in the SoC dtsi. LS1028A based boards should include the SoC dtsi. If other board DT writers don't do that or if they delete the fixed-link node from the CPU ports, that's not my problem and I don't really want to help them.

- seville_vsc9953 (arch/powerpc/boot/dts/fsl/t1040si-post.dtsi) on NXP T1040. Same thing, embedded switch, not my fault if the fixed-link disappears from the SoC dtsi.

- Colin Foster's SPI-controlled VSC7512 (still downstream). He has an Ethernet cable connecting the CPU port to a Beaglebone Black, so he has a phy-handle on the CPU port, so definitely not nothing. I believe his work hasn't made it to production in any case, so enforcing validation now shouldn't bother him too much if at all.

As for sja1105, there is DT validation that checks for the presence of all required properties in sja1105_parse_ports_node().

There is some DT validation in felix_parse_ports_node() too, but it doesn't check that all specifiers that phylink might use are there. I'd really like to add some validation before I gain any involuntary users, but all open-coded constructs I can come up with are clumsy. What would you suggest, if I explicitly don't want to rely on context-specific phylink interpretation of empty OF nodes, and rather error out?

author maintainer
#23 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 25 lines · Vladimir Oltean
Quoted 6 lines · Russell King (Oracle)

More importantly, we need your input on Ocelot, which you are listed as a maintainer for, and Ocelot is the only DSA driver that does stuff differently (due to the rate adapting PCS). It doesn't set mac_capabilities, and therefore phylink_set_max_fixed_link() will not work here.

Quoted 6 lines

Has Ocelot ever made use of this DSA feature where, when nothing is specified for a CPU or DSA port, we use an effective fixed-link setup with an interface mode that gives the highest speed? Or does this not apply to this DSA driver?

Thanks.

I'm fine with both the ocelot and sja1105 drivers.

The ocelot driver has 3 users:

- felix_vsc9959 (arch/arm64/boot/dts/freescale/fsl-ls1028a.dtsi) on NXP LS1028A, where the CPU ports have and have always had a fixed-link node in the SoC dtsi. LS1028A based boards should include the SoC dtsi. If other board DT writers don't do that or if they delete the fixed-link node from the CPU ports, that's not my problem and I don't really want to help them.

Quoted 3 lines

- seville_vsc9953 (arch/powerpc/boot/dts/fsl/t1040si-post.dtsi) on NXP T1040. Same thing, embedded switch, not my fault if the fixed-link disappears from the SoC dtsi.

Great, so I'll mark ocelot is safe.

Quoted 5 lines

- Colin Foster's SPI-controlled VSC7512 (still downstream). He has an Ethernet cable connecting the CPU port to a Beaglebone Black, so he has a phy-handle on the CPU port, so definitely not nothing. I believe his work hasn't made it to production in any case, so enforcing validation now shouldn't bother him too much if at all.

Ok, thanks.

Quoted 2 lines

As for sja1105, there is DT validation that checks for the presence of all required properties in sja1105_parse_ports_node().

Looking at those, it requires all of:

- a phy mode to be specified (as determined by of_get_phy_mode())
- a phy-handle or of_phy_is_fixed_link() to return true

otherwise it errors out.

Quoted 2 lines

There is some DT validation in felix_parse_ports_node() too, but it doesn't check that all specifiers that phylink might use are there.

Phylink (correction, fwnode_get_phy_node() which is not part of phylink anymore) will look for phy-handle, phy, or phy-device. This is I don't see that there's any incompatibility between what the driver is doing and what phylink does.

If there's a fixed-link property, then sja1105_parse_ports_node() is happy, and so will phylink. If there's a phy-handle, the same is true. If there's a "phy" or "phy-device" then sja1105_parse_ports_node() errors out. That's completely fine.

"phy" and "phy-device" are the backwards compatibility for DT - I believe one of them is the ePAPR specified property that we in Linux have decided to only fall back on if there's not our more modern "phy-handle" property.

It seems We have a lot of users of "phy" in DT today, so we can't drop that from generic code such as phylink, but I haven't found any users of "phy-device".

Quoted 5 lines

I'd really like to add some validation before I gain any involuntary users, but all open-coded constructs I can come up with are clumsy. What would you suggest, if I explicitly don't want to rely on context-specific phylink interpretation of empty OF nodes, and rather error out?

So I also don't see a problem - sja1105 rejects DTs that fail to describe a port using at least one of a phy-handle, a fixed-link, or a managed in-band link, and I don't think it needs to do further validation, certainly not for the phy describing properties that the kernel has chosen to deprecate for new implementations.

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
maintainer
#24 lore raw

Re: [PATCH RFC net-next 5/5] net: dsa: always use phylink for CPU and DSA ports

Quoted 1 line · Russell King (Oracle)

Great, so I'll mark ocelot is safe.

Yes, please.

Quoted 9 lines
Quoted 2 lines

As for sja1105, there is DT validation that checks for the presence of all required properties in sja1105_parse_ports_node().

Looking at those, it requires all of:

- a phy mode to be specified (as determined by of_get_phy_mode())
- a phy-handle or of_phy_is_fixed_link() to return true

otherwise it errors out.

I know. The problem with this ad-hoc validation is that it doesn't cover the pure MLO_AN_INBAND:

	managed = "in-band-status";

so it is more restrictive than it needs to be. Also it doesn't recognize the presence of an SFP bus in MLO_AN_PHY mode.

That is part 1 of my problem. I want to have validation that I'm providing phylink with all the right things it may need, but I don't want to make the driver code super clunky. By checking just the presence of either phy-handle or fixed-link I am rejecting valid phylink configurations. What I need is a validation function that is actually in sync with phylink, not just ad-hoc.

Quoted 28 lines
Quoted 2 lines

There is some DT validation in felix_parse_ports_node() too, but it doesn't check that all specifiers that phylink might use are there.

Phylink (correction, fwnode_get_phy_node() which is not part of phylink anymore) will look for phy-handle, phy, or phy-device. This is I don't see that there's any incompatibility between what the driver is doing and what phylink does.

If there's a fixed-link property, then sja1105_parse_ports_node() is happy, and so will phylink. If there's a phy-handle, the same is true. If there's a "phy" or "phy-device" then sja1105_parse_ports_node() errors out. That's completely fine.

"phy" and "phy-device" are the backwards compatibility for DT - I believe one of them is the ePAPR specified property that we in Linux have decided to only fall back on if there's not our more modern "phy-handle" property.

It seems We have a lot of users of "phy" in DT today, so we can't drop that from generic code such as phylink, but I haven't found any users of "phy-device".

Quoted 5 lines

I'd really like to add some validation before I gain any involuntary users, but all open-coded constructs I can come up with are clumsy. What would you suggest, if I explicitly don't want to rely on context-specific phylink interpretation of empty OF nodes, and rather error out?

Quoted 5 lines

So I also don't see a problem - sja1105 rejects DTs that fail to describe a port using at least one of a phy-handle, a fixed-link, or a managed in-band link, and I don't think it needs to do further validation, certainly not for the phy describing properties that the kernel has chosen to deprecate for new implementations.

And this is part 2 of my problem, ocelot/felix doesn't have validation at all except for phy-mode, because if it were to simply copy the phy-handle/fixed-link either/or logic from sja1105, it would break some customer boards with SFP cages. But without that validation, I am exposing this driver to configurations I don't want it to support (CPU ports with empty OF nodes, i.o.w. what this patch set is about).

#25 lore raw
In reply to Russell King (Oracle)
Quoted 11 lines · Russell King (Oracle)

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

3. Patch 5 - now also removes the port_max_speed_mode() method

This was tested with bcm_sf2.c and b53_srab.b and did not cause regressions, however we do have a 'fixed-link' property for the CPU port (always have had one), so there was no regression expected.

See answers to your RFC v1 below.

Quoted 23 lines
  drivers/net/dsa/b53/b53_common.c       |   3 +-
  drivers/net/dsa/bcm_sf2.c              |   3 +-
  drivers/net/dsa/hirschmann/hellcreek.c |   3 +-
  drivers/net/dsa/lantiq_gswip.c         |   6 +-
  drivers/net/dsa/microchip/ksz_common.c |   3 +-
  drivers/net/dsa/mt7530.c               |   3 +-
  drivers/net/dsa/mv88e6xxx/chip.c       | 136 +++++++++++++++---------------
  drivers/net/dsa/mv88e6xxx/chip.h       |   6 +-
  drivers/net/dsa/mv88e6xxx/port.c       |  32 -------
  drivers/net/dsa/mv88e6xxx/port.h       |   5 --
  drivers/net/dsa/ocelot/felix.c         |   3 +-
  drivers/net/dsa/qca/ar9331.c           |   3 +-
  drivers/net/dsa/qca8k.c                |   3 +-
  drivers/net/dsa/realtek/rtl8365mb.c    |   3 +-
  drivers/net/dsa/sja1105/sja1105_main.c |   3 +-
  drivers/net/dsa/xrs700x/xrs700x.c      |   3 +-
  drivers/net/phy/phylink.c              | 150 ++++++++++++++++++++++++++++++---
  include/linux/phylink.h                |   5 ++
  include/net/dsa.h                      |   3 +-
  net/dsa/port.c                         |  47 +++++++----
  20 files changed, 270 insertions(+), 153 deletions(-)
Quoted 84 lines
Quoted 83 lines · Russell King (Oracle)

Mostly the same as the previous RFC, except:

1) incldues the phylink_validate_mask_caps() function
2) has Marek's idea of searching the supported_interfaces bitmap for the fastest interface we can use
3) includes a final patch to add a print which will be useful to hear from people testing it.

Some of the questions from the original RFC remain though, so I've included that text below. I'm guessing as they remain unanswered that no one has any opinions on them?

  drivers/net/dsa/b53/b53_common.c       |   3 +-
  drivers/net/dsa/bcm_sf2.c              |   3 +-
  drivers/net/dsa/hirschmann/hellcreek.c |   3 +-
  drivers/net/dsa/lantiq_gswip.c         |   6 +-
  drivers/net/dsa/microchip/ksz_common.c |   3 +-
  drivers/net/dsa/mt7530.c               |   3 +-
  drivers/net/dsa/mv88e6xxx/chip.c       |  53 ++++--------
  drivers/net/dsa/ocelot/felix.c         |   3 +-
  drivers/net/dsa/qca/ar9331.c           |   3 +-
  drivers/net/dsa/qca8k.c                |   3 +-
  drivers/net/dsa/realtek/rtl8365mb.c    |   3 +-
  drivers/net/dsa/sja1105/sja1105_main.c |   3 +-
  drivers/net/dsa/xrs700x/xrs700x.c      |   3 +-
  drivers/net/phy/phylink.c              | 148 ++++++++++++++++++++++++++++++---
  include/linux/phylink.h                |   5 ++
  include/net/dsa.h                      |   3 +-
  net/dsa/port.c                         |  47 +++++++----
  17 files changed, 215 insertions(+), 80 deletions(-)
Quoted 51 lines · Russell King (Oracle)

Hi,

Currently, the core DSA code conditionally uses phylink for CPU and DSA ports depending on whether the firmware specifies a fixed-link or a PHY. If either of these are specified, then phylink is used for these ports, otherwise phylink is not, and we rely on the DSA drivers to "do the right thing". However, this detail is not mentioned in the DT binding, but Andrew has said that this behaviour has always something that DSA wants.

mv88e6xxx has had support for this for a long time with its "SPEED_MAX" thing, which I recently reworked to make use of the mac_capabilities in preparation to solving this more fully.

This series is an experiment to solve this properly, and it does this in two steps.

The first step consists of the first two patches. Phylink needs to know the PHY interface mode that is being used so it can (a) pass the right mode into the MAC/PCS etc and (b) know the properties of the link and therefore which speeds can be supported across it.

In order to achieve this, the DSA phylink_get_caps() method has an extra argument added to it so that DSA drivers can report the interface mode that they will be using for this port back to the core DSA code, thereby allowing phylink to be initialised with the correct interface mode.

Note that this can only be used for CPU and DSA ports as "user" ports need a different behaviour - they rely on getting the interface mode from phylib, which will only happen if phylink is initialised with PHY_INTERFACE_MODE_NA. Unfortunately, changing this behaviour is likely to cause widespread regressions.

Obvious questions:
1. Should phylink_get_caps() be augmented in this way, or should it be a separate method?

2. DSA has traditionally used "interface mode for the maximum supported speed on this port" where the interface mode is programmable (via its internal port_max_speed_mode() method) but this is only present for a few of the sub-drivers. Is reporting the current interface mode correct where this method is not implemented?

The second step is to introduce a function that allows phylink to be reconfigured after creation time to operate at max-speed fixed-link mode for the PHY interface mode, also using the MAC capabilities to determine the speed and duplex mode we should be using.

Obvious questions:
1. Should we be allowing half-duplex for this?

Except for testing, not sure I do see a point as it should not be a configuration being used at all?

Quoted 3 lines
Quoted 3 lines
Quoted 3 lines

2. If we do allow half-duplex, should we prefer fastest speed over duplex setting, or should we prefer fastest full-duplex speed over any half-duplex?

I would opt for fastest speed over duplex setting.

Quoted 8 lines
Quoted 8 lines
Quoted 8 lines

3. How do we sanely switch DSA from its current behaviour to always using phylink for these ports without breakage - this is the difficult one, because it's not obvious which drivers have been coded to either work around this quirk of the DSA implementation. For example, if we start forcing the link down before calling dsa_port_phylink_create(), and we then fail to set max-fixed-link, then the CPU/DSA port is going to fail, and we're going to have lots of regressions.

Good question, we already have a legacy_pre_march2020 behavior for a piece of infrastructure code that is not so old, I doubt that we would want to add more of that type of quirk.

Signature · 1 line
Florian
maintainer
#26 lore raw

Hi Florian,

Quoted 11 lines · Florian Fainelli
Quoted 10 lines · Russell King (Oracle)

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

Quoted 5 lines
Quoted 1 line

3. Patch 5 - now also removes the port_max_speed_mode() method

This was tested with bcm_sf2.c and b53_srab.b and did not cause regressions, however we do have a 'fixed-link' property for the CPU port (always have had one), so there was no regression expected.

What about arch/arm/boot/dts/bcm47189-tenda-ac9.dts?
Just to make sure I'm simply not seeing something, I compiled and then decompiled the dtb. We have:

		ethernet@5000 {
			reg = <0x5000 0x1000>;
			phandle = <0x03>;

			mdio {
				#address-cells = <0x01>;
				#size-cells = <0x00>;

				switch@1e {
					compatible = "brcm,bcm53125";
					reg = <0x1e>;
					status = "okay";

					ports {
						#address-cells = <0x01>;
						#size-cells = <0x00>;

						port@0 {
							reg = <0x00>;
							label = "wan";
						};

						port@1 {
							reg = <0x01>;
							label = "lan1";
						};

						port@2 {
							reg = <0x02>;
							label = "lan2";
						};

						port@3 {
							reg = <0x03>;
							label = "lan3";
						};

						port@4 {
							reg = <0x04>;
							label = "lan4";
						};

						port@5 {
							reg = <0x05>;
							label = "cpu";
							ethernet = <0x03>; <- CPU port with no phy-handle, no fixed-link
						};
					};
				};
			};
		};
#27 lore raw
Quoted 14 lines · Vladimir Oltean

Hi Florian,

Quoted 11 lines · Florian Fainelli
Quoted 10 lines · Russell King (Oracle)

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

Quoted 7 lines
Quoted 5 lines
Quoted 1 line

3. Patch 5 - now also removes the port_max_speed_mode() method

This was tested with bcm_sf2.c and b53_srab.b and did not cause regressions, however we do have a 'fixed-link' property for the CPU port (always have had one), so there was no regression expected.

What about arch/arm/boot/dts/bcm47189-tenda-ac9.dts?

You found one of the devices that I do not have access to and did not test, thanks. We do expect to run the port at 2GBits/sec on these devices however there is no "official" way to advertise that a port can run at 2Gbits/sec, as this is not even a "sanctioned" speed. I do have a similar device however, so let me run some more tests, we won't see a regression however since we do not use the NATP accelerator which would be the reason to run the port at 2Gbits/sec.

Signature · 1 line
Florian
#28 lore raw
Quoted 17 lines · Florian Fainelli
Quoted 16 lines · Vladimir Oltean

Hi Florian,

Quoted 13 lines · Florian Fainelli
Quoted 11 lines · Russell King (Oracle)

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

3. Patch 5 - now also removes the port_max_speed_mode() method

Quoted 7 lines
Quoted 5 lines
Quoted 3 lines

This was tested with bcm_sf2.c and b53_srab.b and did not cause regressions, however we do have a 'fixed-link' property for the CPU port (always have had one), so there was no regression expected.

What about arch/arm/boot/dts/bcm47189-tenda-ac9.dts?

You found one of the devices that I do not have access to and did not test, thanks. We do expect to run the port at 2GBits/sec on these devices however there is no "official" way to advertise that a port can run at 2Gbits/sec, as this is not even a "sanctioned" speed. I do have a similar device however, so let me run some more tests, we won't see a regression however since we do not use the NATP accelerator which would be the reason to run the port at 2Gbits/sec.

I will try this change on some devices with the lantiq gswip driver at the weekend.

On the SoC supported by the lantiq gswip driver the switch is integrated in the SoC and there is a internal link with more than 1GBit/s connecting the switch to the rest of the system. I think it is also around 2GBit/s. We can not configure the interface speed or many other interface settings for the link between the switch and the CPU. How should the device tree ideally look for this setup?

Hauke

author maintainer
#29 lore raw
Quoted 37 lines · Hauke Mehrtens
Quoted 25 lines · Florian Fainelli
Quoted 16 lines · Vladimir Oltean

Hi Florian,

Quoted 13 lines · Florian Fainelli
Quoted 11 lines · Russell King (Oracle)

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

3. Patch 5 - now also removes the port_max_speed_mode() method

Quoted 7 lines
Quoted 5 lines

This was tested with bcm_sf2.c and b53_srab.b and did not cause regressions,
however we do have a 'fixed-link' property for the CPU port (always have had
one), so there was no regression expected.

What about arch/arm/boot/dts/bcm47189-tenda-ac9.dts?

Quoted 7 lines

You found one of the devices that I do not have access to and did not test, thanks. We do expect to run the port at 2GBits/sec on these devices however there is no "official" way to advertise that a port can run at 2Gbits/sec, as this is not even a "sanctioned" speed. I do have a similar device however, so let me run some more tests, we won't see a regression however since we do not use the NATP accelerator which would be the reason to run the port at 2Gbits/sec.

I will try this change on some devices with the lantiq gswip driver at the weekend.

Quoted 6 lines

On the SoC supported by the lantiq gswip driver the switch is integrated in the SoC and there is a internal link with more than 1GBit/s connecting the switch to the rest of the system. I think it is also around 2GBit/s. We can not configure the interface speed or many other interface settings for the link between the switch and the CPU. How should the device tree ideally look for this setup?

I think this falls into Andrew's "don't specify anything" category, which means that we should default to the maximum speed for the port - which is in this case quite clearly fixed at whatever the internal link actually is.

From the get_caps() function, the fastest speed apparently supported is 1Gbps. I'm guessing the CPU port is one of ports 2..5 on xrx200 and 1..5 on xrx300 - in which case, PHY_INTERFACE_MODE_INTERNAL is likely to be selected, which seems appropriate given what you've said above. (PHY_INTERFACE_MODE_INTERNAL will be the first interface type found that will give the highest speed as it permits any speed given in the mac_capabilities.)

Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTP is here! 40Mbps down 10Mbps up. Decent connectivity at last!
maintainer
#30 lore raw
In reply to Russell King (Oracle)

Hi Russell,

Quoted 11 lines · Russell King

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

3. Patch 5 - now also removes the port_max_speed_mode() method

Tested with hellcreek driver and no problems observed.

Thanks,
Kurt

Tested-by on the v2 series
#31 lore raw
In reply to Russell King (Oracle)
Quoted 11 lines · Russell King (Oracle)

A new revision of the series which incorporates changes that Marek suggested. Specifically, the changes are:

1. Patch 2 - use the phylink_get_caps method in mv88e6xxx to get the default interface rather than re-using port_max_speed_mode()

2. Patch 4 - if no default interface is provided, use the supported interface mask to search for the first interface that gives the fastest speed.

3. Patch 5 - now also removes the port_max_speed_mode() method

Pulled in the patch set on top of net-next and tested on the D-Link DIR-685 with the RTL8366RB switch with no regressions, so:

The plan is to enhance the phylink handling in the RTL8366RB on top of Russell's patch in some time.

Yours,
Linus Walleij

#32 lore raw
Quoted 7 lines · Linus Walleij

Pulled in the patch set on top of net-next and tested on the D-Link DIR-685 with the RTL8366RB switch with no regressions, so:

The plan is to enhance the phylink handling in the RTL8366RB on top of Russell's patch in some time.

I developed a patch like this and tested it, it works great and the DSA core now properly configures all the links (as expected).

I will send this out once Russell's patches are finalized and merged.

Yours,
Linus Walleij