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 7908d736ce..481083805c 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 @@ -528,6 +528,148 @@ int rtldsa_83xx_lag_setup_algomask(struct rtl838x_switch_priv *priv, int group, return priv->r->lag_set_distribution_algorithm(priv, group, algoidx, algomsk); } +static int rtldsa_93xx_lag_set_group2ports(struct rtl838x_switch_priv *priv, int group, + struct netdev_lag_upper_info *info) +{ + DECLARE_BITMAP(ports, ARRAY_SIZE(priv->ports)); + struct rtldsa_93xx_lag_entry e; + unsigned int table_pos = 0; + u8 num_of_lag_ports = 0; + u8 group_ports[8]; + u32 data[3]; + int i; + + /* Read lag table using Table control register 2 */ + struct table_reg *r = priv->r->lag_table(); + + rtl_table_read(r, group); + + bitmap_clear(ports, 0, ARRAY_SIZE(priv->ports)); + bitmap_from_arr64(ports, &priv->lags_port_members[group], + ARRAY_SIZE(priv->ports)); + + for (i = 0; i < 3; i++) + data[i] = sw_r32(rtl_table_data(r, i)); + + priv->r->lag_fill_data(data, &e); + + num_of_lag_ports = bitmap_weight(ports, ARRAY_SIZE(priv->ports)); + if (num_of_lag_ports > ARRAY_SIZE(group_ports)) { + pr_err("%s: Number of LAG ports too high: %u", __func__, + num_of_lag_ports); + + return -ENOSPC; + } + + memset(group_ports, 0x3f, sizeof(group_ports)); + + table_pos = 0; + for_each_set_bit(i, ports, ARRAY_SIZE(priv->ports)) { + group_ports[table_pos] = i; + table_pos++; + } + + /* Remove tx disabled ports */ + num_of_lag_ports = table_pos; + + e.trk_dev0 = 0; + e.trk_port0 = group_ports[0]; + e.trk_dev1 = 0; + e.trk_port1 = group_ports[1]; + e.trk_dev2 = 0; + e.trk_port2 = group_ports[2]; + e.trk_dev3 = 0; + e.trk_port3 = group_ports[3]; + e.trk_dev4 = 0; + e.trk_port4 = group_ports[4]; + e.trk_dev5 = 0; + e.trk_port5 = group_ports[5]; + e.trk_dev6 = 0; + e.trk_port6 = group_ports[6]; + e.trk_dev7 = 0; + e.trk_port7 = group_ports[7]; + + e.num_tx_candi = num_of_lag_ports; + + /* set hash_mask_idx to 0 if we are deleting lag group */ + if (info) { + if (info->hash_type == NETDEV_LAG_HASH_L2) { + e.l2_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L2; + e.ip4_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L2; + e.ip6_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L2; + } else if (info->hash_type == NETDEV_LAG_HASH_L23) { + e.l2_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L23; + e.ip4_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L23; + e.ip6_hash_mask_idx = RTL93XX_HASH_MASK_INDEX_L23; + } else { + return -EOPNOTSUPP; + } + } + + priv->r->lag_write_data(data, &e); + + for (i = 0; i < 3; i++) + sw_w32(data[i], rtl_table_data(r, i)); + rtl_table_write(r, group); + rtl_table_release(r); + + return 0; +} + +static inline void rtldsa_93xx_lag_set_local_group2ports(struct rtl838x_switch_priv *priv, int group, + u64 ports) +{ + priv->r->set_port_reg_be(ports, priv->r->trk_mbr_ctr(group)); +} + +int rtldsa_93xx_lag_set_port_members(struct rtl838x_switch_priv *priv, int group, + u64 members, struct netdev_lag_upper_info *info) +{ + DECLARE_BITMAP(affected_members, ARRAY_SIZE(priv->ports)); + bool valid_group; + u64 old_members; + u64 affected; + size_t port; + int ret; + + /* calculate modifications of the LAG group */ + old_members = priv->lags_port_members[group]; + priv->lags_port_members[group] = members; + + affected = old_members | priv->lags_port_members[group]; + + bitmap_clear(affected_members, 0, ARRAY_SIZE(priv->ports)); + bitmap_from_arr64(affected_members, &affected, BITS_PER_TYPE(affected)); + + valid_group = __sw_hweight64(priv->lags_port_members[group]); + + /* apply global group and port settings */ + ret = rtldsa_93xx_lag_set_group2ports(priv, group, info); + if (ret) + return ret; + + for_each_set_bit(port, affected_members, ARRAY_SIZE(priv->ports)) { + bool valid = priv->lags_port_members[group] & BIT_ULL(port); + + priv->r->lag_set_port2group(group, port, valid); + } + + /* apply local group and port settings */ + priv->r->lag_set_local_group_id(group, group, valid_group); + rtldsa_93xx_lag_set_local_group2ports(priv, group, priv->lags_port_members[group]); + + for_each_set_bit(port, affected_members, ARRAY_SIZE(priv->ports)) { + bool valid = priv->lags_port_members[group] & BIT_ULL(port); + + priv->r->lag_set_local_port2group(group, port, valid); + } + + /* write lag table (and maybe additional information) to SRAM */ + priv->r->lag_sync_tables(); + + return 0; +} + // 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.h b/target/linux/realtek/files-6.12/drivers/net/dsa/rtl83xx/rtl838x.h index 3692506ed3..0843676e93 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 @@ -406,13 +406,98 @@ #define RTL839X_TRK_HASH_IDX_CTRL (0x2280) #define RTL839X_TRK_HASH_CTRL (0x2284) +#define RTL930X_LOCAL_PORT_TRK_MAP (0xD0C8) +#define RTL930X_TRK_ID_CTRL (0xA3A8) #define RTL930X_TRK_MBR_CTRL (0xA41C) #define RTL930X_TRK_HASH_CTRL (0x9F80) #define RTL930X_TRK_CTRL (0x9F88) +#define RTL930X_TRK_SHIFT_CTRL (0x9F8C) +#define RTL930X_TRK_LOCAL_TBL_REFRESH (0x9F90) +#define RTL930X_TRK_LOCAL_TBL (0x9F94) +#define RTL930X_TRK_STK_CTRL (0xA07C) +#define RTL930X_TRK_ID_CTRL_TRK_VALID BIT(6) +#define RTL930X_TRK_ID_CTRL_TRK_ID GENMASK(5, 0) + +#define RTL930X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR BIT(6) +#define RTL930X_LOCAL_PORT_TRK_MAP_TRK_ID GENMASK(5, 0) + +#define RTL930X_SRC_TRK_MAP_TRK_VALID BIT(31) +#define RTL930X_SRC_TRK_MAP_TRK_ID GENMASK(30, 25) + +#define RTL931X_LOCAL_PORT_TRK_MAP (0x4CAC) +#define RTL931X_TRK_ID_CTRL (0xB800) #define RTL931X_TRK_MBR_CTRL (0xB8D0) #define RTL931X_TRK_HASH_CTRL (0xBA70) #define RTL931X_TRK_CTRL (0xBA78) +#define RTL931X_TRK_SHIFT_CTRL (0xBA7C) +#define RTL931X_TRK_LOCAL_TBL_REFRESH (0xBA80) +#define RTL931X_TRK_LOCAL_TBL (0xBA84) +#define RTL931X_TRK_STK_CTRL (0xBE94) + +#define RLT931X_TRK_ID_CTRL_TRK_ID GENMASK(6, 0) +#define RTL931X_TRK_ID_CTRL_TRK_VALID BIT(7) + +#define RTL931X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR BIT(7) +#define RTL931X_LOCAL_PORT_TRK_MAP_TRK_ID GENMASK(6, 0) + +#define RTL931X_SRC_TRK_MAP_TRK_ID GENMASK(30, 24) +#define RTL931X_SRC_TRK_MAP_TRK_ID_VALID BIT(31) + +#define GENMASK_MOD(high, low) GENMASK((high) % 32, (low) % 32) +#define BIT_MOD(bit) BIT((bit) % 32) + +/* RTL930X LAG Table offsets */ +#define RTL930X_LAG_NUM_TX_CANDI GENMASK_MOD(92, 89) +#define RTL930X_LAG_L2_HASH_MSK_IDX BIT_MOD(88) +#define RTL930X_LAG_IP4_HASH_MSK_IDX BIT_MOD(87) +#define RTL930X_LAG_IP6_HASH_MSK_IDX BIT_MOD(86) +#define RTL930X_LAG_SEP_DLF_BCAST_EN BIT_MOD(85) +#define RTL930X_LAG_SEP_KWN_MC_EN BIT_MOD(84) +#define RTL930X_LAG_TRK_DEV7 GENMASK_MOD(83, 80) +#define RTL930X_LAG_TRK_PORT7 GENMASK_MOD(79, 74) +#define RTL930X_LAG_TRK_DEV6 GENMASK_MOD(73, 70) +#define RTL930X_LAG_TRK_PORT6 GENMASK_MOD(69, 64) + +#define RTL930X_LAG_TRK_DEV5 GENMASK_MOD(61, 58) +#define RTL930X_LAG_TRK_PORT5 GENMASK_MOD(57, 52) +#define RTL930X_LAG_TRK_DEV4 GENMASK_MOD(51, 48) +#define RTL930X_LAG_TRK_PORT4 GENMASK_MOD(47, 42) +#define RTL930X_LAG_TRK_DEV3 GENMASK_MOD(41, 38) +#define RTL930X_LAG_TRK_PORT3 GENMASK_MOD(37, 32) + +#define RTL930X_LAG_TRK_DEV2 GENMASK_MOD(29, 26) +#define RTL930X_LAG_TRK_PORT2 GENMASK_MOD(25, 20) +#define RTL930X_LAG_TRK_DEV1 GENMASK_MOD(19, 16) +#define RTL930X_LAG_TRK_PORT1 GENMASK_MOD(15, 10) +#define RTL930X_LAG_TRK_DEV0 GENMASK_MOD(9, 6) +#define RTL930X_LAG_TRK_PORT0 GENMASK_MOD(5, 0) + +/* RTL931X LAG Table offsets */ +#define RTL931X_LAG_NUM_TX_CANDI GENMASK_MOD(92, 89) +#define RTL931X_LAG_L2_HASH_MSK_IDX BIT_MOD(88) +#define RTL931X_LAG_IP4_HASH_MSK_IDX BIT_MOD(87) +#define RTL931X_LAG_IP6_HASH_MSK_IDX BIT_MOD(86) +#define RTL931X_LAG_SEP_FLOOD_EN BIT_MOD(85) +#define RTL931X_LAG_SEP_KWN_MC_EN BIT_MOD(84) +#define RTL931X_LAG_TRK_DEV7 GENMASK_MOD(83, 80) +#define RTL931X_LAG_TRK_PORT7 GENMASK_MOD(79, 74) +#define RTL931X_LAG_TRK_DEV6 GENMASK_MOD(73, 70) +#define RTL931X_LAG_TRK_PORT6 GENMASK_MOD(69, 64) + +#define RTL931X_LAG_TRK_DEV5 GENMASK_MOD(61, 58) +#define RTL931X_LAG_TRK_PORT5 GENMASK_MOD(57, 52) +#define RTL931X_LAG_TRK_DEV4 GENMASK_MOD(51, 48) +#define RTL931X_LAG_TRK_PORT4 GENMASK_MOD(47, 42) +#define RTL931X_LAG_TRK_DEV3 GENMASK_MOD(41, 38) +#define RTL931X_LAG_TRK_PORT3 GENMASK_MOD(37, 32) + +#define RTL931X_LAG_TRK_DEV2 GENMASK_MOD(29, 26) +#define RTL931X_LAG_TRK_PORT2 GENMASK_MOD(25, 20) +#define RTL931X_LAG_TRK_DEV1 GENMASK_MOD(19, 16) +#define RTL931X_LAG_TRK_PORT1 GENMASK_MOD(15, 10) +#define RTL931X_LAG_TRK_DEV0 GENMASK_MOD(9, 6) +#define RTL931X_LAG_TRK_PORT0 GENMASK_MOD(5, 0) /* Attack prevention */ #define RTL838X_ATK_PRVNT_PORT_EN (0x5B00) @@ -886,6 +971,36 @@ struct rtldsa_counter_state { struct rtnl_link_stats64 link_stat; }; +struct rtldsa_93xx_lag_entry { + u32 trk_port0:6; + u32 trk_dev0:4; + u32 trk_port1:6; + u32 trk_dev1:4; + u32 trk_port2:6; + u32 trk_dev2:4; + u32 trk_port3:6; + u32 trk_dev3:4; + u32 trk_port4:6; + u32 trk_dev4:4; + u32 trk_port5:6; + u32 trk_dev5:4; + u32 trk_port6:6; + u32 trk_dev6:4; + u32 trk_port7:6; + u32 trk_dev7:4; + u32 sep_kwn_mc_en:1; + union { + // for rtl930x + u32 sep_dlf_bcast_en:1; + // for rtl931x + u32 sep_flood_en:1; + } flood_dlf_bcast; + u32 ip6_hash_mask_idx:1; + u32 ip4_hash_mask_idx:1; + u32 l2_hash_mask_idx:1; + u32 num_tx_candi:4; +}; + struct rtldsa_port { bool enable:1; bool phy_is_integrated:1; @@ -1387,6 +1502,13 @@ struct rtldsa_config { int (*lag_set_distribution_algorithm)(struct rtl838x_switch_priv *priv, int group, int algoidx, u32 algomask); + void (*lag_set_local_group_id)(int local_group, int global_group, bool valid); + void (*lag_write_data)(u32 data[], struct rtldsa_93xx_lag_entry *e); + void (*lag_fill_data)(u32 data[], struct rtldsa_93xx_lag_entry *e); + void (*lag_set_local_port2group)(int group, int port, bool valid); + void (*lag_set_port2group)(int group, int port, bool valid); + struct table_reg* (*lag_table)(void); + void (*lag_sync_tables)(void); }; struct rtl838x_switch_priv { @@ -1463,6 +1585,8 @@ void rtl930x_dbgfs_init(struct rtl838x_switch_priv *priv); void rtldsa_93xx_lag_switch_init(struct rtl838x_switch_priv *priv); int rtldsa_93xx_lag_set_distribution_algorithm(struct rtl838x_switch_priv *priv, int group, int algoidx, u32 algomsk); +int rtldsa_93xx_lag_set_port_members(struct rtl838x_switch_priv *priv, int group, + u64 members, struct netdev_lag_upper_info *info); void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group); 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 5256349d97..c86b28a45b 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 @@ -532,6 +532,118 @@ static void rtldsa_930x_enable_flood(int port, bool enable) RTL930X_L2_LRN_PORT_CONSTRT_CTRL + port * 4); } +static void rtldsa_930x_lag_set_port2group(int group, int port, bool valid) +{ + struct table_reg *r = rtl_table_get(RTL9300_TBL_0, 8); + u32 mask = valid ? RTL930X_SRC_TRK_MAP_TRK_VALID : 0; + + rtl_table_read(r, port); + mask |= FIELD_PREP(RTL930X_SRC_TRK_MAP_TRK_ID, group); // Update TRK Field. + sw_w32(mask, rtl_table_data(r, 0)); + rtl_table_write(r, port); + rtl_table_release(r); +} + +/* Write data from the data buffer into the lag-entry strucure */ +static void rtldsa_930x_lag_fill_data(u32 data[], struct rtldsa_93xx_lag_entry *e) +{ + /* 95-64 */ + e->num_tx_candi = FIELD_GET(RTL930X_LAG_NUM_TX_CANDI, data[0]); + e->l2_hash_mask_idx = FIELD_GET(RTL930X_LAG_L2_HASH_MSK_IDX, data[0]); + e->ip4_hash_mask_idx = FIELD_GET(RTL930X_LAG_IP4_HASH_MSK_IDX, data[0]); + e->ip6_hash_mask_idx = FIELD_GET(RTL930X_LAG_IP6_HASH_MSK_IDX, data[0]); + e->flood_dlf_bcast.sep_dlf_bcast_en = FIELD_GET(RTL930X_LAG_SEP_DLF_BCAST_EN, data[0]); + e->sep_kwn_mc_en = FIELD_GET(RTL930X_LAG_SEP_KWN_MC_EN, data[0]); + e->trk_dev7 = FIELD_GET(RTL930X_LAG_TRK_DEV7, data[0]); + e->trk_port7 = FIELD_GET(RTL930X_LAG_TRK_PORT7, data[0]); + e->trk_dev6 = FIELD_GET(RTL930X_LAG_TRK_DEV6, data[0]); + e->trk_port6 = FIELD_GET(RTL930X_LAG_TRK_PORT6, data[0]); + + /* 63-32 */ + e->trk_dev5 = FIELD_GET(RTL930X_LAG_TRK_DEV5, data[1]); + e->trk_port5 = FIELD_GET(RTL930X_LAG_TRK_PORT5, data[1]); + e->trk_dev4 = FIELD_GET(RTL930X_LAG_TRK_DEV4, data[1]); + e->trk_port4 = FIELD_GET(RTL930X_LAG_TRK_PORT4, data[1]); + e->trk_dev3 = FIELD_GET(RTL930X_LAG_TRK_DEV3, data[1]); + e->trk_port3 = FIELD_GET(RTL930X_LAG_TRK_PORT3, data[1]); + + /* 31-0 */ + e->trk_dev2 = FIELD_GET(RTL930X_LAG_TRK_DEV2, data[2]); + e->trk_port2 = FIELD_GET(RTL930X_LAG_TRK_PORT2, data[2]); + e->trk_dev1 = FIELD_GET(RTL930X_LAG_TRK_DEV1, data[2]); + e->trk_port1 = FIELD_GET(RTL930X_LAG_TRK_PORT1, data[2]); + e->trk_dev0 = FIELD_GET(RTL930X_LAG_TRK_DEV0, data[2]); + e->trk_port0 = FIELD_GET(RTL930X_LAG_TRK_PORT0, data[2]); +} + +/* Write lag-entry data into buffer */ +static void rtldsa_930x_lag_write_data(u32 data[], struct rtldsa_93xx_lag_entry *e) +{ + /* 95-64 */ + data[0] = FIELD_PREP(RTL930X_LAG_NUM_TX_CANDI, e->num_tx_candi); + data[0] |= FIELD_PREP(RTL930X_LAG_L2_HASH_MSK_IDX, e->l2_hash_mask_idx); + data[0] |= FIELD_PREP(RTL930X_LAG_IP4_HASH_MSK_IDX, e->ip4_hash_mask_idx); + data[0] |= FIELD_PREP(RTL930X_LAG_IP6_HASH_MSK_IDX, e->ip6_hash_mask_idx); + data[0] |= FIELD_PREP(RTL930X_LAG_SEP_DLF_BCAST_EN, e->flood_dlf_bcast.sep_dlf_bcast_en); + data[0] |= FIELD_PREP(RTL930X_LAG_SEP_KWN_MC_EN, e->sep_kwn_mc_en); + data[0] |= FIELD_PREP(RTL930X_LAG_TRK_DEV7, e->trk_dev7); + data[0] |= FIELD_PREP(RTL930X_LAG_TRK_PORT7, e->trk_port7); + data[0] |= FIELD_PREP(RTL930X_LAG_TRK_DEV6, e->trk_dev6); + data[0] |= FIELD_PREP(RTL930X_LAG_TRK_PORT6, e->trk_port6); + + /* 63-32 */ + data[1] = FIELD_PREP(RTL930X_LAG_TRK_DEV5, e->trk_dev5); + data[1] |= FIELD_PREP(RTL930X_LAG_TRK_PORT5, e->trk_port5); + data[1] |= FIELD_PREP(RTL930X_LAG_TRK_DEV4, e->trk_dev4); + data[1] |= FIELD_PREP(RTL930X_LAG_TRK_PORT4, e->trk_port4); + data[1] |= FIELD_PREP(RTL930X_LAG_TRK_DEV3, e->trk_dev3); + data[1] |= FIELD_PREP(RTL930X_LAG_TRK_PORT3, e->trk_port3); + + /* 31-0 */ + data[2] = FIELD_PREP(RTL930X_LAG_TRK_DEV2, e->trk_dev2); + data[2] |= FIELD_PREP(RTL930X_LAG_TRK_PORT2, e->trk_port2); + data[2] |= FIELD_PREP(RTL930X_LAG_TRK_DEV1, e->trk_dev1); + data[2] |= FIELD_PREP(RTL930X_LAG_TRK_PORT1, e->trk_port1); + data[2] |= FIELD_PREP(RTL930X_LAG_TRK_DEV0, e->trk_dev0); + data[2] |= FIELD_PREP(RTL930X_LAG_TRK_PORT0, e->trk_port0); +} + +static void rtldsa_930x_lag_set_local_group_id(int local_group, int global_group, bool valid) +{ + u32 mask = 0; + + mask |= valid ? RTL930X_TRK_ID_CTRL_TRK_VALID : 0; + mask |= FIELD_PREP(RTL930X_TRK_ID_CTRL_TRK_ID, global_group); + sw_w32(mask, RTL930X_TRK_ID_CTRL + (4 * local_group)); +} + +static void rtldsa_930x_lag_set_local_port2group(int group, int port, bool valid) +{ + u32 mask = 0; + + mask |= valid ? RTL930X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR : 0; + mask |= FIELD_PREP(RTL930X_LOCAL_PORT_TRK_MAP_TRK_ID, group); + sw_w32(mask, RTL930X_LOCAL_PORT_TRK_MAP + (4 * port)); +} + +static void rtldsa_930x_lag_sync_tables(void) +{ + u32 val; + int ret; + + sw_w32(BIT(0), RTL930X_TRK_LOCAL_TBL_REFRESH); + + ret = readx_poll_timeout(sw_r32, RTL930X_TRK_LOCAL_TBL_REFRESH, val, + !(val & BIT(0)), 20, 10000); + if (ret) + pr_err("%s: timeout\n", __func__); +} + +static struct table_reg *rtldsa_930x_lag_table(void) +{ + return rtl_table_get(RTL9300_TBL_0, 7); +} + static int rtldsa_930x_stp_get(struct rtl838x_switch_priv *priv, u16 msti, int port, u32 port_state[]) { int idx = 1 - ((port + 3) / 16); @@ -2806,4 +2918,11 @@ const struct rtldsa_config rtldsa_930x_cfg = { .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, + .lag_set_local_group_id = rtldsa_930x_lag_set_local_group_id, + .lag_write_data = rtldsa_930x_lag_write_data, + .lag_fill_data = rtldsa_930x_lag_fill_data, + .lag_set_local_port2group = rtldsa_930x_lag_set_local_port2group, + .lag_set_port2group = rtldsa_930x_lag_set_port2group, + .lag_sync_tables = rtldsa_930x_lag_sync_tables, + .lag_table = rtldsa_930x_lag_table, }; 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 df4380b465..3a2a0f5121 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 @@ -1745,6 +1745,123 @@ static void rtldsa_931x_led_init(struct rtl838x_switch_priv *priv) dev_dbg(dev, "%08x: %08x\n", 0xbb000600 + i * 4, sw_r32(0x0600 + i * 4)); } +static void rtldsa_931x_lag_set_port2group(int group, int port, bool valid) +{ + u32 trk_id_valid = valid ? RTL931X_SRC_TRK_MAP_TRK_ID_VALID : 0; + struct table_reg *r = rtl_table_get(RTL9310_TBL_0, 13); + u32 mask = 0; + + rtl_table_read(r, port); + + mask |= trk_id_valid; + /* Update TRK Field */ + mask |= FIELD_PREP(RTL931X_SRC_TRK_MAP_TRK_ID, group); + + sw_w32(mask, rtl_table_data(r, 0)); + rtl_table_write(r, port); + rtl_table_release(r); +} + +/* Write data from the data buffer into the lag-entry strucure */ +static void rtldsa_931x_lag_fill_data(u32 data[], struct rtldsa_93xx_lag_entry *e) +{ + /* 95-64 */ + e->num_tx_candi = FIELD_GET(RTL931X_LAG_NUM_TX_CANDI, data[0]); + e->l2_hash_mask_idx = FIELD_GET(RTL931X_LAG_L2_HASH_MSK_IDX, data[0]); + e->ip4_hash_mask_idx = FIELD_GET(RTL931X_LAG_IP4_HASH_MSK_IDX, data[0]); + e->ip6_hash_mask_idx = FIELD_GET(RTL931X_LAG_IP6_HASH_MSK_IDX, data[0]); + e->flood_dlf_bcast.sep_flood_en = FIELD_GET(RTL931X_LAG_SEP_FLOOD_EN, data[0]); + e->sep_kwn_mc_en = FIELD_GET(RTL931X_LAG_SEP_KWN_MC_EN, data[0]); + e->trk_dev7 = FIELD_GET(RTL931X_LAG_TRK_DEV7, data[0]); + e->trk_port7 = FIELD_GET(RTL931X_LAG_TRK_PORT7, data[0]); + e->trk_dev6 = FIELD_GET(RTL931X_LAG_TRK_DEV6, data[0]); + e->trk_port6 = FIELD_GET(RTL931X_LAG_TRK_PORT6, data[0]); + + /* 63-32 */ + e->trk_dev5 = FIELD_GET(RTL931X_LAG_TRK_DEV5, data[1]); + e->trk_port5 = FIELD_GET(RTL931X_LAG_TRK_PORT5, data[1]); + e->trk_dev4 = FIELD_GET(RTL931X_LAG_TRK_DEV4, data[1]); + e->trk_port4 = FIELD_GET(RTL931X_LAG_TRK_PORT4, data[1]); + e->trk_dev3 = FIELD_GET(RTL931X_LAG_TRK_DEV3, data[1]); + e->trk_port3 = FIELD_GET(RTL931X_LAG_TRK_PORT3, data[1]); + + /* 31-0 */ + e->trk_dev2 = FIELD_GET(RTL931X_LAG_TRK_DEV2, data[2]); + e->trk_port2 = FIELD_GET(RTL931X_LAG_TRK_PORT2, data[2]); + e->trk_dev1 = FIELD_GET(RTL931X_LAG_TRK_DEV1, data[2]); + e->trk_port1 = FIELD_GET(RTL931X_LAG_TRK_PORT1, data[2]); + e->trk_dev0 = FIELD_GET(RTL931X_LAG_TRK_DEV0, data[2]); + e->trk_port0 = FIELD_GET(RTL931X_LAG_TRK_PORT0, data[2]); +} + +/* Write lag-entry data into buffer */ +static void rtldsa_931x_lag_write_data(u32 data[], struct rtldsa_93xx_lag_entry *e) +{ + /* 95-64 */ + data[0] = FIELD_PREP(RTL931X_LAG_NUM_TX_CANDI, e->num_tx_candi); + data[0] |= FIELD_PREP(RTL931X_LAG_L2_HASH_MSK_IDX, e->l2_hash_mask_idx); + data[0] |= FIELD_PREP(RTL931X_LAG_IP4_HASH_MSK_IDX, e->ip4_hash_mask_idx); + data[0] |= FIELD_PREP(RTL931X_LAG_IP6_HASH_MSK_IDX, e->ip6_hash_mask_idx); + data[0] |= FIELD_PREP(RTL931X_LAG_SEP_FLOOD_EN, e->flood_dlf_bcast.sep_flood_en); + data[0] |= FIELD_PREP(RTL931X_LAG_SEP_KWN_MC_EN, e->sep_kwn_mc_en); + data[0] |= FIELD_PREP(RTL931X_LAG_TRK_DEV7, e->trk_dev7); + data[0] |= FIELD_PREP(RTL931X_LAG_TRK_PORT7, e->trk_port7); + data[0] |= FIELD_PREP(RTL931X_LAG_TRK_DEV6, e->trk_dev6); + data[0] |= FIELD_PREP(RTL931X_LAG_TRK_PORT6, e->trk_port6); + + /* 63-32 */ + data[1] = FIELD_PREP(RTL931X_LAG_TRK_DEV5, e->trk_dev5); + data[1] |= FIELD_PREP(RTL931X_LAG_TRK_PORT5, e->trk_port5); + data[1] |= FIELD_PREP(RTL931X_LAG_TRK_DEV4, e->trk_dev4); + data[1] |= FIELD_PREP(RTL931X_LAG_TRK_PORT4, e->trk_port4); + data[1] |= FIELD_PREP(RTL931X_LAG_TRK_DEV3, e->trk_dev3); + data[1] |= FIELD_PREP(RTL931X_LAG_TRK_PORT3, e->trk_port3); + + /* 31-0 */ + data[2] = FIELD_PREP(RTL931X_LAG_TRK_DEV2, e->trk_dev2); + data[2] |= FIELD_PREP(RTL931X_LAG_TRK_PORT2, e->trk_port2); + data[2] |= FIELD_PREP(RTL931X_LAG_TRK_DEV1, e->trk_dev1); + data[2] |= FIELD_PREP(RTL931X_LAG_TRK_PORT1, e->trk_port1); + data[2] |= FIELD_PREP(RTL931X_LAG_TRK_DEV0, e->trk_dev0); + data[2] |= FIELD_PREP(RTL931X_LAG_TRK_PORT0, e->trk_port0); +} + +static void rtldsa_931x_lag_set_local_group_id(int local_group, int global_group, bool valid) +{ + u32 mask = 0; + + mask |= valid ? RTL931X_TRK_ID_CTRL_TRK_VALID : 0; + mask |= FIELD_PREP(RLT931X_TRK_ID_CTRL_TRK_ID, global_group); + sw_w32(mask, RTL931X_TRK_ID_CTRL + (4 * local_group)); +} + +static void rtldsa_931x_lag_set_local_port2group(int group, int port, bool valid) +{ + u32 mask = 0; + + mask |= valid ? RTL931X_LOCAL_PORT_TRK_MAP_IS_TRK_MBR : 0; + mask |= FIELD_PREP(RTL931X_LOCAL_PORT_TRK_MAP_TRK_ID, group); + sw_w32(mask, RTL931X_LOCAL_PORT_TRK_MAP + (4 * port)); +} + +static void rtldsa_931x_lag_sync_tables(void) +{ + u32 val; + int ret; + + sw_w32(BIT(0), RTL931X_TRK_LOCAL_TBL_REFRESH); + + ret = readx_poll_timeout(sw_r32, RTL931X_TRK_LOCAL_TBL_REFRESH, val, + !(val & BIT(0)), 20, 10000); + if (ret) + pr_err("%s: timeout\n", __func__); +} + +static struct table_reg *rtldsa_931x_lag_table(void) +{ + return rtl_table_get(RTL9310_TBL_2, 0); +} + static u64 rtldsa_931x_stat_port_table_read(int port, unsigned int mib_size, unsigned int mib_offset, bool is_pvt) { @@ -1930,4 +2047,11 @@ const struct rtldsa_config rtldsa_931x_cfg = { .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, + .lag_set_local_group_id = rtldsa_931x_lag_set_local_group_id, + .lag_write_data = rtldsa_931x_lag_write_data, + .lag_fill_data = rtldsa_931x_lag_fill_data, + .lag_set_local_port2group = rtldsa_931x_lag_set_local_port2group, + .lag_set_port2group = rtldsa_931x_lag_set_port2group, + .lag_sync_tables = rtldsa_931x_lag_sync_tables, + .lag_table = rtldsa_931x_lag_table, };