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)
#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)
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;
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 {
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);
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);
.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,
};
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)
{
.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,
};