From 2d1f90f9ba8348ebc85fe57a0034509b21570a85 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Jun 2020 11:28:08 +0100 Subject: [PATCH 1/3] net: dsa/bcm_sf2: fix incorrect usage of state->link state->link has never been valid in mac_config() implementations - while it may be correct in some calls, it is not true that it can be relied upon. Fix bcm_sf2 to use the correct method of handling forced link status. Reviewed-by: Florian Fainelli Tested-by: Florian Fainelli Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 946e41f020a5..5a8759d2de6c 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -618,8 +618,6 @@ force_link: break; } - if (state->link) - reg |= LINK_STS; if (state->duplex == DUPLEX_FULL) reg |= DUPLX_MODE; @@ -650,6 +648,20 @@ static void bcm_sf2_sw_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode, phy_interface_t interface) { + struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); + u32 reg, offset; + + if (port != core_readl(priv, CORE_IMP0_PRT_ID)) { + if (priv->type == BCM7445_DEVICE_ID) + offset = CORE_STS_OVERRIDE_GMIIP_PORT(port); + else + offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); + + reg = core_readl(priv, offset); + reg &= ~LINK_STS; + core_writel(priv, reg, offset); + } + bcm_sf2_sw_mac_link_set(ds, port, interface, false); } @@ -662,9 +674,21 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); struct ethtool_eee *p = &priv->dev->ports[port].eee; + u32 reg, offset; bcm_sf2_sw_mac_link_set(ds, port, interface, true); + if (port != core_readl(priv, CORE_IMP0_PRT_ID)) { + if (priv->type == BCM7445_DEVICE_ID) + offset = CORE_STS_OVERRIDE_GMIIP_PORT(port); + else + offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); + + reg = core_readl(priv, offset); + reg |= LINK_STS; + core_writel(priv, reg, offset); + } + if (mode == MLO_AN_PHY && phydev) p->eee_enabled = b53_eee_init(ds, port, phydev); } From 50cc2020a8055491534929abccda5047731f24b8 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Jun 2020 11:28:13 +0100 Subject: [PATCH 2/3] net: dsa/bcm_sf2: move speed/duplex forcing to mac_link_up() Convert the bcm_sf2 to use the finalised speed and duplex in its mac_link_up() call rather than the parameters in mac_config(). Reviewed-by: Florian Fainelli Tested-by: Florian Fainelli Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 43 +++++++++++++++------------------------ 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 5a8759d2de6c..062e6efad53f 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -558,16 +558,11 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, { struct bcm_sf2_priv *priv = bcm_sf2_to_priv(ds); u32 id_mode_dis = 0, port_mode; - u32 reg, offset; + u32 reg; if (port == core_readl(priv, CORE_IMP0_PRT_ID)) return; - if (priv->type == BCM7445_DEVICE_ID) - offset = CORE_STS_OVERRIDE_GMIIP_PORT(port); - else - offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); - switch (state->interface) { case PHY_INTERFACE_MODE_RGMII: id_mode_dis = 1; @@ -582,8 +577,8 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, port_mode = EXT_REVMII; break; default: - /* all other PHYs: internal and MoCA */ - goto force_link; + /* Nothing required for all other PHYs: internal and MoCA */ + return; } /* Clear id_mode_dis bit, and the existing port mode, let @@ -605,23 +600,6 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, } reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); - -force_link: - /* Force link settings detected from the PHY */ - reg = SW_OVERRIDE; - switch (state->speed) { - case SPEED_1000: - reg |= SPDSTS_1000 << SPEED_SHIFT; - break; - case SPEED_100: - reg |= SPDSTS_100 << SPEED_SHIFT; - break; - } - - if (state->duplex == DUPLEX_FULL) - reg |= DUPLX_MODE; - - core_writel(priv, reg, offset); } static void bcm_sf2_sw_mac_link_set(struct dsa_switch *ds, int port, @@ -684,8 +662,19 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, else offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); - reg = core_readl(priv, offset); - reg |= LINK_STS; + reg = SW_OVERRIDE | LINK_STS; + switch (speed) { + case SPEED_1000: + reg |= SPDSTS_1000 << SPEED_SHIFT; + break; + case SPEED_100: + reg |= SPDSTS_100 << SPEED_SHIFT; + break; + } + + if (duplex == DUPLEX_FULL) + reg |= DUPLX_MODE; + core_writel(priv, reg, offset); } From 981015ac60dc5e073081e17a46189ebcfffeea19 Mon Sep 17 00:00:00 2001 From: Russell King Date: Tue, 30 Jun 2020 11:28:18 +0100 Subject: [PATCH 3/3] net: dsa/bcm_sf2: move pause mode setting into mac_link_up() bcm_sf2 only appears to support pause modes on RGMII interfaces (the enable bits are in the RGMII control register.) Setup the pause modes for RGMII connections. Reviewed-by: Florian Fainelli Tested-by: Florian Fainelli Signed-off-by: Russell King Signed-off-by: David S. Miller --- drivers/net/dsa/bcm_sf2.c | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c index 062e6efad53f..bafddb35f3a9 100644 --- a/drivers/net/dsa/bcm_sf2.c +++ b/drivers/net/dsa/bcm_sf2.c @@ -587,18 +587,11 @@ static void bcm_sf2_sw_mac_config(struct dsa_switch *ds, int port, reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); reg &= ~ID_MODE_DIS; reg &= ~(PORT_MODE_MASK << PORT_MODE_SHIFT); - reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); reg |= port_mode; if (id_mode_dis) reg |= ID_MODE_DIS; - if (state->pause & MLO_PAUSE_TXRX_MASK) { - if (state->pause & MLO_PAUSE_TX) - reg |= TX_PAUSE_EN; - reg |= RX_PAUSE_EN; - } - reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); } @@ -662,6 +655,21 @@ static void bcm_sf2_sw_mac_link_up(struct dsa_switch *ds, int port, else offset = CORE_STS_OVERRIDE_GMIIP2_PORT(port); + if (interface == PHY_INTERFACE_MODE_RGMII || + interface == PHY_INTERFACE_MODE_RGMII_TXID || + interface == PHY_INTERFACE_MODE_MII || + interface == PHY_INTERFACE_MODE_REVMII) { + reg = reg_readl(priv, REG_RGMII_CNTRL_P(port)); + reg &= ~(RX_PAUSE_EN | TX_PAUSE_EN); + + if (tx_pause) + reg |= TX_PAUSE_EN; + if (rx_pause) + reg |= RX_PAUSE_EN; + + reg_writel(priv, reg, REG_RGMII_CNTRL_P(port)); + } + reg = SW_OVERRIDE | LINK_STS; switch (speed) { case SPEED_1000: