net: dsa: vsc73xx: convert to PHYLINK
authorPawel Dembicki <paweldembicki@gmail.com>
Wed, 17 Apr 2024 20:50:45 +0000 (22:50 +0200)
committerJakub Kicinski <kuba@kernel.org>
Mon, 22 Apr 2024 21:21:30 +0000 (14:21 -0700)
This patch replaces the adjust_link api with the phylink apis that provide
equivalent functionality.

The remaining functionality from the adjust_link is now covered in the
mac_link_* and mac_config from phylink_mac_ops structure.

Removes:
.adjust_link
Adds phylink_mac_ops structure:
.mac_config
.mac_link_up
.mac_link_down

Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
Link: https://lore.kernel.org/r/20240417205048.3542839-3-paweldembicki@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/dsa/vitesse-vsc73xx-core.c

index ab5771d4d82872b27151c179b0dd66fbb3b70431..ad3634cf907eddb4ff717beeaa85d3aca14ee0d9 100644 (file)
@@ -717,51 +717,44 @@ static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
                      port, VSC73XX_C_RX0, 0);
 }
 
-static void vsc73xx_adjust_enable_port(struct vsc73xx *vsc,
-                                      int port, struct phy_device *phydev,
-                                      u32 initval)
+static void vsc73xx_reset_port(struct vsc73xx *vsc, int port, u32 initval)
 {
-       u32 val = initval;
-       u8 seed;
-
-       /* Reset this port FIXME: break out subroutine */
-       val |= VSC73XX_MAC_CFG_RESET;
-       vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
-
-       /* Seed the port randomness with randomness */
-       get_random_bytes(&seed, 1);
-       val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET;
-       val |= VSC73XX_MAC_CFG_SEED_LOAD;
-       val |= VSC73XX_MAC_CFG_WEXC_DIS;
-       vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
+       int ret, err;
+       u32 val;
 
-       /* Flow control for the PHY facing ports:
-        * Use a zero delay pause frame when pause condition is left
-        * Obey pause control frames
-        * When generating pause frames, use 0xff as pause value
-        */
-       vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_FCCONF,
-                     VSC73XX_FCCONF_ZERO_PAUSE_EN |
-                     VSC73XX_FCCONF_FLOW_CTRL_OBEY |
-                     0xff);
+       /* Disable RX on this port */
+       vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
+                           VSC73XX_MAC_CFG,
+                           VSC73XX_MAC_CFG_RX_EN, 0);
 
-       /* Disallow backward dropping of frames from this port */
+       /* Discard packets */
        vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
-                           VSC73XX_SBACKWDROP, BIT(port), 0);
+                           VSC73XX_ARBDISC, BIT(port), BIT(port));
+
+       /* Wait until queue is empty */
+       ret = read_poll_timeout(vsc73xx_read, err,
+                               err < 0 || (val & BIT(port)),
+                               VSC73XX_POLL_SLEEP_US,
+                               VSC73XX_POLL_TIMEOUT_US, false,
+                               vsc, VSC73XX_BLOCK_ARBITER, 0,
+                               VSC73XX_ARBEMPTY, &val);
+       if (ret)
+               dev_err(vsc->dev,
+                       "timeout waiting for block arbiter\n");
+       else if (err < 0)
+               dev_err(vsc->dev, "error reading arbiter\n");
 
-       /* Enable TX, RX, deassert reset, stop loading seed */
-       vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
-                           VSC73XX_MAC_CFG,
-                           VSC73XX_MAC_CFG_RESET | VSC73XX_MAC_CFG_SEED_LOAD |
-                           VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN,
-                           VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN);
+       /* Put this port into reset */
+       vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
+                     VSC73XX_MAC_CFG_RESET | initval);
 }
 
-static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
-                               struct phy_device *phydev)
+static void vsc73xx_mac_config(struct phylink_config *config, unsigned int mode,
+                              const struct phylink_link_state *state)
 {
-       struct vsc73xx *vsc = ds->priv;
-       u32 val;
+       struct dsa_port *dp = dsa_phylink_to_port(config);
+       struct vsc73xx *vsc = dp->ds->priv;
+       int port = dp->index;
 
        /* Special handling of the CPU-facing port */
        if (port == CPU_PORT) {
@@ -778,102 +771,93 @@ static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
                              VSC73XX_ADVPORTM_ENA_GTX |
                              VSC73XX_ADVPORTM_DDR_MODE);
        }
+}
+
+static void vsc73xx_mac_link_down(struct phylink_config *config,
+                                 unsigned int mode, phy_interface_t interface)
+{
+       struct dsa_port *dp = dsa_phylink_to_port(config);
+       struct vsc73xx *vsc = dp->ds->priv;
+       int port = dp->index;
 
-       /* This is the MAC confiuration that always need to happen
-        * after a PHY or the CPU port comes up or down.
+       /* This routine is described in the datasheet (below ARBDISC register
+        * description)
         */
-       if (!phydev->link) {
-               int ret, err;
-
-               dev_dbg(vsc->dev, "port %d: went down\n",
-                       port);
-
-               /* Disable RX on this port */
-               vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
-                                   VSC73XX_MAC_CFG,
-                                   VSC73XX_MAC_CFG_RX_EN, 0);
-
-               /* Discard packets */
-               vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
-                                   VSC73XX_ARBDISC, BIT(port), BIT(port));
-
-               /* Wait until queue is empty */
-               ret = read_poll_timeout(vsc73xx_read, err,
-                                       err < 0 || (val & BIT(port)),
-                                       VSC73XX_POLL_SLEEP_US,
-                                       VSC73XX_POLL_TIMEOUT_US, false,
-                                       vsc, VSC73XX_BLOCK_ARBITER, 0,
-                                       VSC73XX_ARBEMPTY, &val);
-               if (ret)
-                       dev_err(vsc->dev,
-                               "timeout waiting for block arbiter\n");
-               else if (err < 0)
-                       dev_err(vsc->dev, "error reading arbiter\n");
-
-               /* Put this port into reset */
-               vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
-                             VSC73XX_MAC_CFG_RESET);
-
-               /* Accept packets again */
-               vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
-                                   VSC73XX_ARBDISC, BIT(port), 0);
-
-               /* Allow backward dropping of frames from this port */
-               vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
-                                   VSC73XX_SBACKWDROP, BIT(port), BIT(port));
-
-               /* Receive mask (disable forwarding) */
-               vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
-                                   VSC73XX_RECVMASK, BIT(port), 0);
+       vsc73xx_reset_port(vsc, port, 0);
 
-               return;
-       }
+       /* Allow backward dropping of frames from this port */
+       vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
+                           VSC73XX_SBACKWDROP, BIT(port), BIT(port));
 
-       /* Figure out what speed was negotiated */
-       if (phydev->speed == SPEED_1000) {
-               dev_dbg(vsc->dev, "port %d: 1000 Mbit mode full duplex\n",
-                       port);
-
-               /* Set up default for internal port or external RGMII */
-               if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
-                       val = VSC73XX_MAC_CFG_1000M_F_RGMII;
-               else
-                       val = VSC73XX_MAC_CFG_1000M_F_PHY;
-               vsc73xx_adjust_enable_port(vsc, port, phydev, val);
-       } else if (phydev->speed == SPEED_100) {
-               if (phydev->duplex == DUPLEX_FULL) {
-                       val = VSC73XX_MAC_CFG_100_10M_F_PHY;
-                       dev_dbg(vsc->dev,
-                               "port %d: 100 Mbit full duplex mode\n",
-                               port);
-               } else {
-                       val = VSC73XX_MAC_CFG_100_10M_H_PHY;
-                       dev_dbg(vsc->dev,
-                               "port %d: 100 Mbit half duplex mode\n",
-                               port);
-               }
-               vsc73xx_adjust_enable_port(vsc, port, phydev, val);
-       } else if (phydev->speed == SPEED_10) {
-               if (phydev->duplex == DUPLEX_FULL) {
-                       val = VSC73XX_MAC_CFG_100_10M_F_PHY;
-                       dev_dbg(vsc->dev,
-                               "port %d: 10 Mbit full duplex mode\n",
-                               port);
-               } else {
-                       val = VSC73XX_MAC_CFG_100_10M_H_PHY;
-                       dev_dbg(vsc->dev,
-                               "port %d: 10 Mbit half duplex mode\n",
-                               port);
-               }
-               vsc73xx_adjust_enable_port(vsc, port, phydev, val);
-       } else {
-               dev_err(vsc->dev,
-                       "could not adjust link: unknown speed\n");
-       }
+       /* Receive mask (disable forwarding) */
+       vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
+                           VSC73XX_RECVMASK, BIT(port), 0);
+}
+
+static void vsc73xx_mac_link_up(struct phylink_config *config,
+                               struct phy_device *phy, unsigned int mode,
+                               phy_interface_t interface, int speed,
+                               int duplex, bool tx_pause, bool rx_pause)
+{
+       struct dsa_port *dp = dsa_phylink_to_port(config);
+       struct vsc73xx *vsc = dp->ds->priv;
+       int port = dp->index;
+       u32 val;
+       u8 seed;
 
-       /* Enable port (forwarding) in the receieve mask */
+       if (speed == SPEED_1000)
+               val = VSC73XX_MAC_CFG_GIGA_MODE | VSC73XX_MAC_CFG_TX_IPG_1000M;
+       else
+               val = VSC73XX_MAC_CFG_TX_IPG_100_10M;
+
+       if (interface == PHY_INTERFACE_MODE_RGMII)
+               val |= VSC73XX_MAC_CFG_CLK_SEL_1000M;
+       else
+               val |= VSC73XX_MAC_CFG_CLK_SEL_EXT;
+
+       if (duplex == DUPLEX_FULL)
+               val |= VSC73XX_MAC_CFG_FDX;
+
+       /* This routine is described in the datasheet (below ARBDISC register
+        * description)
+        */
+       vsc73xx_reset_port(vsc, port, val);
+
+       /* Seed the port randomness with randomness */
+       get_random_bytes(&seed, 1);
+       val |= seed << VSC73XX_MAC_CFG_SEED_OFFSET;
+       val |= VSC73XX_MAC_CFG_SEED_LOAD;
+       val |= VSC73XX_MAC_CFG_WEXC_DIS;
+       vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG, val);
+
+       /* Flow control for the PHY facing ports:
+        * Use a zero delay pause frame when pause condition is left
+        * Obey pause control frames
+        * When generating pause frames, use 0xff as pause value
+        */
+       vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_FCCONF,
+                     VSC73XX_FCCONF_ZERO_PAUSE_EN |
+                     VSC73XX_FCCONF_FLOW_CTRL_OBEY |
+                     0xff);
+
+       /* Accept packets again */
+       vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
+                           VSC73XX_ARBDISC, BIT(port), 0);
+
+       /* Enable port (forwarding) in the receive mask */
        vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
                            VSC73XX_RECVMASK, BIT(port), BIT(port));
+
+       /* Disallow backward dropping of frames from this port */
+       vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
+                           VSC73XX_SBACKWDROP, BIT(port), 0);
+
+       /* Enable TX, RX, deassert reset, stop loading seed */
+       vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
+                           VSC73XX_MAC_CFG,
+                           VSC73XX_MAC_CFG_RESET | VSC73XX_MAC_CFG_SEED_LOAD |
+                           VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN,
+                           VSC73XX_MAC_CFG_TX_EN | VSC73XX_MAC_CFG_RX_EN);
 }
 
 static int vsc73xx_port_enable(struct dsa_switch *ds, int port,
@@ -1055,12 +1039,17 @@ static void vsc73xx_phylink_get_caps(struct dsa_switch *dsa, int port,
        config->mac_capabilities = MAC_SYM_PAUSE | MAC_10 | MAC_100 | MAC_1000;
 }
 
+static const struct phylink_mac_ops vsc73xx_phylink_mac_ops = {
+       .mac_config = vsc73xx_mac_config,
+       .mac_link_down = vsc73xx_mac_link_down,
+       .mac_link_up = vsc73xx_mac_link_up,
+};
+
 static const struct dsa_switch_ops vsc73xx_ds_ops = {
        .get_tag_protocol = vsc73xx_get_tag_protocol,
        .setup = vsc73xx_setup,
        .phy_read = vsc73xx_phy_read,
        .phy_write = vsc73xx_phy_write,
-       .adjust_link = vsc73xx_adjust_link,
        .get_strings = vsc73xx_get_strings,
        .get_ethtool_stats = vsc73xx_get_ethtool_stats,
        .get_sset_count = vsc73xx_get_sset_count,
@@ -1217,6 +1206,7 @@ int vsc73xx_probe(struct vsc73xx *vsc)
        vsc->ds->priv = vsc;
 
        vsc->ds->ops = &vsc73xx_ds_ops;
+       vsc->ds->phylink_mac_ops = &vsc73xx_phylink_mac_ops;
        ret = dsa_register_switch(vsc->ds);
        if (ret) {
                dev_err(dev, "unable to register switch (%d)\n", ret);