]> git.ipfire.org Git - thirdparty/openwrt.git/commitdiff
realtek: dsa: Refactor LAG in preparation for rtl93xx
authorHarshal Gohel <hg@simonwunderlich.de>
Mon, 2 Mar 2026 09:13:13 +0000 (09:13 +0000)
committerHauke Mehrtens <hauke@hauke-m.de>
Sat, 7 Mar 2026 19:33:21 +0000 (20:33 +0100)
It is not helpful at the moment to expose all the SoC specific details to
the common code when it actually only needed to add ports to a LAG. Just
have a simple interface for now.

Support returning errors while setting distribution algorithm

Move setting algomask to rtl83xx specific routine and out of common lag_add
because algomasks will be handled differently on rtl93xx

Co-developed-by: Sven Eckelmann <se@simonwunderlich.de>
Signed-off-by: Sven Eckelmann <se@simonwunderlich.de>
Signed-off-by: Harshal Gohel <hg@simonwunderlich.de>
Link: https://github.com/openwrt/openwrt/pull/21740
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c
target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c

index 8bde96b49767841a6fc100240721d34a51e9baa8..e338aab3b518e89b9588d263c45267e4a86eda8d 100644 (file)
@@ -384,9 +384,8 @@ static int rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv)
 int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_lag_upper_info *info)
 {
        struct rtl838x_switch_priv *priv = ds->priv;
+       int ret;
        int i;
-       u32 algomsk = 0;
-       u32 algoidx = 0;
 
        for (i = 0; i < priv->ds->num_lag_ids; i++) {
                if (priv->lags_port_members[i] & BIT_ULL(port))
@@ -397,31 +396,16 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
                return -ENOSPC;
        }
 
-       switch (info->hash_type) {
-       case NETDEV_LAG_HASH_L2:
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
-       break;
-       case NETDEV_LAG_HASH_L23:
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
-               algoidx = 1;
-       break;
-       case NETDEV_LAG_HASH_L34:
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; /* sport */
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; /* dport */
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
-               algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
-               algoidx = 2;
-       break;
-       default:
-               algomsk |= 0x7f;
+       if (priv->r->lag_setup_algomask) {
+               ret = priv->r->lag_setup_algomask(priv, group, info);
+               if (ret)
+                       return ret;
        }
-       priv->r->set_distribution_algorithm(group, algoidx, algomsk);
-       priv->r->mask_port_reg_be(0, BIT_ULL(port), priv->r->trk_mbr_ctr(group));
-       priv->lags_port_members[group] |= BIT_ULL(port);
+
+       ret = priv->r->lag_set_port_members(priv, group,
+                                           priv->lags_port_members[group] | BIT_ULL(port), info);
+       if (ret)
+               return ret;
 
        pr_info("%s: Added port %d to LAG %d. Members now %016llx.\n",
                __func__, port, group, priv->lags_port_members[group]);
@@ -433,6 +417,7 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_la
 int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
 {
        struct rtl838x_switch_priv *priv = ds->priv;
+       int ret;
 
        if (group >= priv->ds->num_lag_ids) {
                pr_err("%s: LAG %d invalid.\n", __func__, group);
@@ -444,9 +429,17 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
                return -ENOSPC;
        }
 
-       /* 0x7f algo mask all */
-       priv->r->mask_port_reg_be(BIT_ULL(port), 0, priv->r->trk_mbr_ctr(group));
-       priv->lags_port_members[group] &= ~BIT_ULL(port);
+       /* Don't touch hash mask bits, as only the port might be removed from
+        * the LAG group. This means the lag group stays valid with existing
+        * mask algo bits. If there are no lag members left, then
+        * rtl83xx_lag_add will reconfigure hash mask when new LAG group is
+        * created.
+        */
+       ret = priv->r->lag_set_port_members(priv, group,
+                                           priv->lags_port_members[group] & ~BIT_ULL(port),
+                                           NULL);
+       if (ret)
+               return ret;
 
        pr_info("%s: Removed port %d from LAG %d. Members now %016llx.\n",
                __func__, port, group, priv->lags_port_members[group]);
@@ -454,6 +447,38 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port)
        return 0;
 }
 
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+                                  struct netdev_lag_upper_info *info)
+{
+       u32 algomsk = 0;
+       u32 algoidx = 0;
+
+       switch (info->hash_type) {
+       case NETDEV_LAG_HASH_L2:
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
+               break;
+       case NETDEV_LAG_HASH_L23:
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_DMAC_BIT;
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_SMAC_BIT;
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
+               algoidx = 1;
+               break;
+       case NETDEV_LAG_HASH_L34:
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT; /* sport */
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT; /* dport */
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_SIP_BIT; /* source ip */
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_DIP_BIT; /* dest ip */
+               algoidx = 2;
+               break;
+       default:
+               algomsk |= TRUNK_DISTRIBUTION_ALGO_MASKALL;
+       }
+
+       return priv->r->lag_set_distribution_algorithm(priv, group, algoidx, algomsk);
+}
+
 // Currently Unused
 // /* Allocate a 64 bit octet counter located in the LOG HW table */
 // static int rtl83xx_octet_cntr_alloc(struct rtl838x_switch_priv *priv)
index e6564284d23d49bfbd3af050f9da3b359042abef..650b46db1488a8db0f87c4cfc6e05838233b8bde 100644 (file)
@@ -1748,12 +1748,14 @@ static void rtl838x_set_egr_filter(int port, enum egr_filter state)
                    RTL838X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2)));
 }
 
-static void rtl838x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtldsa_838x_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
+                                                 int group, int algoidx, u32 algomsk)
 {
        algoidx &= 1; /* RTL838X only supports 2 concurrent algorithms */
        sw_w32_mask(1 << (group % 8), algoidx << (group % 8),
                    RTL838X_TRK_HASH_IDX_CTRL + ((group >> 3) << 2));
        sw_w32(algomsk, RTL838X_TRK_HASH_CTRL + (algoidx << 2));
+       return 0;
 }
 
 static void rtl838x_set_receive_management_action(int port, rma_ctrl_t type, action_type_t action)
@@ -1790,6 +1792,20 @@ rtldsa_838x_vlan_profile_dump(struct rtl838x_switch_priv *priv, int idx)
                p.unkn_mc_fld.pmsks_idx.ip, p.unkn_mc_fld.pmsks_idx.ip6);
 }
 
+static int rtldsa_838x_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
+                                           u64 members, struct netdev_lag_upper_info *info)
+{
+       priv->lags_port_members[group] = members;
+
+       priv->r->set_port_reg_be(priv->lags_port_members[group],
+                                priv->r->trk_mbr_ctr(group));
+
+       return 0;
+}
+
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+                                  struct netdev_lag_upper_info *info);
+
 const struct rtldsa_config rtldsa_838x_cfg = {
        .mask_port_reg_be = rtl838x_mask_port_reg,
        .set_port_reg_be = rtl838x_set_port_reg,
@@ -1875,9 +1891,11 @@ const struct rtldsa_config rtldsa_838x_cfg = {
        .route_read = rtl838x_route_read,
        .route_write = rtl838x_route_write,
        .l3_setup = rtl838x_l3_setup,
-       .set_distribution_algorithm = rtl838x_set_distribution_algorithm,
        .set_receive_management_action = rtl838x_set_receive_management_action,
        .qos_init = rtldsa_838x_qos_init,
+       .lag_set_distribution_algorithm = rtldsa_838x_set_distribution_algorithm,
+       .lag_set_port_members = rtldsa_838x_lag_set_port_members,
+       .lag_setup_algomask = rtldsa_83xx_lag_setup_algomask,
 };
 
 irqreturn_t rtl838x_switch_irq(int irq, void *dev_id)
index 120f77f9cffb4b23dc3cc4f20eec2f588ab5c28d..79e1b42a0895cf38e008de46497e00de3fc73620 100644 (file)
 #define RTL839X_IGR_BWCTRL_CTRL_LB_THR         (0x1614)
 
 /* Link aggregation (Trunking) */
-#define TRUNK_DISTRIBUTION_ALGO_SPA_BIT                0x01
-#define TRUNK_DISTRIBUTION_ALGO_SMAC_BIT       0x02
-#define TRUNK_DISTRIBUTION_ALGO_DMAC_BIT       0x04
-#define TRUNK_DISTRIBUTION_ALGO_SIP_BIT                0x08
-#define TRUNK_DISTRIBUTION_ALGO_DIP_BIT                0x10
-#define TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT 0x20
-#define TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT 0x40
-#define TRUNK_DISTRIBUTION_ALGO_MASKALL                0x7F
+#define TRUNK_DISTRIBUTION_ALGO_SPA_BIT         BIT(0)
+#define TRUNK_DISTRIBUTION_ALGO_SMAC_BIT        BIT(1)
+#define TRUNK_DISTRIBUTION_ALGO_DMAC_BIT        BIT(2)
+
+#define TRUNK_DISTRIBUTION_ALGO_SIP_BIT         BIT(3)
+#define TRUNK_DISTRIBUTION_ALGO_DIP_BIT         BIT(4)
+#define TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT  BIT(5)
+#define TRUNK_DISTRIBUTION_ALGO_DST_L4PORT_BIT  BIT(6)
+#define TRUNK_DISTRIBUTION_ALGO_VLAN_BIT        BIT(7)
+#define TRUNK_DISTRIBUTION_ALGO_MASKALL                GENMASK(6, 0)
 
 #define TRUNK_DISTRIBUTION_ALGO_L2_SPA_BIT     0x01
 #define TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT    0x02
@@ -1296,6 +1298,8 @@ struct rtldsa_config {
        int n_counters;
        int n_pie_blocks;
        u8 port_ignore;
+       int trk_ctrl;
+       int trk_hash_ctrl;
        void (*vlan_tables_read)(u32 vlan, struct rtl838x_vlan_info *info);
        void (*vlan_set_tagged)(u32 vlan, struct rtl838x_vlan_info *info);
        void (*vlan_set_untagged)(u32 vlan, u64 portmask);
@@ -1330,7 +1334,6 @@ struct rtldsa_config {
        void (*write_l2_entry_using_hash)(u32 hash, u32 pos, struct rtl838x_l2_entry *e);
        u64 (*read_cam)(int idx, struct rtl838x_l2_entry *e);
        void (*write_cam)(int idx, struct rtl838x_l2_entry *e);
-       int (*trk_mbr_ctr)(int group);
        int rma_bpdu_fld_pmask;
        int spcl_trap_eapol_ctrl;
        void (*init_eee)(struct rtl838x_switch_priv *priv, bool enable);
@@ -1361,10 +1364,17 @@ struct rtldsa_config {
        void (*get_l3_router_mac)(u32 idx, struct rtl93xx_rt_mac *m);
        void (*set_l3_router_mac)(u32 idx, struct rtl93xx_rt_mac *m);
        void (*set_l3_egress_intf)(int idx, struct rtl838x_l3_intf *intf);
-       void (*set_distribution_algorithm)(int group, int algoidx, u32 algomask);
        void (*set_receive_management_action)(int port, rma_ctrl_t type, action_type_t action);
        void (*led_init)(struct rtl838x_switch_priv *priv);
        void (*qos_init)(struct rtl838x_switch_priv *priv);
+       int (*trk_mbr_ctr)(int group);
+       int (*lag_set_port_members)(struct rtl838x_switch_priv *priv, int group, u64 members,
+                                   struct netdev_lag_upper_info *info);
+       int (*lag_setup_algomask)(struct rtl838x_switch_priv *priv, int group,
+                                 struct netdev_lag_upper_info *info);
+       int (*lag_set_distribution_algorithm)(struct rtl838x_switch_priv *priv,
+                                             int group, int algoidx,
+                                             u32 algomask);
 };
 
 struct rtl838x_switch_priv {
index ac8509db8cff58874969961194e6565bfe58658a..9f0196c371fc2e175cfbcbfbb5c8b5d5076e3ff1 100644 (file)
@@ -1701,11 +1701,14 @@ static void rtl839x_set_egr_filter(int port,  enum egr_filter state)
                    RTL839X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2)));
 }
 
-static void rtl839x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtldsa_839x_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
+                                                 int group, int algoidx, u32 algomsk)
 {
        sw_w32_mask(3 << ((group & 0xf) << 1), algoidx << ((group & 0xf) << 1),
                    RTL839X_TRK_HASH_IDX_CTRL + ((group >> 4) << 2));
        sw_w32(algomsk, RTL839X_TRK_HASH_CTRL + (algoidx << 2));
+
+       return 0;
 }
 
 static void rtl839x_set_receive_management_action(int port, rma_ctrl_t type, action_type_t action)
@@ -1728,6 +1731,20 @@ static void rtl839x_set_receive_management_action(int port, rma_ctrl_t type, act
        }
 }
 
+static int rtldsa_839x_lag_set_port_members(struct rtl838x_switch_priv *priv, int group,
+                                           u64 members, struct netdev_lag_upper_info *info)
+{
+       priv->lags_port_members[group] = members;
+
+       priv->r->set_port_reg_be(priv->lags_port_members[group],
+                                priv->r->trk_mbr_ctr(group));
+
+       return 0;
+}
+
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+                                  struct netdev_lag_upper_info *info);
+
 const struct rtldsa_config rtldsa_839x_cfg = {
        .mask_port_reg_be = rtl839x_mask_port_reg_be,
        .set_port_reg_be = rtl839x_set_port_reg_be,
@@ -1813,7 +1830,9 @@ const struct rtldsa_config rtldsa_839x_cfg = {
        .route_read = rtl839x_route_read,
        .route_write = rtl839x_route_write,
        .l3_setup = rtl839x_l3_setup,
-       .set_distribution_algorithm = rtl839x_set_distribution_algorithm,
        .set_receive_management_action = rtl839x_set_receive_management_action,
        .qos_init = rtldsa_839x_qos_init,
+       .lag_set_distribution_algorithm = rtldsa_839x_set_distribution_algorithm,
+       .lag_set_port_members = rtldsa_839x_lag_set_port_members,
+       .lag_setup_algomask = rtldsa_83xx_lag_setup_algomask,
 };
index 4e9d94f370c709e9da64d65229999c5cdafb5c69..7237aa862c73b6fd8089e006640cf36eed9e7a8e 100644 (file)
@@ -127,6 +127,9 @@ inline u16 rtl_table_data(struct table_reg *r, int i);
 inline u32 rtl_table_data_r(struct table_reg *r, int i);
 inline void rtl_table_data_w(struct table_reg *r, u32 v, int i);
 
+int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group,
+                                  struct netdev_lag_upper_info *info);
+
 void rtldsa_838x_qos_init(struct rtl838x_switch_priv *priv);
 void rtldsa_839x_qos_init(struct rtl838x_switch_priv *priv);
 
index 39477b84bb90db6548db26758ba676828c50eb76..3873a6708da80173d9ee8f92783567d294ce421c 100644 (file)
@@ -2513,7 +2513,8 @@ static void rtl930x_set_egr_filter(int port,  enum egr_filter state)
                    RTL930X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2)));
 }
 
-static void rtl930x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtl930x_set_distribution_algorithm(struct rtl838x_switch_priv *priv, int group,
+                                             int algoidx, u32 algomsk)
 {
        u32 l3shift = 0;
        u32 newmask = 0;
@@ -2551,6 +2552,7 @@ static void rtl930x_set_distribution_algorithm(int group, int algoidx, u32 algom
        }
 
        sw_w32(newmask << l3shift, RTL930X_TRK_HASH_CTRL + (algoidx << 2));
+       return 0;
 }
 
 static void rtldsa_930x_led_get_forced(const struct device_node *node,
@@ -2835,10 +2837,10 @@ const struct rtldsa_config rtldsa_930x_cfg = {
        .set_l3_router_mac = rtl930x_set_l3_router_mac,
        .set_l3_egress_intf = rtl930x_set_l3_egress_intf,
 #endif
-       .set_distribution_algorithm = rtl930x_set_distribution_algorithm,
        .led_init = rtl930x_led_init,
        .enable_learning = rtldsa_930x_enable_learning,
        .enable_flood = rtldsa_930x_enable_flood,
        .set_receive_management_action = rtldsa_930x_set_receive_management_action,
        .qos_init = rtldsa_930x_qos_init,
+       .lag_set_distribution_algorithm = rtl930x_set_distribution_algorithm,
 };
index 2bbc20d63335a4b3e386898d6a42f025c4f70f52..91dd40d32a66c06d41210f72a08ed553b57758ec 100644 (file)
@@ -1624,7 +1624,8 @@ static void rtl931x_set_egr_filter(int port,  enum egr_filter state)
                    RTL931X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2)));
 }
 
-static void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk)
+static int rtl931x_set_distribution_algorithm(struct rtl838x_switch_priv *priv, int group,
+                                             int algoidx, u32 algomsk)
 {
        u32 l3shift = 0;
        u32 newmask = 0;
@@ -1662,6 +1663,7 @@ static void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algom
        }
 
        sw_w32(newmask << l3shift, RTL931X_TRK_HASH_CTRL + (algoidx << 2));
+       return 0;
 }
 
 static void rtldsa_931x_led_get_forced(const struct device_node *node,
@@ -1950,7 +1952,6 @@ const struct rtldsa_config rtldsa_931x_cfg = {
        .rma_bpdu_fld_pmask = RTL931X_RMA_BPDU_FLD_PMSK,
        .set_vlan_igr_filter = rtl931x_set_igr_filter,
        .set_vlan_egr_filter = rtl931x_set_egr_filter,
-       .set_distribution_algorithm = rtl931x_set_distribution_algorithm,
        .l2_hash_key = rtl931x_l2_hash_key,
        .l2_hash_seed = rtldsa_931x_l2_hash_seed,
        .read_mcast_pmask = rtl931x_read_mcast_pmask,
@@ -1965,4 +1966,5 @@ const struct rtldsa_config rtldsa_931x_cfg = {
        .enable_flood = rtldsa_931x_enable_flood,
        .set_receive_management_action = rtldsa_931x_set_receive_management_action,
        .qos_init = rtldsa_931x_qos_init,
+       .lag_set_distribution_algorithm = rtl931x_set_distribution_algorithm,
 };