net: marvell: mvpp2: Fix wrong SerDes reconfiguration order
Commitbfe301ebbc
("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:bfe301ebbc
("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>
This commit is contained in:
parent
7a166854b4
commit
bb7bbb6e36
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user