From 6d790a1ccbe34e443109e063abb82baf5f2cda29 Mon Sep 17 00:00:00 2001 From: Jonas Jelonek Date: Wed, 9 Sep 2026 10:25:45 +0000 Subject: [PATCH] realtek: dsa: describe MAC force mode fields Move the family-specific MAC force mode register layout into the switch configuration. This removes family checks from the RTL83xx link-up path and converts RTL930x handling to the same field descriptions. Describe link-state and flow-control force enables separately along with the fields used to construct resolved MAC state. This allows phylink's resolved pause settings to remain forced when link state is controlled by hardware. Add the initial RTL931x link-force description in preparation for later RTL931x support. Assisted-by: ChatGPT (OpenAI GPT-5.6 Sol) Link: https://github.com/openwrt/openwrt/pull/25118 Signed-off-by: Jonas Jelonek --- .../files-6.18/drivers/net/dsa/rtl83xx/dsa.c | 111 ++++++------------ .../files-6.18/drivers/net/dsa/rtl83xx/mac.h | 31 +++++ .../drivers/net/dsa/rtl83xx/rtl-otto.h | 2 +- .../drivers/net/dsa/rtl83xx/rtl838x.c | 9 +- .../drivers/net/dsa/rtl83xx/rtl839x.c | 9 +- .../drivers/net/dsa/rtl83xx/rtl930x.c | 11 +- .../drivers/net/dsa/rtl83xx/rtl931x.c | 8 +- 7 files changed, 99 insertions(+), 82 deletions(-) diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c index c6129e1f3ae..07b97bafdb2 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/dsa.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only #include +#include #include #include #include @@ -36,23 +37,6 @@ #define RTL_SPEED_10000 4 #define RTL838X_NWAY_EN BIT(2) -#define RTL838X_DUPLEX_MODE BIT(3) -#define RTL838X_SPEED_SHIFT (4) -#define RTL838X_SPEED_MASK (3 << RTL838X_SPEED_SHIFT) -#define RTL838X_TX_PAUSE_EN BIT(6) -#define RTL838X_RX_PAUSE_EN BIT(7) - -#define RTL839X_DUPLEX_MODE BIT(2) -#define RTL839X_SPEED_SHIFT (3) -#define RTL839X_SPEED_MASK (3 << RTL839X_SPEED_SHIFT) -#define RTL839X_TX_PAUSE_EN BIT(5) -#define RTL839X_RX_PAUSE_EN BIT(6) - -#define RTL930X_DUPLEX_MODE BIT(2) -#define RTL930X_SPEED_SHIFT (3) -#define RTL930X_SPEED_MASK (15 << RTL930X_SPEED_SHIFT) -#define RTL930X_TX_PAUSE_EN BIT(7) -#define RTL930X_RX_PAUSE_EN BIT(8) #define RTL930X_PORT_IGNORE 0x3f @@ -336,6 +320,7 @@ static void rtldsa_93xx_phylink_mac_config(struct phylink_config *config, { struct dsa_port *dp = dsa_phylink_to_port(config); struct rtl838x_switch_priv *priv = dp->ds->priv; + const struct rtldsa_mac_force_mode_cfg *cfg; bool force_dynamic_phy; int port = dp->index; @@ -343,6 +328,7 @@ static void rtldsa_93xx_phylink_mac_config(struct phylink_config *config, if (port == priv->r->cpu_port) return; + cfg = &priv->r->mac_force_mode; force_dynamic_phy = priv->family_id == RTL9300_FAMILY_ID && !priv->ports[port].phy && (mode == MLO_AN_PHY || state->interface == PHY_INTERFACE_MODE_SGMII); @@ -358,7 +344,7 @@ static void rtldsa_93xx_phylink_mac_config(struct phylink_config *config, (mode == MLO_AN_FIXED || force_dynamic_phy)) { /* Keep links that require force mode forced down. */ regmap_write(priv->map, priv->r->mac_force_mode_ctrl(port), - RTL930X_FORCE_EN | RTL930X_MAC_FORCE_FC_EN); + cfg->force_en_mask | cfg->fc_force_en_mask); if (force_dynamic_phy) rtldsa_mac_link_state_source_set(priv, port, RTLDSA_MAC_LINK_STATE_SOURCE_PHY, @@ -375,9 +361,9 @@ static void rtldsa_phylink_mac_link_down(struct phylink_config *config, { struct dsa_port *dp = dsa_phylink_to_port(config); struct rtl838x_switch_priv *priv = dp->ds->priv; + const struct rtldsa_mac_force_mode_cfg *cfg; bool force_dynamic_phy; int port = dp->index; - u32 mask; force_dynamic_phy = priv->family_id == RTL9300_FAMILY_ID && !priv->ports[port].phy && @@ -392,24 +378,21 @@ static void rtldsa_phylink_mac_link_down(struct phylink_config *config, RTLDSA_MAC_LINK_STATE_SOURCE_PCS, interface); + cfg = &priv->r->mac_force_mode; if (priv->family_id == RTL9300_FAMILY_ID && (dsa_port_is_cpu(dp) || mode == MLO_AN_FIXED || force_dynamic_phy)) { /* Preserve force mode while forcing the link down. */ regmap_update_bits(priv->map, priv->r->mac_force_mode_ctrl(port), - RTL930X_FORCE_LINK_EN, 0); + cfg->link_up_mask, 0); if (force_dynamic_phy) rtldsa_mac_link_state_source_set(priv, port, RTLDSA_MAC_LINK_STATE_SOURCE_PHY, interface); } else { /* No longer force link */ - mask = priv->r->mac_force_mode_mask; - - if (priv->family_id == RTL9300_FAMILY_ID) - mask |= RTL930X_MAC_FORCE_FC_EN; - regmap_update_bits(priv->map, priv->r->mac_force_mode_ctrl(port), - mask, 0); + cfg->force_en_mask | cfg->fc_force_en_mask | + cfg->link_up_mask, 0); } } @@ -422,6 +405,7 @@ static void rtldsa_83xx_phylink_mac_link_up(struct phylink_config *config, { struct dsa_port *dp = dsa_phylink_to_port(config); struct rtl838x_switch_priv *priv = dp->ds->priv; + const struct rtldsa_mac_force_mode_cfg *cfg; int port = dp->index; u32 mcr, spdsel; @@ -432,42 +416,21 @@ static void rtldsa_83xx_phylink_mac_link_up(struct phylink_config *config, else spdsel = RTL_SPEED_10; + cfg = &priv->r->mac_force_mode; regmap_read(priv->map, priv->r->mac_force_mode_ctrl(port), &mcr); + mcr &= ~(cfg->rx_pause_mask | cfg->tx_pause_mask | + cfg->duplex_mask | cfg->speed_mask); + mcr |= cfg->link_up_mask; + mcr |= field_prep(cfg->speed_mask, spdsel); - if (priv->family_id == RTL8380_FAMILY_ID) { - mcr &= ~RTL838X_RX_PAUSE_EN; - mcr &= ~RTL838X_TX_PAUSE_EN; - mcr &= ~RTL838X_DUPLEX_MODE; - mcr &= ~RTL838X_SPEED_MASK; - mcr |= RTL83XX_FORCE_LINK_EN; - mcr |= spdsel << RTL838X_SPEED_SHIFT; - - if (tx_pause) - mcr |= RTL838X_TX_PAUSE_EN; - if (rx_pause) - mcr |= RTL838X_RX_PAUSE_EN; - if (duplex == DUPLEX_FULL || priv->lagmembers & BIT_ULL(port)) - mcr |= RTL838X_DUPLEX_MODE; - if (dsa_port_is_cpu(dp)) - mcr |= RTL83XX_FORCE_EN; - - } else if (priv->family_id == RTL8390_FAMILY_ID) { - mcr &= ~RTL839X_RX_PAUSE_EN; - mcr &= ~RTL839X_TX_PAUSE_EN; - mcr &= ~RTL839X_DUPLEX_MODE; - mcr &= ~RTL839X_SPEED_MASK; - mcr |= RTL83XX_FORCE_LINK_EN; - mcr |= spdsel << RTL839X_SPEED_SHIFT; - - if (tx_pause) - mcr |= RTL839X_TX_PAUSE_EN; - if (rx_pause) - mcr |= RTL839X_RX_PAUSE_EN; - if (duplex == DUPLEX_FULL || priv->lagmembers & BIT_ULL(port)) - mcr |= RTL839X_DUPLEX_MODE; - if (dsa_port_is_cpu(dp)) - mcr |= RTL83XX_FORCE_EN; - } + if (tx_pause) + mcr |= cfg->tx_pause_mask; + if (rx_pause) + mcr |= cfg->rx_pause_mask; + if (duplex == DUPLEX_FULL || priv->lagmembers & BIT_ULL(port)) + mcr |= cfg->duplex_mask; + if (dsa_port_is_cpu(dp)) + mcr |= cfg->force_en_mask; pr_debug("%s port %d, mode %x, speed %d, duplex %d, txpause %d, rxpause %d: set mcr=%08x\n", __func__, port, mode, speed, duplex, tx_pause, rx_pause, mcr); @@ -486,9 +449,10 @@ static void rtldsa_93xx_phylink_mac_link_up(struct phylink_config *config, { struct dsa_port *dp = dsa_phylink_to_port(config); struct rtl838x_switch_priv *priv = dp->ds->priv; + const struct rtldsa_mac_force_mode_cfg *cfg; int port = dp->index; bool dynamic_phy, force_dynamic_phy, keep_forced; - u32 force_en, mcr, spdsel; + u32 mcr, spdsel; if (priv->family_id != RTL9300_FAMILY_ID) goto restart; @@ -515,13 +479,13 @@ static void rtldsa_93xx_phylink_mac_link_up(struct phylink_config *config, * Dynamic USXGMII PHYs use PCS state after a force pulse refreshes the * MAC parameters; fixed links and CPU ports also remain forced. */ + cfg = &priv->r->mac_force_mode; dynamic_phy = !priv->ports[port].phy && phydev; force_dynamic_phy = dynamic_phy && (!phylink_autoneg_inband(mode) || interface == PHY_INTERFACE_MODE_SGMII); keep_forced = dsa_port_is_cpu(dp) || mode == MLO_AN_FIXED || force_dynamic_phy; - force_en = RTL930X_FORCE_EN; if (dynamic_phy && (interface == PHY_INTERFACE_MODE_SGMII || interface == PHY_INTERFACE_MODE_USXGMII)) { @@ -532,19 +496,19 @@ static void rtldsa_93xx_phylink_mac_link_up(struct phylink_config *config, } regmap_read(priv->map, priv->r->mac_force_mode_ctrl(port), &mcr); - mcr &= ~(RTL930X_RX_PAUSE_EN | RTL930X_TX_PAUSE_EN); - mcr |= RTL930X_MAC_FORCE_FC_EN; + mcr &= ~(cfg->rx_pause_mask | cfg->tx_pause_mask); + mcr |= cfg->fc_force_en_mask; if (tx_pause) - mcr |= RTL930X_TX_PAUSE_EN; + mcr |= cfg->tx_pause_mask; if (rx_pause) - mcr |= RTL930X_RX_PAUSE_EN; + mcr |= cfg->rx_pause_mask; if (!keep_forced && !dynamic_phy) { if (!priv->ports[port].phy) rtldsa_mac_link_state_source_set(priv, port, RTLDSA_MAC_LINK_STATE_SOURCE_PCS, interface); - mcr &= ~force_en; + mcr &= ~cfg->force_en_mask; regmap_write(priv->map, priv->r->mac_force_mode_ctrl(port), mcr); goto restart; } @@ -562,22 +526,21 @@ static void rtldsa_93xx_phylink_mac_link_up(struct phylink_config *config, else spdsel = RTL_SPEED_10; - mcr &= ~RTL930X_DUPLEX_MODE; - mcr &= ~RTL930X_SPEED_MASK; - mcr |= force_en | RTL930X_MAC_FORCE_FC_EN | RTL930X_FORCE_LINK_EN; - mcr |= spdsel << RTL930X_SPEED_SHIFT; + mcr &= ~(cfg->duplex_mask | cfg->speed_mask); + mcr |= cfg->force_en_mask | cfg->fc_force_en_mask | cfg->link_up_mask; + mcr |= field_prep(cfg->speed_mask, spdsel); if (dynamic_phy) - mcr &= ~RTL930X_MEDIA_SEL; + mcr &= ~cfg->media_mask; if (duplex == DUPLEX_FULL || priv->lagmembers & BIT_ULL(port)) - mcr |= RTL930X_DUPLEX_MODE; + mcr |= cfg->duplex_mask; pr_debug("%s port %d, mode %x, speed %d, duplex %d, txpause %d, rxpause %d: set mcr=%08x\n", __func__, port, mode, speed, duplex, tx_pause, rx_pause, mcr); regmap_write(priv->map, priv->r->mac_force_mode_ctrl(port), mcr); /* Pulse state force enables so hardware latches the new parameters. */ regmap_write(priv->map, priv->r->mac_force_mode_ctrl(port), - mcr & ~force_en); + mcr & ~cfg->force_en_mask); if (keep_forced) regmap_write(priv->map, priv->r->mac_force_mode_ctrl(port), mcr); diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/mac.h b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/mac.h index a549e658c6c..0f7ff70bbaf 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/mac.h +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/mac.h @@ -11,14 +11,45 @@ #define RTL83XX_FORCE_EN BIT(0) #define RTL83XX_FORCE_LINK_EN BIT(1) +#define RTL838X_DUPLEX_MODE BIT(3) +#define RTL838X_SPEED_SHIFT (4) +#define RTL838X_SPEED_MASK (3 << RTL838X_SPEED_SHIFT) +#define RTL838X_TX_PAUSE_EN BIT(6) +#define RTL838X_RX_PAUSE_EN BIT(7) + +#define RTL839X_DUPLEX_MODE BIT(2) +#define RTL839X_SPEED_SHIFT (3) +#define RTL839X_SPEED_MASK (3 << RTL839X_SPEED_SHIFT) +#define RTL839X_TX_PAUSE_EN BIT(5) +#define RTL839X_RX_PAUSE_EN BIT(6) + #define RTL930X_FORCE_EN BIT(0) #define RTL930X_FORCE_LINK_EN BIT(1) +#define RTL930X_DUPLEX_MODE BIT(2) +#define RTL930X_SPEED_SHIFT (3) +#define RTL930X_SPEED_MASK (15 << RTL930X_SPEED_SHIFT) +#define RTL930X_TX_PAUSE_EN BIT(7) +#define RTL930X_RX_PAUSE_EN BIT(8) #define RTL930X_MAC_FORCE_FC_EN BIT(9) #define RTL930X_MEDIA_SEL BIT(16) +#define RTL931X_FORCE_LINK_EN BIT(0) +#define RTL931X_FORCE_LINK BIT(9) + enum rtldsa_mac_link_state_source { RTLDSA_MAC_LINK_STATE_SOURCE_PCS, RTLDSA_MAC_LINK_STATE_SOURCE_PHY, }; +struct rtldsa_mac_force_mode_cfg { + u32 force_en_mask; + u32 fc_force_en_mask; + u32 link_up_mask; + u32 duplex_mask; + u32 speed_mask; + u32 tx_pause_mask; + u32 rx_pause_mask; + u32 media_mask; +}; + #endif /* _OTTO_MAC_H */ diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h index 3074499b285..a36b39b16f0 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl-otto.h @@ -395,7 +395,7 @@ struct rtldsa_config { int (*stp_get)(struct rtl838x_switch_priv *priv, u16 msti, int port); void (*stp_set)(struct rtl838x_switch_priv *priv, u16 msti, int port, int state); int mac_link_sts; - u32 mac_force_mode_mask; + struct rtldsa_mac_force_mode_cfg mac_force_mode; int (*mac_force_mode_ctrl)(int port); int (*mac_port_ctrl)(int port); int (*mac_link_state_source_set)(struct rtl838x_switch_priv *priv, diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c index c28963026ba..d66799c9f3e 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl838x.c @@ -236,7 +236,14 @@ const struct rtldsa_config rtldsa_838x_cfg = { .vlan_tables_read = otto_vlan_838x_tables_read, .vlan_set_tagged = otto_vlan_838x_set_tagged, .vlan_set_untagged = otto_vlan_838x_set_untagged, - .mac_force_mode_mask = RTL83XX_FORCE_EN | RTL83XX_FORCE_LINK_EN, + .mac_force_mode = { + .force_en_mask = RTL83XX_FORCE_EN, + .link_up_mask = RTL83XX_FORCE_LINK_EN, + .duplex_mask = RTL838X_DUPLEX_MODE, + .speed_mask = RTL838X_SPEED_MASK, + .tx_pause_mask = RTL838X_TX_PAUSE_EN, + .rx_pause_mask = RTL838X_RX_PAUSE_EN, + }, .mac_force_mode_ctrl = rtl838x_mac_force_mode_ctrl, .mac_link_sts = RTL838X_MAC_LINK_STS, .vlan_profile_get = otto_vlan_838x_profile_get, diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c index 071ee8af33b..dbdc85f3aff 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl839x.c @@ -250,7 +250,14 @@ const struct rtldsa_config rtldsa_839x_cfg = { .set_static_move_action = otto_l2_839x_set_static_move_action, .stp_get = rtldsa_839x_stp_get, .stp_set = rtl839x_stp_set, - .mac_force_mode_mask = RTL83XX_FORCE_EN | RTL83XX_FORCE_LINK_EN, + .mac_force_mode = { + .force_en_mask = RTL83XX_FORCE_EN, + .link_up_mask = RTL83XX_FORCE_LINK_EN, + .duplex_mask = RTL839X_DUPLEX_MODE, + .speed_mask = RTL839X_SPEED_MASK, + .tx_pause_mask = RTL839X_TX_PAUSE_EN, + .rx_pause_mask = RTL839X_RX_PAUSE_EN, + }, .mac_force_mode_ctrl = rtl839x_mac_force_mode_ctrl, .mac_link_sts = RTL839X_MAC_LINK_STS, .mac_port_ctrl = rtl839x_mac_port_ctrl, diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c index 6d427639b2d..45d0323721b 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl930x.c @@ -634,7 +634,16 @@ const struct rtldsa_config rtldsa_930x_cfg = { .stp_get = rtldsa_930x_stp_get, .stp_set = rtl930x_stp_set, .mac_link_sts = RTL930X_MAC_LINK_STS, - .mac_force_mode_mask = RTL930X_FORCE_EN | RTL930X_FORCE_LINK_EN, + .mac_force_mode = { + .force_en_mask = RTL930X_FORCE_EN, + .fc_force_en_mask = RTL930X_MAC_FORCE_FC_EN, + .link_up_mask = RTL930X_FORCE_LINK_EN, + .duplex_mask = RTL930X_DUPLEX_MODE, + .speed_mask = RTL930X_SPEED_MASK, + .tx_pause_mask = RTL930X_TX_PAUSE_EN, + .rx_pause_mask = RTL930X_RX_PAUSE_EN, + .media_mask = RTL930X_MEDIA_SEL, + }, .mac_force_mode_ctrl = rtl930x_mac_force_mode_ctrl, .mac_link_state_source_set = rtldsa_930x_mac_link_state_source_set, .mac_port_ctrl = rtl930x_mac_port_ctrl, diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c index 3085b352a5b..966cf4245b2 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/rtl931x.c @@ -36,9 +36,6 @@ #define RTL931X_MAC_LINK_STS (0x0EC0) -#define RTL931X_FORCE_EN BIT(9) -#define RTL931X_FORCE_LINK_EN BIT(0) - #define RTL931X_TRK_HASH_CTRL (0xBA70) #define RTL931X_TRK_CTRL (0xBA78) @@ -434,7 +431,10 @@ const struct rtldsa_config rtldsa_931x_cfg = { .vlan_fwd_on_inner = otto_vlan_931x_port_forward_on_inner, .stp_get = rtldsa_931x_stp_get, .stp_set = rtl931x_stp_set, - .mac_force_mode_mask = RTL931X_FORCE_EN | RTL931X_FORCE_LINK_EN, + .mac_force_mode = { + .force_en_mask = RTL931X_FORCE_LINK_EN, + .link_up_mask = RTL931X_FORCE_LINK, + }, .mac_force_mode_ctrl = rtl931x_mac_force_mode_ctrl, .mac_link_sts = RTL931X_MAC_LINK_STS, .mac_port_ctrl = rtl931x_mac_port_ctrl,