Commit bb7bbb6e authored by Marek Behún's avatar Marek Behún Committed by David S. Miller
Browse files

net: marvell: mvpp2: Fix wrong SerDes reconfiguration order



Commit bfe301eb ("net: mvpp2: convert to use
mac_prepare()/mac_finish()") introduced a bug wherein it leaves the MAC
RESET register asserted after mac_finish(), due to wrong order of
function calls.

Before it was:
  .mac_config()
    mvpp22_mode_reconfigure()
      assert reset
    mvpp2_xlg_config()
      deassert reset

Now it is:
  .mac_prepare()
  .mac_config()
    mvpp2_xlg_config()
      deassert reset
  .mac_finish()
    mvpp2_xlg_config()
      assert reset

Obviously this is wrong.

This bug is triggered when phylink tries to change the PHY interface
mode from a GMAC mode (sgmii, 1000base-x, 2500base-x) to XLG mode
(10gbase-r, xaui). The XLG mode does not work since reset is left
asserted. Only after
  ifconfig down && ifconfig up
is called will the XLG mode work.

Move the call to mvpp22_mode_reconfigure() to .mac_prepare()
implementation. Since some of the subsequent functions need to know
whether the interface is being changed, we unfortunately also need to
pass around the new interface mode before setting port->phy_interface.

Fixes: bfe301eb ("net: mvpp2: convert to use mac_prepare()/mac_finish()")
Signed-off-by: default avatarMarek Behún <kabel@kernel.org>
Signed-off-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 7a166854
Loading
Loading
Loading
Loading
+20 −18
Original line number Diff line number Diff line
@@ -1605,7 +1605,7 @@ static void mvpp22_gop_fca_set_periodic_timer(struct mvpp2_port *port)
	mvpp22_gop_fca_enable_periodic(port, true);
}

static int mvpp22_gop_init(struct mvpp2_port *port)
static int mvpp22_gop_init(struct mvpp2_port *port, phy_interface_t interface)
{
	struct mvpp2 *priv = port->priv;
	u32 val;
@@ -1613,7 +1613,7 @@ static int mvpp22_gop_init(struct mvpp2_port *port)
	if (!priv->sysctrl_base)
		return 0;

	switch (port->phy_interface) {
	switch (interface) {
	case PHY_INTERFACE_MODE_RGMII:
	case PHY_INTERFACE_MODE_RGMII_ID:
	case PHY_INTERFACE_MODE_RGMII_RXID:
@@ -1743,15 +1743,15 @@ static void mvpp22_gop_setup_irq(struct mvpp2_port *port)
 * lanes by the physical layer. This is why configurations like
 * "PPv2 (2500BaseX) - COMPHY (2500SGMII)" are valid.
 */
static int mvpp22_comphy_init(struct mvpp2_port *port)
static int mvpp22_comphy_init(struct mvpp2_port *port,
			      phy_interface_t interface)
{
	int ret;

	if (!port->comphy)
		return 0;

	ret = phy_set_mode_ext(port->comphy, PHY_MODE_ETHERNET,
			       port->phy_interface);
	ret = phy_set_mode_ext(port->comphy, PHY_MODE_ETHERNET, interface);
	if (ret)
		return ret;

@@ -2172,7 +2172,8 @@ static void mvpp22_pcs_reset_assert(struct mvpp2_port *port)
	writel(val & ~MVPP22_XPCS_CFG0_RESET_DIS, xpcs + MVPP22_XPCS_CFG0);
}

static void mvpp22_pcs_reset_deassert(struct mvpp2_port *port)
static void mvpp22_pcs_reset_deassert(struct mvpp2_port *port,
				      phy_interface_t interface)
{
	struct mvpp2 *priv = port->priv;
	void __iomem *mpcs, *xpcs;
@@ -2184,7 +2185,7 @@ static void mvpp22_pcs_reset_deassert(struct mvpp2_port *port)
	mpcs = priv->iface_base + MVPP22_MPCS_BASE(port->gop_id);
	xpcs = priv->iface_base + MVPP22_XPCS_BASE(port->gop_id);

	switch (port->phy_interface) {
	switch (interface) {
	case PHY_INTERFACE_MODE_10GBASER:
		val = readl(mpcs + MVPP22_MPCS_CLK_RESET);
		val |= MAC_CLK_RESET_MAC | MAC_CLK_RESET_SD_RX |
@@ -4529,7 +4530,8 @@ static int mvpp2_poll(struct napi_struct *napi, int budget)
	return rx_done;
}

static void mvpp22_mode_reconfigure(struct mvpp2_port *port)
static void mvpp22_mode_reconfigure(struct mvpp2_port *port,
				    phy_interface_t interface)
{
	u32 ctrl3;

@@ -4540,18 +4542,18 @@ static void mvpp22_mode_reconfigure(struct mvpp2_port *port)
	mvpp22_pcs_reset_assert(port);

	/* comphy reconfiguration */
	mvpp22_comphy_init(port);
	mvpp22_comphy_init(port, interface);

	/* gop reconfiguration */
	mvpp22_gop_init(port);
	mvpp22_gop_init(port, interface);

	mvpp22_pcs_reset_deassert(port);
	mvpp22_pcs_reset_deassert(port, interface);

	if (mvpp2_port_supports_xlg(port)) {
		ctrl3 = readl(port->base + MVPP22_XLG_CTRL3_REG);
		ctrl3 &= ~MVPP22_XLG_CTRL3_MACMODESELECT_MASK;

		if (mvpp2_is_xlg(port->phy_interface))
		if (mvpp2_is_xlg(interface))
			ctrl3 |= MVPP22_XLG_CTRL3_MACMODESELECT_10G;
		else
			ctrl3 |= MVPP22_XLG_CTRL3_MACMODESELECT_GMAC;
@@ -4559,7 +4561,7 @@ static void mvpp22_mode_reconfigure(struct mvpp2_port *port)
		writel(ctrl3, port->base + MVPP22_XLG_CTRL3_REG);
	}

	if (mvpp2_port_supports_xlg(port) && mvpp2_is_xlg(port->phy_interface))
	if (mvpp2_port_supports_xlg(port) && mvpp2_is_xlg(interface))
		mvpp2_xlg_max_rx_size_set(port);
	else
		mvpp2_gmac_max_rx_size_set(port);
@@ -4579,7 +4581,7 @@ static void mvpp2_start_dev(struct mvpp2_port *port)
	mvpp2_interrupts_enable(port);

	if (port->priv->hw_version >= MVPP22)
		mvpp22_mode_reconfigure(port);
		mvpp22_mode_reconfigure(port, port->phy_interface);

	if (port->phylink) {
		phylink_start(port->phylink);
@@ -6444,6 +6446,9 @@ static int mvpp2__mac_prepare(struct phylink_config *config, unsigned int mode,
			mvpp22_gop_mask_irq(port);

			phy_power_off(port->comphy);

			/* Reconfigure the serdes lanes */
			mvpp22_mode_reconfigure(port, interface);
		}
	}

@@ -6498,9 +6503,6 @@ static int mvpp2_mac_finish(struct phylink_config *config, unsigned int mode,
	    port->phy_interface != interface) {
		port->phy_interface = interface;

		/* Reconfigure the serdes lanes */
		mvpp22_mode_reconfigure(port);

		/* Unmask interrupts */
		mvpp22_gop_unmask_irq(port);
	}
@@ -6961,7 +6963,7 @@ static int mvpp2_port_probe(struct platform_device *pdev,
	 * driver does this, we can remove this code.
	 */
	if (port->comphy) {
		err = mvpp22_comphy_init(port);
		err = mvpp22_comphy_init(port, port->phy_interface);
		if (err == 0)
			phy_power_off(port->comphy);
	}