From b1c7b87443c2c12c4fe095114736b8ad6f963f67 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 5 Jul 2020 19:16:22 +0300 Subject: net: dsa: felix: support half-duplex link modes Ping tested: [ 11.808455] mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Full - flow control rx/tx [ 11.816497] IPv6: ADDRCONF(NETDEV_CHANGE): swp0: link becomes ready [root@LS1028ARDB ~] # ethtool -s swp0 advertise 0x4 [ 18.844591] mscc_felix 0000:00:00.5 swp0: Link is Down [ 22.048337] mscc_felix 0000:00:00.5 swp0: Link is Up - 100Mbps/Half - flow control off [root@LS1028ARDB ~] # ip addr add 192.168.1.1/24 dev swp0 [root@LS1028ARDB ~] # ping 192.168.1.2 PING 192.168.1.2 (192.168.1.2): 56 data bytes (...) ^C--- 192.168.1.2 ping statistics --- 3 packets transmitted, 3 packets received, 0% packet loss round-trip min/avg/max = 0.383/0.611/1.051 ms [root@LS1028ARDB ~] # ethtool -s swp0 advertise 0x10 [ 355.637747] mscc_felix 0000:00:00.5 swp0: Link is Down [ 358.788034] mscc_felix 0000:00:00.5 swp0: Link is Up - 1Gbps/Half - flow control off [root@LS1028ARDB ~] # ping 192.168.1.2 PING 192.168.1.2 (192.168.1.2): 56 data bytes (...) ^C --- 192.168.1.2 ping statistics --- 16 packets transmitted, 16 packets received, 0% packet loss round-trip min/avg/max = 0.301/0.384/1.138 ms Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Reviewed-by: Russell King Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/net/dsa/ocelot/felix.c') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 75020af7f7a4..f54648dff0ec 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -194,13 +194,15 @@ static void felix_phylink_validate(struct dsa_switch *ds, int port, return; } - /* No half-duplex. */ phylink_set_port_modes(mask); phylink_set(mask, Autoneg); phylink_set(mask, Pause); phylink_set(mask, Asym_Pause); + phylink_set(mask, 10baseT_Half); phylink_set(mask, 10baseT_Full); + phylink_set(mask, 100baseT_Half); phylink_set(mask, 100baseT_Full); + phylink_set(mask, 1000baseT_Half); phylink_set(mask, 1000baseT_Full); if (state->interface == PHY_INTERFACE_MODE_INTERNAL || -- cgit From da1c4ba1f741ee8f7a7f88d52bc2482fae26200d Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 5 Jul 2020 19:16:23 +0300 Subject: net: dsa: felix: unconditionally configure MAC speed to 1000Mbps In VSC9959, the PCS is the one who performs rate adaptation (symbol duplication) to the speed negotiated by the PHY. The MAC is unaware of that and must remain configured for gigabit. If it is configured at OCELOT_SPEED_10 or OCELOT_SPEED_100, it'll start transmitting PAUSE frames out of control and never recover, _even if_ we then reconfigure it at OCELOT_SPEED_1000 afterwards. This patch fixes a bug that luckily did not have any functional impact. We were writing 10, 100, 1000 etc into this 2-bit field in DEV_CLOCK_CFG, but the hardware expects values in the range 0, 1, 2, 3. So all speed values were getting truncated to 0, which is OCELOT_SPEED_2500, and which also appears to be fine. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'drivers/net/dsa/ocelot/felix.c') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index f54648dff0ec..4d819cc45bed 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -240,9 +240,14 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, u32 mac_fc_cfg; /* Take port out of reset by clearing the MAC_TX_RST, MAC_RX_RST and - * PORT_RST bits in CLOCK_CFG + * PORT_RST bits in DEV_CLOCK_CFG. Note that the way this system is + * integrated is that the MAC speed is fixed and it's the PCS who is + * performing the rate adaptation, so we have to write "1000Mbps" into + * the LINK_SPEED field of DEV_CLOCK_CFG (which is also its default + * value). */ - ocelot_port_writel(ocelot_port, DEV_CLOCK_CFG_LINK_SPEED(state->speed), + ocelot_port_writel(ocelot_port, + DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), DEV_CLOCK_CFG); /* Flow control. Link speed is only used here to evaluate the time -- cgit From 151a7cee728a89d909096f552108692905b66aaa Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 5 Jul 2020 19:16:24 +0300 Subject: net: dsa: felix: set proper pause frame timers based on link speed state->speed holds a value of 10, 100, 1000 or 2500, but SYS_MAC_FC_CFG_FC_LINK_SPEED expects a value in the range 0, 1, 2 or 3. So set the correct speed encoding into this register. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) (limited to 'drivers/net/dsa/ocelot/felix.c') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 4d819cc45bed..4684339012c5 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -250,10 +250,25 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), DEV_CLOCK_CFG); - /* Flow control. Link speed is only used here to evaluate the time - * specification in incoming pause frames. - */ - mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(state->speed); + switch (state->speed) { + case SPEED_10: + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); + break; + case SPEED_100: + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(2); + break; + case SPEED_1000: + case SPEED_2500: + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); + break; + case SPEED_UNKNOWN: + mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(0); + break; + default: + dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", + port, state->speed); + return; + } /* handle Rx pause in all cases, with 2500base-X this is used for rate * adaptation. @@ -265,6 +280,10 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | SYS_MAC_FC_CFG_ZERO_PAUSE_ENA; + + /* Flow control. Link speed is only used here to evaluate the time + * specification in incoming pause frames. + */ ocelot_write_rix(ocelot, mac_fc_cfg, SYS_MAC_FC_CFG, port); ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); -- cgit From b4c2354537b41a13805d28f6f5e8a811d8097e8a Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 5 Jul 2020 19:16:25 +0300 Subject: net: dsa: felix: delete .phylink_mac_an_restart code Phylink uses the .mac_an_restart method to offer the user an implementation of the "ethtool -r" behavior, when the media-side auto negotiation can be restarted by the local MAC PCS. This is the case for fiber modes 1000Base-X and 2500Base-X (IEEE clause 37) that don't have an Ethernet PHY connected locally, and the media is connected to the MAC PCS directly. On the other hand, the Cisco SGMII and USXGMII standards also have an auto negotiation mechanism based on IEEE 802.3 clause 37 (their respective specs require a MAC PCS and a PHY PCS to implement the same state machine, which is described in IEEE 802.3 "Auto-Negotiation Figure 37-6"), so the ability to restart auto-negotiation is intrinsically symmetrical (the MAC PCS can do it too). However, it appears that not all SGMII/USXGMII PHYs have logic to restart the MDI-side auto-negotiation process when they detect a transition of the SGMII link from data mode to configuration mode. Some do (VSC8234) and some don't (AR8033, MV88E1111). IEEE and/or Cisco specification wordings to not help to prove whether propagating the "AN restart" event from MII side ("mr_restart_an") to MDI side ("mr_restart_negotiation") is required behavior - neither of them specifies any mandatory interaction between the clause 37 AN state machine from Figure 37-6 and the clause 28 AN state machine from Figure 28-18. Therefore, even if a certain behavior could be proven as being required, real-life SGMII/USXGMII PHYs are inconsistent enough that a clause 37 AN restart cannot be used by phylink to reliably trigger a media-side renegotiation, when the user requests it via ethtool. The only remaining use that the .mac_an_restart callback might possibly have, given what we know now, is to implement some silicon quirks, but so far that has proven to not be necessary. So remove this code for now, since it never gets called and we don't foresee any circumstance in which it might be, either. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 10 ---------- 1 file changed, 10 deletions(-) (limited to 'drivers/net/dsa/ocelot/felix.c') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 4684339012c5..57c400a67f16 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -296,15 +296,6 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, state->speed); } -static void felix_phylink_mac_an_restart(struct dsa_switch *ds, int port) -{ - struct ocelot *ocelot = ds->priv; - struct felix *felix = ocelot_to_felix(ocelot); - - if (felix->info->pcs_an_restart) - felix->info->pcs_an_restart(ocelot, port); -} - static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, unsigned int link_an_mode, phy_interface_t interface) @@ -810,7 +801,6 @@ static const struct dsa_switch_ops felix_switch_ops = { .phylink_validate = felix_phylink_validate, .phylink_mac_link_state = felix_phylink_mac_pcs_get_state, .phylink_mac_config = felix_phylink_mac_config, - .phylink_mac_an_restart = felix_phylink_mac_an_restart, .phylink_mac_link_down = felix_phylink_mac_link_down, .phylink_mac_link_up = felix_phylink_mac_link_up, .port_enable = felix_port_enable, -- cgit From 7e14a2dc8c656acea48729daf3f617aa76d62937 Mon Sep 17 00:00:00 2001 From: Vladimir Oltean Date: Sun, 5 Jul 2020 19:16:26 +0300 Subject: net: dsa: felix: use resolved link config in mac_link_up() Phylink now requires that parameters established through auto-negotiation be written into the MAC at the time of the mac_link_up() callback. In the case of felix, that means taking the port out of reset, setting the correct timers for PAUSE frames, and enabling/disabling TX flow control. This patch also splits the inband and noinband configuration of the vsc9959 PCS (currently found in a function called "init") into 2 different functions, which have a nomenclature closer to phylink: "config", for inband setup, and "link_up", for noinband (forced) setup. This is necessary as a preparation step for giving up control of the PCS to phylink, which will be done in further patch series. Signed-off-by: Vladimir Oltean Reviewed-by: Florian Fainelli Signed-off-by: David S. Miller --- drivers/net/dsa/ocelot/felix.c | 76 ++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 37 deletions(-) (limited to 'drivers/net/dsa/ocelot/felix.c') diff --git a/drivers/net/dsa/ocelot/felix.c b/drivers/net/dsa/ocelot/felix.c index 57c400a67f16..75652ed99b24 100644 --- a/drivers/net/dsa/ocelot/felix.c +++ b/drivers/net/dsa/ocelot/felix.c @@ -233,6 +233,32 @@ static int felix_phylink_mac_pcs_get_state(struct dsa_switch *ds, int port, static void felix_phylink_mac_config(struct dsa_switch *ds, int port, unsigned int link_an_mode, const struct phylink_link_state *state) +{ + struct ocelot *ocelot = ds->priv; + struct felix *felix = ocelot_to_felix(ocelot); + + if (felix->info->pcs_config) + felix->info->pcs_config(ocelot, port, link_an_mode, state); +} + +static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, + unsigned int link_an_mode, + phy_interface_t interface) +{ + struct ocelot *ocelot = ds->priv; + struct ocelot_port *ocelot_port = ocelot->ports[port]; + + ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); + ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, + QSYS_SWITCH_PORT_MODE, port); +} + +static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, + unsigned int link_an_mode, + phy_interface_t interface, + struct phy_device *phydev, + int speed, int duplex, + bool tx_pause, bool rx_pause) { struct ocelot *ocelot = ds->priv; struct ocelot_port *ocelot_port = ocelot->ports[port]; @@ -250,7 +276,7 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, DEV_CLOCK_CFG_LINK_SPEED(OCELOT_SPEED_1000), DEV_CLOCK_CFG); - switch (state->speed) { + switch (speed) { case SPEED_10: mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(3); break; @@ -261,12 +287,9 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, case SPEED_2500: mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(1); break; - case SPEED_UNKNOWN: - mac_fc_cfg = SYS_MAC_FC_CFG_FC_LINK_SPEED(0); - break; default: dev_err(ocelot->dev, "Unsupported speed on port %d: %d\n", - port, state->speed); + port, speed); return; } @@ -275,7 +298,7 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, */ mac_fc_cfg |= SYS_MAC_FC_CFG_RX_FC_ENA; - if (state->pause & MLO_PAUSE_TX) + if (tx_pause) mac_fc_cfg |= SYS_MAC_FC_CFG_TX_FC_ENA | SYS_MAC_FC_CFG_PAUSE_VAL_CFG(0xffff) | SYS_MAC_FC_CFG_FC_LATENCY_CFG(0x7) | @@ -288,37 +311,9 @@ static void felix_phylink_mac_config(struct dsa_switch *ds, int port, ocelot_write_rix(ocelot, 0, ANA_POL_FLOWC, port); - if (felix->info->pcs_init) - felix->info->pcs_init(ocelot, port, link_an_mode, state); - - if (felix->info->port_sched_speed_set) - felix->info->port_sched_speed_set(ocelot, port, - state->speed); -} - -static void felix_phylink_mac_link_down(struct dsa_switch *ds, int port, - unsigned int link_an_mode, - phy_interface_t interface) -{ - struct ocelot *ocelot = ds->priv; - struct ocelot_port *ocelot_port = ocelot->ports[port]; - - ocelot_port_writel(ocelot_port, 0, DEV_MAC_ENA_CFG); - ocelot_rmw_rix(ocelot, 0, QSYS_SWITCH_PORT_MODE_PORT_ENA, - QSYS_SWITCH_PORT_MODE, port); -} - -static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, - unsigned int link_an_mode, - phy_interface_t interface, - struct phy_device *phydev, - int speed, int duplex, - bool tx_pause, bool rx_pause) -{ - struct ocelot *ocelot = ds->priv; - struct ocelot_port *ocelot_port = ocelot->ports[port]; - - /* Enable MAC module */ + /* Undo the effects of felix_phylink_mac_link_down: + * enable MAC module + */ ocelot_port_writel(ocelot_port, DEV_MAC_ENA_CFG_RX_ENA | DEV_MAC_ENA_CFG_TX_ENA, DEV_MAC_ENA_CFG); @@ -335,6 +330,13 @@ static void felix_phylink_mac_link_up(struct dsa_switch *ds, int port, QSYS_SWITCH_PORT_MODE_SCH_NEXT_CFG(1) | QSYS_SWITCH_PORT_MODE_PORT_ENA, QSYS_SWITCH_PORT_MODE, port); + + if (felix->info->pcs_link_up) + felix->info->pcs_link_up(ocelot, port, link_an_mode, interface, + speed, duplex); + + if (felix->info->port_sched_speed_set) + felix->info->port_sched_speed_set(ocelot, port, speed); } static void felix_port_qos_map_init(struct ocelot *ocelot, int port) -- cgit