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

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.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent eb7e33d0
Loading
Loading
Loading
Loading
+117 −127
Original line number Diff line number Diff line
@@ -717,76 +717,10 @@ 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);

	/* 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);

	/* 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 void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
				struct phy_device *phydev)
{
	struct vsc73xx *vsc = ds->priv;
	u32 val;

	/* Special handling of the CPU-facing port */
	if (port == CPU_PORT) {
		/* Other ports are already initialized but not this one */
		vsc73xx_init_port(vsc, CPU_PORT);
		/* Select the external port for this interface (EXT_PORT)
		 * Enable the GMII GTX external clock
		 * Use double data rate (DDR mode)
		 */
		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
			      CPU_PORT,
			      VSC73XX_ADVPORTM,
			      VSC73XX_ADVPORTM_EXT_PORT |
			      VSC73XX_ADVPORTM_ENA_GTX |
			      VSC73XX_ADVPORTM_DDR_MODE);
	}

	/* This is the MAC confiuration that always need to happen
	 * after a PHY or the CPU port comes up or down.
	 */
	if (!phydev->link) {
	int ret, err;

		dev_dbg(vsc->dev, "port %d: went down\n",
			port);
	u32 val;

	/* Disable RX on this port */
	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_MAC, port,
@@ -812,11 +746,44 @@ static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,

	/* Put this port into reset */
	vsc73xx_write(vsc, VSC73XX_BLOCK_MAC, port, VSC73XX_MAC_CFG,
			      VSC73XX_MAC_CFG_RESET);
		      VSC73XX_MAC_CFG_RESET | initval);
}

		/* Accept packets again */
		vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
				    VSC73XX_ARBDISC, BIT(port), 0);
static void vsc73xx_mac_config(struct phylink_config *config, unsigned int mode,
			       const struct phylink_link_state *state)
{
	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) {
		/* Other ports are already initialized but not this one */
		vsc73xx_init_port(vsc, CPU_PORT);
		/* Select the external port for this interface (EXT_PORT)
		 * Enable the GMII GTX external clock
		 * Use double data rate (DDR mode)
		 */
		vsc73xx_write(vsc, VSC73XX_BLOCK_MAC,
			      CPU_PORT,
			      VSC73XX_ADVPORTM,
			      VSC73XX_ADVPORTM_EXT_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 routine is described in the datasheet (below ARBDISC register
	 * description)
	 */
	vsc73xx_reset_port(vsc, port, 0);

	/* Allow backward dropping of frames from this port */
	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ARBITER, 0,
@@ -825,55 +792,72 @@ static void vsc73xx_adjust_link(struct dsa_switch *ds, int port,
	/* Receive mask (disable forwarding) */
	vsc73xx_update_bits(vsc, VSC73XX_BLOCK_ANALYZER, 0,
			    VSC73XX_RECVMASK, BIT(port), 0);

		return;
}

	/* Figure out what speed was negotiated */
	if (phydev->speed == SPEED_1000) {
		dev_dbg(vsc->dev, "port %d: 1000 Mbit mode full duplex\n",
			port);
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;

		/* Set up default for internal port or external RGMII */
		if (phydev->interface == PHY_INTERFACE_MODE_RGMII)
			val = VSC73XX_MAC_CFG_1000M_F_RGMII;
	if (speed == SPEED_1000)
		val = VSC73XX_MAC_CFG_GIGA_MODE | VSC73XX_MAC_CFG_TX_IPG_1000M;
	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");
	}
		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;

	/* Enable port (forwarding) in the receieve mask */
	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);