Commit 2d1b50ab authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'lantiq-GSWIP-fixes'



Martin Blumenstingl says:

====================
lantiq: GSWIP: two more fixes

after my last patch got accepted and is now in net as commit
3e6fdeb2 ("net: dsa: lantiq_gswip: Let GSWIP automatically set
the xMII clock") [0] some more people from the OpenWrt community
(many thanks to everyone involved) helped test the GSWIP driver: [1]

It turns out that the previous fix does not work for all boards.
There's no regression, but it doesn't fix as many problems as I
thought. This is why two more fixes are needed:
- the first one solves many (four known but probably there are
  a few extra hidden ones) reported bugs with the GSWIP where no
  traffic would flow. Not all circumstances are fully understood
  but testing shows that switching away from PHY auto polling
  solves all of them
- while investigating the different problems which are addressed
  by the first patch some small issues with the existing code were
  found. These are addressed by the second patch

Changes since v1 at [0]:
- Don't configure the link parameters in gswip_phylink_mac_config
  (as we're using the "modern" way in gswip_phylink_mac_link_up).
  Thanks to Andrew for the hint with the phylink documentation.
- Clarify that GSWIP_MII_CFG_RMII_CLK is ignored by the hardware in
  the description of the second patch as suggested by Hauke
- Don't set GSWIP_MII_CFG_RGMII_IBS in the second patch as we don't
  have any hardware available for testing this. The patch
  description now also reflects this.
- Added Andrew's Reviewed-by to the first patch (thank you!)
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6494d15f 4b592324
Loading
Loading
Loading
Loading
+174 −28
Original line number Diff line number Diff line
@@ -93,8 +93,12 @@

/* GSWIP MII Registers */
#define GSWIP_MII_CFGp(p)		(0x2 * (p))
#define  GSWIP_MII_CFG_RESET		BIT(15)
#define  GSWIP_MII_CFG_EN		BIT(14)
#define  GSWIP_MII_CFG_ISOLATE		BIT(13)
#define  GSWIP_MII_CFG_LDCLKDIS		BIT(12)
#define  GSWIP_MII_CFG_RGMII_IBS	BIT(8)
#define  GSWIP_MII_CFG_RMII_CLK		BIT(7)
#define  GSWIP_MII_CFG_MODE_MIIP	0x0
#define  GSWIP_MII_CFG_MODE_MIIM	0x1
#define  GSWIP_MII_CFG_MODE_RMIIP	0x2
@@ -190,6 +194,23 @@
#define GSWIP_PCE_DEFPVID(p)		(0x486 + ((p) * 0xA))

#define GSWIP_MAC_FLEN			0x8C5
#define GSWIP_MAC_CTRL_0p(p)		(0x903 + ((p) * 0xC))
#define  GSWIP_MAC_CTRL_0_PADEN		BIT(8)
#define  GSWIP_MAC_CTRL_0_FCS_EN	BIT(7)
#define  GSWIP_MAC_CTRL_0_FCON_MASK	0x0070
#define  GSWIP_MAC_CTRL_0_FCON_AUTO	0x0000
#define  GSWIP_MAC_CTRL_0_FCON_RX	0x0010
#define  GSWIP_MAC_CTRL_0_FCON_TX	0x0020
#define  GSWIP_MAC_CTRL_0_FCON_RXTX	0x0030
#define  GSWIP_MAC_CTRL_0_FCON_NONE	0x0040
#define  GSWIP_MAC_CTRL_0_FDUP_MASK	0x000C
#define  GSWIP_MAC_CTRL_0_FDUP_AUTO	0x0000
#define  GSWIP_MAC_CTRL_0_FDUP_EN	0x0004
#define  GSWIP_MAC_CTRL_0_FDUP_DIS	0x000C
#define  GSWIP_MAC_CTRL_0_GMII_MASK	0x0003
#define  GSWIP_MAC_CTRL_0_GMII_AUTO	0x0000
#define  GSWIP_MAC_CTRL_0_GMII_MII	0x0001
#define  GSWIP_MAC_CTRL_0_GMII_RGMII	0x0002
#define GSWIP_MAC_CTRL_2p(p)		(0x905 + ((p) * 0xC))
#define GSWIP_MAC_CTRL_2_MLEN		BIT(3) /* Maximum Untagged Frame Lnegth */

@@ -653,16 +674,13 @@ static int gswip_port_enable(struct dsa_switch *ds, int port,
			  GSWIP_SDMA_PCTRLp(port));

	if (!dsa_is_cpu_port(ds, port)) {
		u32 macconf = GSWIP_MDIO_PHY_LINK_AUTO |
			      GSWIP_MDIO_PHY_SPEED_AUTO |
			      GSWIP_MDIO_PHY_FDUP_AUTO |
			      GSWIP_MDIO_PHY_FCONTX_AUTO |
			      GSWIP_MDIO_PHY_FCONRX_AUTO |
			      (phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK);
		u32 mdio_phy = 0;

		gswip_mdio_w(priv, macconf, GSWIP_MDIO_PHYp(port));
		/* Activate MDIO auto polling */
		gswip_mdio_mask(priv, 0, BIT(port), GSWIP_MDIO_MDC_CFG0);
		if (phydev)
			mdio_phy = phydev->mdio.addr & GSWIP_MDIO_PHY_ADDR_MASK;

		gswip_mdio_mask(priv, GSWIP_MDIO_PHY_ADDR_MASK, mdio_phy,
				GSWIP_MDIO_PHYp(port));
	}

	return 0;
@@ -675,14 +693,6 @@ static void gswip_port_disable(struct dsa_switch *ds, int port)
	if (!dsa_is_user_port(ds, port))
		return;

	if (!dsa_is_cpu_port(ds, port)) {
		gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_DOWN,
				GSWIP_MDIO_PHY_LINK_MASK,
				GSWIP_MDIO_PHYp(port));
		/* Deactivate MDIO auto polling */
		gswip_mdio_mask(priv, BIT(port), 0, GSWIP_MDIO_MDC_CFG0);
	}

	gswip_switch_mask(priv, GSWIP_FDMA_PCTRL_EN, 0,
			  GSWIP_FDMA_PCTRLp(port));
	gswip_switch_mask(priv, GSWIP_SDMA_PCTRL_EN, 0,
@@ -794,19 +804,32 @@ static int gswip_setup(struct dsa_switch *ds)
	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP2);
	gswip_switch_w(priv, BIT(cpu_port), GSWIP_PCE_PMAP3);

	/* disable PHY auto polling */
	/* Deactivate MDIO PHY auto polling. Some PHYs as the AR8030 have an
	 * interoperability problem with this auto polling mechanism because
	 * their status registers think that the link is in a different state
	 * than it actually is. For the AR8030 it has the BMSR_ESTATEN bit set
	 * as well as ESTATUS_1000_TFULL and ESTATUS_1000_XFULL. This makes the
	 * auto polling state machine consider the link being negotiated with
	 * 1Gbit/s. Since the PHY itself is a Fast Ethernet RMII PHY this leads
	 * to the switch port being completely dead (RX and TX are both not
	 * working).
	 * Also with various other PHY / port combinations (PHY11G GPHY, PHY22F
	 * GPHY, external RGMII PEF7071/7072) any traffic would stop. Sometimes
	 * it would work fine for a few minutes to hours and then stop, on
	 * other device it would no traffic could be sent or received at all.
	 * Testing shows that when PHY auto polling is disabled these problems
	 * go away.
	 */
	gswip_mdio_w(priv, 0x0, GSWIP_MDIO_MDC_CFG0);

	/* Configure the MDIO Clock 2.5 MHz */
	gswip_mdio_mask(priv, 0xff, 0x09, GSWIP_MDIO_MDC_CFG1);

	for (i = 0; i < priv->hw_info->max_ports; i++) {
		/* Disable the xMII link */
		gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, i);

		/* Automatically select the xMII interface clock */
		gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_RATE_MASK,
				   GSWIP_MII_CFG_RATE_AUTO, i);
	}
	/* Disable the xMII interface and clear it's isolation bit */
	for (i = 0; i < priv->hw_info->max_ports; i++)
		gswip_mii_mask_cfg(priv,
				   GSWIP_MII_CFG_EN | GSWIP_MII_CFG_ISOLATE,
				   0, i);

	/* enable special tag insertion on cpu port */
	gswip_switch_mask(priv, 0, GSWIP_FDMA_PCTRL_STEN,
@@ -1455,6 +1478,112 @@ static void gswip_phylink_validate(struct dsa_switch *ds, int port,
	return;
}

static void gswip_port_set_link(struct gswip_priv *priv, int port, bool link)
{
	u32 mdio_phy;

	if (link)
		mdio_phy = GSWIP_MDIO_PHY_LINK_UP;
	else
		mdio_phy = GSWIP_MDIO_PHY_LINK_DOWN;

	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_LINK_MASK, mdio_phy,
			GSWIP_MDIO_PHYp(port));
}

static void gswip_port_set_speed(struct gswip_priv *priv, int port, int speed,
				 phy_interface_t interface)
{
	u32 mdio_phy = 0, mii_cfg = 0, mac_ctrl_0 = 0;

	switch (speed) {
	case SPEED_10:
		mdio_phy = GSWIP_MDIO_PHY_SPEED_M10;

		if (interface == PHY_INTERFACE_MODE_RMII)
			mii_cfg = GSWIP_MII_CFG_RATE_M50;
		else
			mii_cfg = GSWIP_MII_CFG_RATE_M2P5;

		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII;
		break;

	case SPEED_100:
		mdio_phy = GSWIP_MDIO_PHY_SPEED_M100;

		if (interface == PHY_INTERFACE_MODE_RMII)
			mii_cfg = GSWIP_MII_CFG_RATE_M50;
		else
			mii_cfg = GSWIP_MII_CFG_RATE_M25;

		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_MII;
		break;

	case SPEED_1000:
		mdio_phy = GSWIP_MDIO_PHY_SPEED_G1;

		mii_cfg = GSWIP_MII_CFG_RATE_M125;

		mac_ctrl_0 = GSWIP_MAC_CTRL_0_GMII_RGMII;
		break;
	}

	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_SPEED_MASK, mdio_phy,
			GSWIP_MDIO_PHYp(port));
	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_RATE_MASK, mii_cfg, port);
	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_GMII_MASK, mac_ctrl_0,
			  GSWIP_MAC_CTRL_0p(port));
}

static void gswip_port_set_duplex(struct gswip_priv *priv, int port, int duplex)
{
	u32 mac_ctrl_0, mdio_phy;

	if (duplex == DUPLEX_FULL) {
		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_EN;
		mdio_phy = GSWIP_MDIO_PHY_FDUP_EN;
	} else {
		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FDUP_DIS;
		mdio_phy = GSWIP_MDIO_PHY_FDUP_DIS;
	}

	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FDUP_MASK, mac_ctrl_0,
			  GSWIP_MAC_CTRL_0p(port));
	gswip_mdio_mask(priv, GSWIP_MDIO_PHY_FDUP_MASK, mdio_phy,
			GSWIP_MDIO_PHYp(port));
}

static void gswip_port_set_pause(struct gswip_priv *priv, int port,
				 bool tx_pause, bool rx_pause)
{
	u32 mac_ctrl_0, mdio_phy;

	if (tx_pause && rx_pause) {
		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RXTX;
		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN |
			   GSWIP_MDIO_PHY_FCONRX_EN;
	} else if (tx_pause) {
		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_TX;
		mdio_phy = GSWIP_MDIO_PHY_FCONTX_EN |
			   GSWIP_MDIO_PHY_FCONRX_DIS;
	} else if (rx_pause) {
		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_RX;
		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS |
			   GSWIP_MDIO_PHY_FCONRX_EN;
	} else {
		mac_ctrl_0 = GSWIP_MAC_CTRL_0_FCON_NONE;
		mdio_phy = GSWIP_MDIO_PHY_FCONTX_DIS |
			   GSWIP_MDIO_PHY_FCONRX_DIS;
	}

	gswip_switch_mask(priv, GSWIP_MAC_CTRL_0_FCON_MASK,
			  mac_ctrl_0, GSWIP_MAC_CTRL_0p(port));
	gswip_mdio_mask(priv,
			GSWIP_MDIO_PHY_FCONTX_MASK |
			GSWIP_MDIO_PHY_FCONRX_MASK,
			mdio_phy, GSWIP_MDIO_PHYp(port));
}

static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,
				     unsigned int mode,
				     const struct phylink_link_state *state)
@@ -1474,6 +1603,9 @@ static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,
		break;
	case PHY_INTERFACE_MODE_RMII:
		miicfg |= GSWIP_MII_CFG_MODE_RMIIM;

		/* Configure the RMII clock as output: */
		miicfg |= GSWIP_MII_CFG_RMII_CLK;
		break;
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
@@ -1486,7 +1618,11 @@ static void gswip_phylink_mac_config(struct dsa_switch *ds, int port,
			"Unsupported interface: %d\n", state->interface);
		return;
	}
	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_MODE_MASK, miicfg, port);

	gswip_mii_mask_cfg(priv,
			   GSWIP_MII_CFG_MODE_MASK | GSWIP_MII_CFG_RMII_CLK |
			   GSWIP_MII_CFG_RGMII_IBS | GSWIP_MII_CFG_LDCLKDIS,
			   miicfg, port);

	switch (state->interface) {
	case PHY_INTERFACE_MODE_RGMII_ID:
@@ -1511,6 +1647,9 @@ static void gswip_phylink_mac_link_down(struct dsa_switch *ds, int port,
	struct gswip_priv *priv = ds->priv;

	gswip_mii_mask_cfg(priv, GSWIP_MII_CFG_EN, 0, port);

	if (!dsa_is_cpu_port(ds, port))
		gswip_port_set_link(priv, port, false);
}

static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,
@@ -1522,6 +1661,13 @@ static void gswip_phylink_mac_link_up(struct dsa_switch *ds, int port,
{
	struct gswip_priv *priv = ds->priv;

	if (!dsa_is_cpu_port(ds, port)) {
		gswip_port_set_link(priv, port, true);
		gswip_port_set_speed(priv, port, speed, interface);
		gswip_port_set_duplex(priv, port, duplex);
		gswip_port_set_pause(priv, port, tx_pause, rx_pause);
	}

	gswip_mii_mask_cfg(priv, 0, GSWIP_MII_CFG_EN, port);
}