Merge branch 'Better-PHYLINK-compliance-for-SJA1105-DSA'
authorDavid S. Miller <davem@davemloft.net>
Fri, 28 Jun 2019 16:31:31 +0000 (09:31 -0700)
committerDavid S. Miller <davem@davemloft.net>
Fri, 28 Jun 2019 16:31:31 +0000 (09:31 -0700)
Vladimir Oltean says:

====================
Better PHYLINK compliance for SJA1105 DSA

After discussing with Russell King, it appears this driver is making a
few confusions and not performing some checks for consistent operation.

Changes in v2:
- Removed redundant print in the phylink_validate callback (in 2/3).
====================

Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/dsa/sja1105/sja1105_main.c

index caebf76eaa3e7ac9440418adcdee167baebfdaa1..32bf3a7cc3b6db9961ec7df11cc0e9bb127de4a8 100644 (file)
@@ -715,7 +715,13 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
 
        switch (speed_mbps) {
        case SPEED_UNKNOWN:
-               /* No speed update requested */
+               /* PHYLINK called sja1105_mac_config() to inform us about
+                * the state->interface, but AN has not completed and the
+                * speed is not yet valid. UM10944.pdf says that setting
+                * SJA1105_SPEED_AUTO at runtime disables the port, so that is
+                * ok for power consumption in case AN will never complete -
+                * otherwise PHYLINK should come back with a new update.
+                */
                speed = SJA1105_SPEED_AUTO;
                break;
        case SPEED_10:
@@ -760,14 +766,50 @@ static int sja1105_adjust_port_config(struct sja1105_private *priv, int port,
        return sja1105_clocking_setup_port(priv, port);
 }
 
+/* The SJA1105 MAC programming model is through the static config (the xMII
+ * Mode table cannot be dynamically reconfigured), and we have to program
+ * that early (earlier than PHYLINK calls us, anyway).
+ * So just error out in case the connected PHY attempts to change the initial
+ * system interface MII protocol from what is defined in the DT, at least for
+ * now.
+ */
+static bool sja1105_phy_mode_mismatch(struct sja1105_private *priv, int port,
+                                     phy_interface_t interface)
+{
+       struct sja1105_xmii_params_entry *mii;
+       sja1105_phy_interface_t phy_mode;
+
+       mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
+       phy_mode = mii->xmii_mode[port];
+
+       switch (interface) {
+       case PHY_INTERFACE_MODE_MII:
+               return (phy_mode != XMII_MODE_MII);
+       case PHY_INTERFACE_MODE_RMII:
+               return (phy_mode != XMII_MODE_RMII);
+       case PHY_INTERFACE_MODE_RGMII:
+       case PHY_INTERFACE_MODE_RGMII_ID:
+       case PHY_INTERFACE_MODE_RGMII_RXID:
+       case PHY_INTERFACE_MODE_RGMII_TXID:
+               return (phy_mode != XMII_MODE_RGMII);
+       default:
+               return true;
+       }
+}
+
 static void sja1105_mac_config(struct dsa_switch *ds, int port,
                               unsigned int link_an_mode,
                               const struct phylink_link_state *state)
 {
        struct sja1105_private *priv = ds->priv;
 
-       if (!state->link)
+       if (sja1105_phy_mode_mismatch(priv, port, state->interface))
+               return;
+
+       if (link_an_mode == MLO_AN_INBAND) {
+               dev_err(ds->dev, "In-band AN not supported!\n");
                return;
+       }
 
        sja1105_adjust_port_config(priv, port, state->speed);
 }
@@ -801,6 +843,16 @@ static void sja1105_phylink_validate(struct dsa_switch *ds, int port,
 
        mii = priv->static_config.tables[BLK_IDX_XMII_PARAMS].entries;
 
+       /* include/linux/phylink.h says:
+        *     When @state->interface is %PHY_INTERFACE_MODE_NA, phylink
+        *     expects the MAC driver to return all supported link modes.
+        */
+       if (state->interface != PHY_INTERFACE_MODE_NA &&
+           sja1105_phy_mode_mismatch(priv, port, state->interface)) {
+               bitmap_zero(supported, __ETHTOOL_LINK_MODE_MASK_NBITS);
+               return;
+       }
+
        /* The MAC does not support pause frames, and also doesn't
         * support half-duplex traffic modes.
         */