Commit 21fc3416 authored by Pawel Dembicki's avatar Pawel Dembicki Committed by Jakub Kicinski

net: dsa: vsc73xx: convert to PHYLINK

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: default avatarPawel Dembicki <paweldembicki@gmail.com>
Link: https://lore.kernel.org/r/20240417205048.3542839-3-paweldembicki@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent eb7e33d0
...@@ -717,51 +717,44 @@ static void vsc73xx_init_port(struct vsc73xx *vsc, int port) ...@@ -717,51 +717,44 @@ static void vsc73xx_init_port(struct vsc73xx *vsc, int port)
port, VSC73XX_C_RX0, 0); port, VSC73XX_C_RX0, 0);
} }
static void vsc73xx_adjust_enable_port(struct vsc73xx *vsc, static void vsc73xx_reset_port(struct vsc73xx *vsc, int port, u32 initval)
int port, struct phy_device *phydev,
u32 initval)
{ {
u32 val = initval; int ret, err;
u8 seed; u32 val;
/* 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);
/* Flow control for the PHY facing ports: /* Disable RX on this port */
* Use a zero delay pause frame when pause condition is left vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
* Obey pause control frames VSC73XX_MAC_CFG,
* When generating pause frames, use 0xff as pause value VSC73XX_MAC_CFG_RX_EN, 0);
*/
vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_FCCONF,
VSC73XX_FCCONF_ZERO_PAUSE_EN |
VSC73XX_FCCONF_FLOW_CTRL_OBEY |
0xff);
/* Disallow backward dropping of frames from this port */ /* Discard packets */
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0, 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 */ /* Put this port into reset */
vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port, vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
VSC73XX_MAC_CFG, VSC73XX_MAC_CFG_RESET | initval);
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 void vsc73xx_adjust_link(struct dsa_switch *ds, int port, static void vsc73xx_mac_config(struct phylink_config *config, unsigned int mode,
struct phy_device *phydev) const struct phylink_link_state *state)
{ {
struct vsc73xx *vsc = ds->priv; struct dsa_port *dp = dsa_phylink_to_port(config);
u32 val; struct vsc73xx *vsc = dp->ds->priv;
int port = dp->index;
/* Special handling of the CPU-facing port */ /* Special handling of the CPU-facing port */
if (port == CPU_PORT) { if (port == CPU_PORT) {
...@@ -778,102 +771,93 @@ static void vsc73xx_adjust_link(struct dsa_switch *ds, int port, ...@@ -778,102 +771,93 @@ static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
VSC73XX_ADVPORTM_ENA_GTX | VSC73XX_ADVPORTM_ENA_GTX |
VSC73XX_ADVPORTM_DDR_MODE); 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 /* This routine is described in the datasheet (below ARBDISC register
* after a PHY or the CPU port comes up or down. * description)
*/ */
if (!phydev->link) { vsc73xx_reset_port(vsc, port, 0);
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);
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 */ /* Receive mask (disable forwarding) */
if (phydev->speed == SPEED_1000) { vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
dev_dbg(vsc->dev, "port %d: 1000 Mbit mode full duplex\n", VSC73XX_RECVMASK, BIT(port), 0);
port); }
/* Set up default for internal port or external RGMII */ static void vsc73xx_mac_link_up(struct phylink_config *config,
if (phydev->interface == PHY_INTERFACE_MODE_RGMII) struct phy_device *phy, unsigned int mode,
val = VSC73XX_MAC_CFG_1000M_F_RGMII; phy_interface_t interface, int speed,
else int duplex, bool tx_pause, bool rx_pause)
val = VSC73XX_MAC_CFG_1000M_F_PHY; {
vsc73xx_adjust_enable_port(vsc, port, phydev, val); struct dsa_port *dp = dsa_phylink_to_port(config);
} else if (phydev->speed == SPEED_100) { struct vsc73xx *vsc = dp->ds->priv;
if (phydev->duplex == DUPLEX_FULL) { int port = dp->index;
val = VSC73XX_MAC_CFG_100_10M_F_PHY; u32 val;
dev_dbg(vsc->dev, u8 seed;
"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");
}
/* 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_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
VSC73XX_RECVMASK, BIT(port), BIT(port)); 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, 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, ...@@ -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; 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 = { static const struct dsa_switch_ops vsc73xx_ds_ops = {
.get_tag_protocol = vsc73xx_get_tag_protocol, .get_tag_protocol = vsc73xx_get_tag_protocol,
.setup = vsc73xx_setup, .setup = vsc73xx_setup,
.phy_read = vsc73xx_phy_read, .phy_read = vsc73xx_phy_read,
.phy_write = vsc73xx_phy_write, .phy_write = vsc73xx_phy_write,
.adjust_link = vsc73xx_adjust_link,
.get_strings = vsc73xx_get_strings, .get_strings = vsc73xx_get_strings,
.get_ethtool_stats = vsc73xx_get_ethtool_stats, .get_ethtool_stats = vsc73xx_get_ethtool_stats,
.get_sset_count = vsc73xx_get_sset_count, .get_sset_count = vsc73xx_get_sset_count,
...@@ -1217,6 +1206,7 @@ int vsc73xx_probe(struct vsc73xx *vsc) ...@@ -1217,6 +1206,7 @@ int vsc73xx_probe(struct vsc73xx *vsc)
vsc->ds->priv = vsc; vsc->ds->priv = vsc;
vsc->ds->ops = &vsc73xx_ds_ops; vsc->ds->ops = &vsc73xx_ds_ops;
vsc->ds->phylink_mac_ops = &vsc73xx_phylink_mac_ops;
ret = dsa_register_switch(vsc->ds); ret = dsa_register_switch(vsc->ds);
if (ret) { if (ret) {
dev_err(dev, "unable to register switch (%d)\n", ret); dev_err(dev, "unable to register switch (%d)\n", ret);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment