diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/debugfs.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/debugfs.c index 4b560f6192..e8085eb709 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/debugfs.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/debugfs.c @@ -268,6 +268,13 @@ static void l2_table_print_entry(struct seq_file *m, struct rtl838x_switch_priv e->vid, e->rvid); seq_printf(m, " port %d age %d", e->port, e->age); + if (e->is_trunk) { + seq_printf(m, " trunk %d trunk_members: 0x%08llx non-primary: 0x%08llx primary-port: %d", + e->trunk, + priv->lags_port_members[e->trunk], + priv->lag_non_primary, + priv->lag_primary[e->trunk]); + } if (e->is_static) seq_puts(m, " static"); if (e->block_da) diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c index 90dbdf9c3a..92ca67b5d6 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/dsa.c @@ -1865,6 +1865,39 @@ static int rtldsa_find_l2_cam_entry(struct rtl838x_switch_priv *priv, u64 seed, return idx; } +/** + * rtldsa_find_lag_group_from_port() - Find lag group of current port + * @priv: private data of rtldsa switch + * @port: port id of potential LAG member + * Return: -ENOENT when port does not belong to any lag group, lag id otherwise + */ +static int rtldsa_find_lag_group_from_port(struct rtl838x_switch_priv *priv, int port) +{ + if (!(priv->lagmembers & BIT_ULL(port))) + return -ENOENT; + + /* port is a lag member */ + for (int lag_group = 0; lag_group < MAX_LAGS; lag_group++) { + if (priv->lags_port_members[lag_group] & BIT_ULL(port)) + return lag_group; + } + + return -ENOENT; +} + +/** + * rtldsa_93xx_prepare_lag_fdb() - Prepare fdb entry for LAG + * @e: L2 entry data + * @lag_group: lag id of the trunk group + */ +inline void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group) +{ + if (e && lag_group >= 0) { + e->is_trunk = true; + e->trunk = lag_group; + } +} + static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port, const unsigned char *addr, u16 vid, const struct dsa_db db) @@ -1874,10 +1907,16 @@ static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port, struct rtl838x_l2_entry e; int err = 0, idx; u64 seed = priv->r->l2_hash_seed(mac, vid); + int lag_group = rtldsa_find_lag_group_from_port(priv, port); - if (priv->lag_non_primary & BIT_ULL(port)) { - pr_debug("%s: %d is lag slave. ignore\n", __func__, port); - return 0; + if (lag_group >= 0 && priv->r->prepare_lag_fdb) { + priv->r->prepare_lag_fdb(&e, lag_group); + } else { + if (priv->lag_non_primary & BIT_ULL(port)) { + pr_debug("%s: %d is lag slave but prepare_lag_fdb is not supported. ignore\n", + __func__, port); + return 0; + } } mutex_lock(&priv->reg_mutex); @@ -1917,8 +1956,13 @@ static int rtldsa_port_fdb_del(struct dsa_switch *ds, int port, struct rtl838x_l2_entry e; int err = 0, idx; u64 seed = priv->r->l2_hash_seed(mac, vid); + int lag_group = rtldsa_find_lag_group_from_port(priv, port); + + if (lag_group >= 0 && priv->r->prepare_lag_fdb) + priv->r->prepare_lag_fdb(&e, lag_group); pr_debug("In %s, mac %llx, vid: %d\n", __func__, mac, vid); + mutex_lock(&priv->reg_mutex); idx = rtldsa_find_l2_hash_entry(priv, seed, true, &e); @@ -1960,6 +2004,10 @@ static int rtldsa_port_fdb_dump(struct dsa_switch *ds, int port, if (!e.valid) continue; + // Ignore trunk fdb entries + if (e.is_trunk) + continue; + if (e.port == port || e.port == RTL930X_PORT_IGNORE) cb(e.mac, e.vid, e.is_static, data); @@ -1973,6 +2021,10 @@ static int rtldsa_port_fdb_dump(struct dsa_switch *ds, int port, if (!e.valid) continue; + // Ignore trunk fdb entries + if (e.is_trunk) + continue; + if (e.port == port) cb(e.mac, e.vid, e.is_static, data); } @@ -2396,7 +2448,6 @@ static int rtldsa_port_lag_leave(struct dsa_switch *ds, int port, } pr_info("port_lag_del: group %d, port %d\n", group, port); priv->lagmembers &= ~BIT_ULL(port); - priv->lag_primary[group] = -1; priv->lag_non_primary &= ~BIT_ULL(port); pr_debug("lag_members = %llX\n", priv->lagmembers); err = rtl83xx_lag_del(priv->ds, group, port); @@ -2405,6 +2456,19 @@ static int rtldsa_port_lag_leave(struct dsa_switch *ds, int port, goto out; } + /* To re-elect primary interface, just remove the first interface in + * this-group's interfaces from non-primary + */ + if (priv->lags_port_members[group]) { + priv->lag_primary[group] = fls64(priv->lags_port_members[group]); + priv->lag_non_primary &= ~BIT_ULL(priv->lag_primary[group]); + } + + /* No need to update fdb entries since they make use of trunk_id for entry. + * The primary interface is only calculated at time of + * port_fdb_dump + */ + out: mutex_unlock(&priv->reg_mutex); return 0; diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h index 77b7097ca3..f5b6445d3b 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h @@ -1366,6 +1366,8 @@ struct rtldsa_config { void (*led_init)(struct rtl838x_switch_priv *priv); void (*qos_init)(struct rtl838x_switch_priv *priv); int (*trk_mbr_ctr)(int group); + void (*lag_switch_init)(struct rtl838x_switch_priv *priv); + void (*prepare_lag_fdb)(struct rtl838x_l2_entry *e, int lag_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, @@ -1449,6 +1451,8 @@ void rtl930x_dbgfs_init(struct rtl838x_switch_priv *priv); int rtldsa_93xx_lag_set_distribution_algorithm(struct rtl838x_switch_priv *priv, int group, int algoidx, u32 algomsk); +void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group); + void rtldsa_counters_lock_register(struct rtl838x_switch_priv *priv, int port) __acquires(&priv->ports[port].counters.lock); void rtldsa_counters_unlock_register(struct rtl838x_switch_priv *priv, int port) diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c index 1452f65c5d..345e642037 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl930x.c @@ -2801,5 +2801,8 @@ const struct rtldsa_config rtldsa_930x_cfg = { .set_receive_management_action = rtldsa_930x_set_receive_management_action, .qos_init = rtldsa_930x_qos_init, .trk_hash_ctrl = RTL930X_TRK_HASH_CTRL, + .prepare_lag_fdb = rtldsa_93xx_prepare_lag_fdb, + .lag_switch_init = rtldsa_93xx_lag_switch_init, + .lag_set_port_members = rtldsa_93xx_lag_set_port_members, .lag_set_distribution_algorithm = rtldsa_93xx_lag_set_distribution_algorithm, }; diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c index be65340cab..e831753120 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl931x.c @@ -1925,5 +1925,8 @@ const struct rtldsa_config rtldsa_931x_cfg = { .set_receive_management_action = rtldsa_931x_set_receive_management_action, .qos_init = rtldsa_931x_qos_init, .trk_hash_ctrl = RTL931X_TRK_HASH_CTRL, + .prepare_lag_fdb = rtldsa_93xx_prepare_lag_fdb, + .lag_switch_init = rtldsa_93xx_lag_switch_init, + .lag_set_port_members = rtldsa_93xx_lag_set_port_members, .lag_set_distribution_algorithm = rtldsa_93xx_lag_set_distribution_algorithm, };