realtek: dsa: Refactor LAG in preparation for rtl93xx

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>
This commit is contained in:
Harshal Gohel 2026-03-02 09:13:13 +00:00 committed by Hauke Mehrtens
parent cd1b70f6f9
commit 6e63fac22a
7 changed files with 126 additions and 47 deletions

View 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)

View 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)

View file

@ -371,14 +371,16 @@
#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 {

View 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,
};

View 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);

View 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,
};

View 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,
};