diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c index 8bde96b497..e338aab3b5 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/common.c @@ -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) diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c index e6564284d2..650b46db14 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.c @@ -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) 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 120f77f9cf..79e1b42a08 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 @@ -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 { diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c index ac8509db8c..9f0196c371 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl839x.c @@ -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, }; diff --git a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h index 4e9d94f370..7237aa862c 100644 --- a/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h +++ b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl83xx.h @@ -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); 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 39477b84bb..3873a6708d 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 @@ -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, }; 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 2bbc20d633..91dd40d32a 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 @@ -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, };