Subject: Re: [PATCH 1/2] net: dsa: qca8k: Switch to PHYLINK instead of PHYLIB

From: Jonathan McDowell <[email-masked]>
Date: Thu, 11 Jun 2020 12:04:39 +0100

On Thu, Jun 11, 2020 at 11:58:43AM +0300, Vladimir Oltean wrote:
> Hi Jonathan,
> 
> On Wed, 10 Jun 2020 at 23:19, Jonathan McDowell <[email-masked]> wrote:
> >
> > Update the driver to use the new PHYLINK callbacks, removing the
> > legacy adjust_link callback.
> >
> > Signed-off-by: Jonathan McDowell <[email-masked]>
...
> >  static void
> > -qca8k_adjust_link(struct dsa_switch *ds, int port, struct phy_device *phy)
> > +qca8k_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int mode,
> > +                        const struct phylink_link_state *state)
> >  {
> >         struct qca8k_priv *priv = ds->priv;
> >         u32 reg;
> >
> > -       /* Force fixed-link setting for CPU port, skip others. */
> > -       if (!phy_is_pseudo_fixed_link(phy))
> > +       switch (port) {
> > +       case 0: /* 1st CPU port */
> > +               if (state->interface != PHY_INTERFACE_MODE_RGMII &&
> > +                   state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
> > +                   state->interface != PHY_INTERFACE_MODE_SGMII)
> > +                       return;
> > +
> > +               reg = QCA8K_REG_PORT0_PAD_CTRL;
> > +               break;
> > +       case 1:
> > +       case 2:
> > +       case 3:
> > +       case 4:
> > +       case 5:
> > +               /* Internal PHY, nothing to do */
> > +               return;
> > +       case 6: /* 2nd CPU port / external PHY */
> > +               if (state->interface != PHY_INTERFACE_MODE_RGMII &&
> > +                   state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
> > +                   state->interface != PHY_INTERFACE_MODE_SGMII &&
> > +                   state->interface != PHY_INTERFACE_MODE_1000BASEX)
> > +                       return;
> > +
> > +               reg = QCA8K_REG_PORT6_PAD_CTRL;
> > +               break;
> > +       default:
> > +               dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
> > +               return;
> > +       }
> > +
> > +       if (port != 6 && phylink_autoneg_inband(mode)) {
> > +               dev_err(ds->dev, "%s: in-band negotiation unsupported\n",
> > +                       __func__);
> > +               return;
> > +       }
> > +
> > +       switch (state->interface) {
> > +       case PHY_INTERFACE_MODE_RGMII:
> > +               /* RGMII mode means no delay so don't enable the delay */
> > +               qca8k_write(priv, reg, QCA8K_PORT_PAD_RGMII_EN);
> > +               break;
> > +       case PHY_INTERFACE_MODE_RGMII_ID:
> > +               /* RGMII_ID needs internal delay. This is enabled through
> > +                * PORT5_PAD_CTRL for all ports, rather than individual port
> > +                * registers
> > +                */
> > +               qca8k_write(priv, reg,
> > +                           QCA8K_PORT_PAD_RGMII_EN |
> > +                           QCA8K_PORT_PAD_RGMII_TX_DELAY(QCA8K_MAX_DELAY) |
> > +                           QCA8K_PORT_PAD_RGMII_RX_DELAY(QCA8K_MAX_DELAY));
> 
> 3 points here:
> - Should you prevalidate the device tree bindings that in case rgmii*
> mode are used, same delay settings are applied to all ports?
> - Can any RGMII port be connected to a PHY? If it can, won't the PHY
> enable delays too for RGMII_ID? Will the link work in that case?
> - Should you treat RGMII_TX_DELAY and RGMII_RX_DELAY independently for
> the case where there may be PCB traces?

The intent with this patch was to pull out the conversion to PHYLINK to
be stand-alone, with no functional changes, as request by Andrew. I
think there's room for some future clean-up here around the RGMII
options, but my main purpose in this patch set is to improve the SGMII
portion which my hardware uses that doesn't work with mainline.

> > +static void
> > +qca8k_phylink_validate(struct dsa_switch *ds, int port,
> > +                      unsigned long *supported,
> > +                      struct phylink_link_state *state)
> > +{
> > +       __ETHTOOL_DECLARE_LINK_MODE_MASK(mask) = { 0, };
> > +
> > +       switch (port) {
> > +       case 0: /* 1st CPU port */
> > +               if (state->interface != PHY_INTERFACE_MODE_NA &&
> > +                   state->interface != PHY_INTERFACE_MODE_RGMII &&
> > +                   state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
> > +                   state->interface != PHY_INTERFACE_MODE_SGMII)
> > +                       goto unsupported;
> >                 break;
> > -       case 100:
> > -               reg = QCA8K_PORT_STATUS_SPEED_100;
> > +       case 1:
> > +       case 2:
> > +       case 3:
> > +       case 4:
> > +       case 5:
> > +               /* Internal PHY */
> > +               if (state->interface != PHY_INTERFACE_MODE_NA &&
> > +                   state->interface != PHY_INTERFACE_MODE_GMII)
> > +                       goto unsupported;
> >                 break;
> > -       case 1000:
> > -               reg = QCA8K_PORT_STATUS_SPEED_1000;
> > +       case 6: /* 2nd CPU port / external PHY */
> > +               if (state->interface != PHY_INTERFACE_MODE_NA &&
> > +                   state->interface != PHY_INTERFACE_MODE_RGMII &&
> > +                   state->interface != PHY_INTERFACE_MODE_RGMII_ID &&
> > +                   state->interface != PHY_INTERFACE_MODE_SGMII &&
> > +                   state->interface != PHY_INTERFACE_MODE_1000BASEX)
> > +                       goto unsupported;
> >                 break;
> >         default:
> > -               dev_dbg(priv->dev, "port%d link speed %dMbps not supported.\n",
> > -                       port, phy->speed);
> > +               dev_err(ds->dev, "%s: unsupported port: %i\n", __func__, port);
> 
> phylink has a better validation error message than this, I'd say this
> is unnecessary.

Ok.

> > +static void
> > +qca8k_phylink_mac_link_up(struct dsa_switch *ds, int port, unsigned int mode,
> > +                         phy_interface_t interface, struct phy_device *phydev,
> > +                         int speed, int duplex, bool tx_pause, bool rx_pause)
> > +{
> > +       struct qca8k_priv *priv = ds->priv;
> > +       u32 reg;
> > +
> > +       if (phylink_autoneg_inband(mode)) {
> > +               reg = QCA8K_PORT_STATUS_LINK_AUTO;
> > +       } else {
> > +               switch (speed) {
> > +               case SPEED_10:
> > +                       reg = QCA8K_PORT_STATUS_SPEED_10;
> > +                       break;
> > +               case SPEED_100:
> > +                       reg = QCA8K_PORT_STATUS_SPEED_100;
> > +                       break;
> > +               case SPEED_1000:
> > +                       reg = QCA8K_PORT_STATUS_SPEED_1000;
> > +                       break;
> > +               default:
> > +                       reg = QCA8K_PORT_STATUS_LINK_AUTO;
> > +                       break;
> > +               }
> > +
> > +               if (duplex == DUPLEX_FULL)
> > +                       reg |= QCA8K_PORT_STATUS_DUPLEX;
> > +
> > +               if (rx_pause | dsa_is_cpu_port(ds, port))
> 
> I think it is odd to do bitwise OR on booleans.

I agree; will fix in the next spin.

J.

-- 
I get the feeling that I've been cheated.