From: Birger Koblitz Date: Tue, 18 Jan 2022 13:20:40 +0000 (+0100) Subject: realtek: Add Link Aggregation (aka trunking) support X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=32e5b5ee6b86956d7f97736615bb56c8a28cd841;p=openwrt%2Fstaging%2Fxback.git realtek: Add Link Aggregation (aka trunking) support This adds LAG support for all 4 SoC families, including support ofr the use of different distribution algorithm for the load- balancing between individual links. Signed-off-by: Sebastian Gottschall Signed-off-by: Birger Koblitz --- diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c index 5a90e53da2..ea08ca12fc 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/common.c @@ -402,11 +402,15 @@ static int __init rtl83xx_get_l2aging(struct rtl838x_switch_priv *priv) } /* Caller must hold priv->reg_mutex */ -int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port) +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 i; - + u32 algomsk = 0; + u32 algoidx = 0; + if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { + return -EINVAL; + } pr_info("%s: Adding port %d to LA-group %d\n", __func__, port, group); if (group >= priv->n_lags) { pr_err("Link Agrregation group too large.\n"); @@ -419,18 +423,40 @@ int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port) } for (i = 0; i < priv->n_lags; i++) { - if (priv->lags_port_members[i] & BIT_ULL(i)) + if (priv->lags_port_members[i] & BIT_ULL(port)) break; } if (i != priv->n_lags) { pr_err("%s: Port already member of LAG: %d\n", __func__, i); 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; + } + 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); - pr_info("lags_port_members %d now %016llx\n", group, priv->lags_port_members[group]); + pr_debug("lags_port_members %d now %016llx\n", group, priv->lags_port_members[group]); return 0; } @@ -453,11 +479,10 @@ int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port) if (!(priv->lags_port_members[group] & BIT_ULL(port))) { - pr_err("%s: Port not member of LAG: %d\n", __func__, group - ); + pr_err("%s: Port not member of LAG: %d\n", __func__, group); 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); @@ -625,6 +650,7 @@ static int rtl83xx_handle_changeupper(struct rtl838x_switch_priv *priv, struct netdev_notifier_changeupper_info *info) { struct net_device *upper = info->upper_dev; + struct netdev_lag_upper_info *lag_upper_info = NULL; int i, j, err; if (!netif_is_lag_master(upper)) @@ -646,9 +672,10 @@ static int rtl83xx_handle_changeupper(struct rtl838x_switch_priv *priv, } if (info->linking) { + lag_upper_info = info->upper_info; if (!priv->lag_devs[i]) priv->lag_devs[i] = upper; - err = rtl83xx_lag_add(priv->ds, i, priv->ports[j].dp->index); + err = rtl83xx_lag_add(priv->ds, i, priv->ports[j].dp->index, lag_upper_info); if (err) { err = -EINVAL; goto out; diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c index 0cd4e0d5dd..c71396efab 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/dsa.c @@ -651,6 +651,19 @@ static void rtl83xx_phylink_mac_config(struct dsa_switch *ds, int port, if (state->duplex == RTL839X_DUPLEX_MODE) reg |= RTL839X_DUPLEX_MODE; } + + // LAG members must use DUPLEX and we need to enable the link + if (priv->lagmembers & BIT_ULL(port)) { + switch(priv->family_id) { + case RTL8380_FAMILY_ID: + reg |= (RTL838X_DUPLEX_MODE | RTL838X_FORCE_LINK_EN); + break; + case RTL8390_FAMILY_ID: + reg |= (RTL839X_DUPLEX_MODE | RTL839X_FORCE_LINK_EN); + break; + } + } + // Disable AN if (priv->family_id == RTL8380_FAMILY_ID) reg &= ~RTL838X_NWAY_EN; @@ -717,7 +730,10 @@ static void rtl931x_phylink_mac_config(struct dsa_switch *ds, int port, reg &= ~(0xf << 12); reg |= 0x2 << 12; // Set SMI speed to 0x2 - reg |= BIT(17) | BIT(16); // Enable RX pause and TX pause + reg |= RTL931X_TX_PAUSE_EN | RTL931X_RX_PAUSE_EN; + + if (priv->lagmembers & BIT_ULL(port)) + reg |= RTL931X_DUPLEX_MODE; if (state->duplex == DUPLEX_FULL) reg |= RTL931X_DUPLEX_MODE; @@ -796,6 +812,9 @@ static void rtl93xx_phylink_mac_config(struct dsa_switch *ds, int port, if (state->link) reg |= RTL930X_FORCE_LINK_EN; + if (priv->lagmembers & BIT_ULL(port)) + reg |= RTL930X_DUPLEX_MODE | RTL930X_FORCE_LINK_EN; + if (state->duplex == DUPLEX_FULL) reg |= RTL930X_DUPLEX_MODE; @@ -925,6 +944,11 @@ static int rtl83xx_port_enable(struct dsa_switch *ds, int port, /* add port to switch mask of CPU_PORT */ priv->r->traffic_enable(priv->cpu_port, port); + if (priv->is_lagmember[port]) { + pr_debug("%s: %d is lag slave. ignore\n", __func__, port); + return 0; + } + /* add all other ports in the same bridge to switch mask of port */ v = priv->r->traffic_get(port); v |= priv->ports[port].pm; @@ -1045,13 +1069,19 @@ static int rtl83xx_port_bridge_join(struct dsa_switch *ds, int port, int i; pr_debug("%s %x: %d %llx", __func__, (u32)priv, port, port_bitmap); + + if (priv->is_lagmember[port]) { + pr_debug("%s: %d is lag slave. ignore\n", __func__, port); + return 0; + } + mutex_lock(&priv->reg_mutex); for (i = 0; i < ds->num_ports; i++) { /* Add this port to the port matrix of the other ports in the * same bridge. If the port is disabled, port matrix is kept * and not being setup until the port becomes enabled. */ - if (dsa_is_user_port(ds, i) && i != port) { + if (dsa_is_user_port(ds, i) && !priv->is_lagmember[i] && i != port) { if (dsa_to_port(ds, i)->bridge_dev != bridge) continue; if (priv->ports[i].enable) @@ -1492,6 +1522,11 @@ static int rtl83xx_port_fdb_add(struct dsa_switch *ds, int port, int err = 0, idx; u64 seed = priv->r->l2_hash_seed(mac, vid); + if (priv->is_lagmember[port]) { + pr_debug("%s: %d is lag slave. ignore\n", __func__, port); + return 0; + } + mutex_lock(&priv->reg_mutex); idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e); @@ -1631,6 +1666,12 @@ static int rtl83xx_mc_group_alloc(struct rtl838x_switch_priv *priv, int port) return -1; pr_debug("Using MC group %d\n", mc_group); + + if (priv->is_lagmember[port]) { + pr_debug("%s: %d is lag slave. ignore\n", __func__, port); + return 0; + } + set_bit(mc_group, priv->mc_group_bm); mc_group++; // We cannot use group 0, as this is used for lookup miss flooding portmask = BIT_ULL(port); @@ -1643,6 +1684,11 @@ static u64 rtl83xx_mc_group_add_port(struct rtl838x_switch_priv *priv, int mc_gr { u64 portmask = priv->r->read_mcast_pmask(mc_group); + if (priv->is_lagmember[port]) { + pr_debug("%s: %d is lag slave. ignore\n", __func__, port); + return portmask; + } + portmask |= BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); @@ -1653,6 +1699,11 @@ static u64 rtl83xx_mc_group_del_port(struct rtl838x_switch_priv *priv, int mc_gr { u64 portmask = priv->r->read_mcast_pmask(mc_group); + if (priv->is_lagmember[port]) { + pr_debug("%s: %d is lag slave. ignore\n", __func__, port); + return portmask; + } + portmask &= ~BIT_ULL(port); priv->r->write_mcast_pmask(mc_group, portmask); if (!portmask) @@ -1673,6 +1724,12 @@ static void rtl83xx_port_mdb_add(struct dsa_switch *ds, int port, int mc_group; pr_debug("In %s port %d, mac %llx, vid: %d\n", __func__, port, mac, vid); + + if (priv->is_lagmember[port]) { + pr_debug("%s: %d is lag slave. ignore\n", __func__, port); + return; + } + mutex_lock(&priv->reg_mutex); idx = rtl83xx_find_l2_hash_entry(priv, seed, false, &e); @@ -1736,6 +1793,12 @@ int rtl83xx_port_mdb_del(struct dsa_switch *ds, int port, u64 portmask; pr_debug("In %s, port %d, mac %llx, vid: %d\n", __func__, port, mac, vid); + + if (priv->is_lagmember[port]) { + pr_info("%s: %d is lag slave. ignore\n", __func__, port); + return 0; + } + mutex_lock(&priv->reg_mutex); idx = rtl83xx_find_l2_hash_entry(priv, seed, true, &e); @@ -1864,6 +1927,121 @@ static void rtl83xx_port_mirror_del(struct dsa_switch *ds, int port, mutex_unlock(&priv->reg_mutex); } +static bool rtl83xx_lag_can_offload(struct dsa_switch *ds, + struct net_device *lag, + struct netdev_lag_upper_info *info) +{ + int id; + + id = dsa_lag_id(ds->dst, lag); + if (id < 0 || id >= ds->num_lag_ids) + return false; + + if (info->tx_type != NETDEV_LAG_TX_TYPE_HASH) { + return false; + } + if (info->hash_type != NETDEV_LAG_HASH_L2 && info->hash_type != NETDEV_LAG_HASH_L23) + return false; + + return true; +} + +static int rtl83xx_port_lag_change(struct dsa_switch *ds, int port) +{ + struct rtl838x_switch_priv *priv = ds->priv; + + pr_debug("%s: %d\n", __func__, port); + // Nothing to be done... + + return 0; +} + +static int rtl83xx_port_lag_join(struct dsa_switch *ds, int port, + struct net_device *lag, + struct netdev_lag_upper_info *info) +{ + struct rtl838x_switch_priv *priv = ds->priv; + int i, err = 0; + + if (!rtl83xx_lag_can_offload(ds, lag, info)) + return -EOPNOTSUPP; + + mutex_lock(&priv->reg_mutex); + + for (i = 0; i < priv->n_lags; i++) { + if ((!priv->lag_devs[i]) || (priv->lag_devs[i] == lag)) + break; + } + if (port >= priv->cpu_port) { + err = -EINVAL; + goto out; + } + pr_info("port_lag_join: group %d, port %d\n",i, port); + if (!priv->lag_devs[i]) + priv->lag_devs[i] = lag; + + if (priv->lag_primary[i]==-1) { + priv->lag_primary[i]=port; + } else + priv->is_lagmember[port] = 1; + + priv->lagmembers |= (1ULL << port); + + pr_debug("lag_members = %llX\n", priv->lagmembers); + err = rtl83xx_lag_add(priv->ds, i, port, info); + if (err) { + err = -EINVAL; + goto out; + } + +out: + mutex_unlock(&priv->reg_mutex); + return err; + +} + +static int rtl83xx_port_lag_leave(struct dsa_switch *ds, int port, + struct net_device *lag) +{ + int i, group = -1, err; + struct rtl838x_switch_priv *priv = ds->priv; + + mutex_lock(&priv->reg_mutex); + for (i=0;in_lags;i++) { + if (priv->lags_port_members[i] & BIT_ULL(port)) { + group = i; + break; + } + } + + if (group == -1) { + pr_info("port_lag_leave: port %d is not a member\n", port); + err = -EINVAL; + goto out; + } + + if (port >= priv->cpu_port) { + err = -EINVAL; + goto out; + } + pr_info("port_lag_del: group %d, port %d\n",group, port); + priv->lagmembers &=~ (1ULL << port); + priv->lag_primary[i] = -1; + priv->is_lagmember[port] = 0; + pr_debug("lag_members = %llX\n", priv->lagmembers); + err = rtl83xx_lag_del(priv->ds, group, port); + if (err) { + err = -EINVAL; + goto out; + } + if (!priv->lags_port_members[i]) + priv->lag_devs[i] = NULL; + +out: + mutex_unlock(&priv->reg_mutex); + return 0; +} + int dsa_phy_read(struct dsa_switch *ds, int phy_addr, int phy_reg) { u32 val; @@ -1941,6 +2119,10 @@ const struct dsa_switch_ops rtl83xx_switch_ops = { .port_mirror_add = rtl83xx_port_mirror_add, .port_mirror_del = rtl83xx_port_mirror_del, + + .port_lag_change = rtl83xx_port_lag_change, + .port_lag_join = rtl83xx_port_lag_join, + .port_lag_leave = rtl83xx_port_lag_leave, }; const struct dsa_switch_ops rtl930x_switch_ops = { @@ -1985,4 +2167,8 @@ const struct dsa_switch_ops rtl930x_switch_ops = { .port_mdb_add = rtl83xx_port_mdb_add, .port_mdb_del = rtl83xx_port_mdb_del, + .port_lag_change = rtl83xx_port_lag_change, + .port_lag_join = rtl83xx_port_lag_join, + .port_lag_leave = rtl83xx_port_lag_leave, + }; diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c index cefae82573..85e8c85a7f 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.c @@ -1609,6 +1609,13 @@ static void rtl838x_set_egr_filter(int port, enum egr_filter state) RTL838X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2))); } +void rtl838x_set_distribution_algorithm(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)); +} const struct rtl838x_reg rtl838x_reg = { .mask_port_reg_be = rtl838x_mask_port_reg, @@ -1687,6 +1694,7 @@ const struct rtl838x_reg rtl838x_reg = { .route_read = rtl838x_route_read, .route_write = rtl838x_route_write, .l3_setup = rtl838x_l3_setup, + .set_distribution_algorithm = rtl838x_set_distribution_algorithm, }; irqreturn_t rtl838x_switch_irq(int irq, void *dev_id) diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h index fd2c6d3245..660efc8cad 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl838x.h @@ -320,10 +320,46 @@ #define RTL839X_IGR_BWCTRL_CTRL_LB_THR (0x1614) /* Link aggregation (Trunking) */ -#define RTL839X_TRK_MBR_CTR (0x2200) -#define RTL838X_TRK_MBR_CTR (0x3E00) -#define RTL930X_TRK_MBR_CTRL (0xA41C) -#define RTL931X_TRK_MBR_CTRL (0xB8D0) +#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_L2_SPA_BIT 0x01 +#define TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT 0x02 +#define TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT 0x04 +#define TRUNK_DISTRIBUTION_ALGO_L2_VLAN_BIT 0x08 +#define TRUNK_DISTRIBUTION_ALGO_L2_MASKALL 0xF + +#define TRUNK_DISTRIBUTION_ALGO_L3_SPA_BIT 0x01 +#define TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT 0x02 +#define TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT 0x04 +#define TRUNK_DISTRIBUTION_ALGO_L3_VLAN_BIT 0x08 +#define TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT 0x10 +#define TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT 0x20 +#define TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT 0x40 +#define TRUNK_DISTRIBUTION_ALGO_L3_DST_L4PORT_BIT 0x80 +#define TRUNK_DISTRIBUTION_ALGO_L3_PROTO_BIT 0x100 +#define TRUNK_DISTRIBUTION_ALGO_L3_FLOW_LABEL_BIT 0x200 +#define TRUNK_DISTRIBUTION_ALGO_L3_MASKALL 0x3FF + +#define RTL838X_TRK_MBR_CTR (0x3E00) +#define RTL838X_TRK_HASH_IDX_CTRL (0x3E20) +#define RTL838X_TRK_HASH_CTRL (0x3E24) + +#define RTL839X_TRK_MBR_CTR (0x2200) +#define RTL839X_TRK_HASH_IDX_CTRL (0x2280) +#define RTL839X_TRK_HASH_CTRL (0x2284) + +#define RTL930X_TRK_MBR_CTRL (0xA41C) +#define RTL930X_TRK_HASH_CTRL (0x9F80) + +#define RTL931X_TRK_MBR_CTRL (0xB8D0) +#define RTL931X_TRK_HASH_CTRL (0xBA70) /* Attack prevention */ #define RTL838X_ATK_PRVNT_PORT_EN (0x5B00) @@ -885,6 +921,8 @@ struct rtl838x_reg { 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); + }; struct rtl838x_switch_priv { @@ -912,6 +950,9 @@ struct rtl838x_switch_priv { int n_lags; u64 lags_port_members[MAX_LAGS]; struct net_device *lag_devs[MAX_LAGS]; + u32 lag_primary[MAX_LAGS]; + u32 is_lagmember[57]; + u64 lagmembers; struct notifier_block nb; // TODO: change to different name struct notifier_block ne_nb; struct notifier_block fib_nb; diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c index 8253cf1b34..0d1f3e0382 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl839x.c @@ -1733,6 +1733,12 @@ static void rtl839x_set_egr_filter(int port, enum egr_filter state) RTL839X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2))); } +void rtl839x_set_distribution_algorithm(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)); +} const struct rtl838x_reg rtl839x_reg = { .mask_port_reg_be = rtl839x_mask_port_reg_be, @@ -1811,4 +1817,5 @@ const struct rtl838x_reg rtl839x_reg = { .route_read = rtl839x_route_read, .route_write = rtl839x_route_write, .l3_setup = rtl839x_l3_setup, + .set_distribution_algorithm = rtl839x_set_distribution_algorithm, }; diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h index 70b1c4e09d..0bb11f9b8b 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl83xx.h @@ -129,5 +129,8 @@ int rtl931x_sds_cmu_band_get(int sds, phy_interface_t mode); int rtl931x_sds_cmu_band_set(int sds, bool enable, u32 band, phy_interface_t mode); void rtl931x_sds_init(u32 sds, phy_interface_t mode); +int rtl83xx_lag_add(struct dsa_switch *ds, int group, int port, struct netdev_lag_upper_info *info); +int rtl83xx_lag_del(struct dsa_switch *ds, int group, int port); + #endif /* _NET_DSA_RTL83XX_H */ diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl930x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl930x.c index 04be44fc90..c7fb319229 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl930x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl930x.c @@ -2344,6 +2344,46 @@ static void rtl930x_set_egr_filter(int port, enum egr_filter state) RTL930X_VLAN_PORT_EGR_FLTR + (((port / 29) << 2))); } +void rtl930x_set_distribution_algorithm(int group, int algoidx, u32 algomsk) +{ + u32 l3shift = 0; + u32 newmask = 0; + + /* TODO: for now we set algoidx to 0 */ + algoidx = 0; + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT; + } + if (algomsk & TRUNK_DISTRIBUTION_ALGO_DIP_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT; + } + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT; + } + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT; + } + + if (l3shift == 4) { + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT; + + if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT; + } else { + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT; + if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT; + } + + sw_w32(newmask << l3shift, RTL930X_TRK_HASH_CTRL + (algoidx << 2)); +} + const struct rtl838x_reg rtl930x_reg = { .mask_port_reg_be = rtl838x_mask_port_reg, .set_port_reg_be = rtl838x_set_port_reg, @@ -2428,4 +2468,5 @@ const struct rtl838x_reg rtl930x_reg = { .get_l3_router_mac = rtl930x_get_l3_router_mac, .set_l3_router_mac = rtl930x_set_l3_router_mac, .set_l3_egress_intf = rtl930x_set_l3_egress_intf, + .set_distribution_algorithm = rtl930x_set_distribution_algorithm, }; diff --git a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl931x.c b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl931x.c index f61652f393..7c3cbd2ff9 100644 --- a/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl931x.c +++ b/target/linux/realtek/files-5.10/drivers/net/dsa/rtl83xx/rtl931x.c @@ -386,6 +386,46 @@ static void rtl931x_set_egr_filter(int port, enum egr_filter state) RTL931X_VLAN_PORT_EGR_FLTR + (((port >> 5) << 2))); } +void rtl931x_set_distribution_algorithm(int group, int algoidx, u32 algomsk) +{ + u32 l3shift = 0; + u32 newmask = 0; + + /* TODO: for now we set algoidx to 0 */ + algoidx=0; + + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SIP_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SIP_BIT; + } + if (algomsk & TRUNK_DISTRIBUTION_ALGO_DIP_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DIP_BIT; + } + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT; + } + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SRC_L4PORT_BIT) { + l3shift = 4; + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SRC_L4PORT_BIT; + } + + if (l3shift == 4) { + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_SMAC_BIT; + if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L3_DMAC_BIT; + } else { + if (algomsk & TRUNK_DISTRIBUTION_ALGO_SMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L2_SMAC_BIT; + if (algomsk & TRUNK_DISTRIBUTION_ALGO_DMAC_BIT) + newmask |= TRUNK_DISTRIBUTION_ALGO_L2_DMAC_BIT; + } + + sw_w32(newmask << l3shift, RTL931X_TRK_HASH_CTRL + (algoidx << 2)); +} + const struct rtl838x_reg rtl931x_reg = { .mask_port_reg_be = rtl839x_mask_port_reg_be, .set_port_reg_be = rtl839x_set_port_reg_be, @@ -434,5 +474,6 @@ const struct rtl838x_reg rtl931x_reg = { .trk_mbr_ctr = rtl931x_trk_mbr_ctr, .set_vlan_igr_filter = rtl931x_set_igr_filter, .set_vlan_egr_filter = rtl931x_set_egr_filter, + .set_distribution_algorithm = rtl931x_set_distribution_algorithm, };