[PATCH 5/6] net: dsa: felix: call phy_config at .port_probe() time

Ramon Fried rfried.dev at gmail.com
Wed Jun 30 00:20:03 CEST 2021


On Tue, Jun 29, 2021 at 8:09 PM Vladimir Oltean <olteanv at gmail.com> wrote:
>
> From: Vladimir Oltean <vladimir.oltean at nxp.com>
>
> It is an unfortunate reality that some PHY settings done by U-Boot
> persist even after the PHY is reset and taken over by Linux, and even
> more unfortunate that Linux has come to depend on things being set in a
> certain way.
>
> For example, on the NXP LS1028A-RDB, the felix switch ports are
> connected to a VSC8514 QSGMII PHY. Between the switch port PCS and the
> PHY, the U-Boot drivers enable in-band auto-negotiation which makes the
> copper-side negotiated speed and duplex be transmitted from the PHY to
> the MAC automatically.
>
> The PHY driver portion that does this is in vsc8514_config():
>
>         /* Enable Serdes Auto-negotiation */
>         phy_write(phydev, MDIO_DEVAD_NONE, PHY_EXT_PAGE_ACCESS,
>                   PHY_EXT_PAGE_ACCESS_EXTENDED3);
>         val = phy_read(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON);
>         val = val | MIIM_VSC8574_MAC_SERDES_ANEG;
>         phy_write(phydev, MDIO_DEVAD_NONE, MIIM_VSC8514_MAC_SERDES_CON, val);
>
> The point is that in-band autoneg should be turned on in both the PHY
> and the MAC, or off in both the PHY and the MAC, otherwise the QSGMII
> link will be broken.
>
> And because phy_config() is currently called at .port_enable() time, the
> result is that ports on which traffic has been sent in U-Boot will have
> in-band autoneg enabled, and the rest won't.
>
> It can be argued that the Linux kernel should not assume one way or
> another and just reinitialize everything according to what it expects,
> and that is completely fair. In fact, I've already started an attempt to
> remove this dependency, although admittedly I am making slow progress at
> it:
> https://patchwork.kernel.org/project/netdevbpf/cover/20210212172341.3489046-1-olteanv@gmail.com/
>
> Nonetheless, the sad reality is that NXP also has, apart from kernel
> drivers, some user space networking (DPDK), and for some reason, the
> expectation there is that somebody else initializes the PHYs. The kernel
> can't do it because the device ownership doesn't belong to the kernel,
> so what remains is for the bootloader to do it (especially since other
> drivers generally call phy_config() at probe time). This is a really
> weak guarantee that might break at any time, but apparently that is
> enough for some.
>
> Since initializing the ports and PHYs at probe time does not break
> anything, we can just do that.
>
> Signed-off-by: Vladimir Oltean <vladimir.oltean at nxp.com>
> ---
>  drivers/net/mscc_eswitch/felix_switch.c | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/net/mscc_eswitch/felix_switch.c b/drivers/net/mscc_eswitch/felix_switch.c
> index 75073880cf87..c8ecf4f19442 100644
> --- a/drivers/net/mscc_eswitch/felix_switch.c
> +++ b/drivers/net/mscc_eswitch/felix_switch.c
> @@ -317,10 +317,23 @@ static int felix_probe(struct udevice *dev)
>         return 0;
>  }
>
> +static int felix_port_probe(struct udevice *dev, int port,
> +                           struct phy_device *phy)
> +{
> +       int supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full;
> +       struct felix_priv *priv = dev_get_priv(dev);
> +
> +       phy->supported &= supported;
> +       phy->advertising &= supported;
> +
> +       felix_start_pcs(dev, port, phy, &priv->imdio);
> +
> +       return phy_config(phy);
> +}
> +
>  static int felix_port_enable(struct udevice *dev, int port,
>                              struct phy_device *phy)
>  {
> -       int supported = PHY_GBIT_FEATURES | SUPPORTED_2500baseX_Full;
>         struct felix_priv *priv = dev_get_priv(dev);
>         void *base = priv->regs_base;
>
> @@ -339,12 +352,6 @@ static int felix_port_enable(struct udevice *dev, int port,
>                  FELIX_QSYS_SYSTEM_SW_PORT_LOSSY |
>                  FELIX_QSYS_SYSTEM_SW_PORT_SCH(1));
>
> -       felix_start_pcs(dev, port, phy, &priv->imdio);
> -
> -       phy->supported &= supported;
> -       phy->advertising &= supported;
> -       phy_config(phy);
> -
>         phy_startup(phy);
>
>         return 0;
> @@ -392,6 +399,7 @@ static int felix_rcv(struct udevice *dev, int *pidx, void *packet, int length)
>  }
>
>  static const struct dsa_ops felix_dsa_ops = {
> +       .port_probe     = felix_port_probe,
>         .port_enable    = felix_port_enable,
>         .port_disable   = felix_port_disable,
>         .xmit           = felix_xmit,
> --
> 2.25.1
>
Interesting, My two cents is that device drivers by definition
shouldn't assume anything regarding the state of the HW.
Reviewed-by: Ramon Fried <rfried.dev at gmail.com>


More information about the U-Boot mailing list