| From 2ab6fa0c761c6722cacf4eaa38a0dcbd5ddfa8d1 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 8 Nov 2021 22:49:18 +0100 |
| Subject: net: marvell: mvpp2: Fix wrong SerDes reconfiguration order |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: Marek Behún <kabel@kernel.org> |
| |
| [ Upstream commit bb7bbb6e36474933540c24ae1f1ad651b843981f ] |
| |
| Commit bfe301ebbc94 ("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: bfe301ebbc94 ("net: mvpp2: convert to use mac_prepare()/mac_finish()") |
| Signed-off-by: Marek Behún <kabel@kernel.org> |
| Signed-off-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> |
| Signed-off-by: David S. Miller <davem@davemloft.net> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| .../net/ethernet/marvell/mvpp2/mvpp2_main.c | 38 ++++++++++--------- |
| 1 file changed, 20 insertions(+), 18 deletions(-) |
| |
| diff --git a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c |
| index 3229bafa2a2c7..3e673e40e878e 100644 |
| --- a/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c |
| +++ b/drivers/net/ethernet/marvell/mvpp2/mvpp2_main.c |
| @@ -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); |
| @@ -6462,6 +6464,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); |
| } |
| } |
| |
| @@ -6516,9 +6521,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); |
| } |
| @@ -6945,7 +6947,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); |
| } |
| -- |
| 2.33.0 |
| |