mirror of
https://github.com/openwrt/openwrt.git
synced 2025-04-08 03:44:59 +00:00
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 <s.gottschall@dd-wrt.com> Signed-off-by: Birger Koblitz <git@birger-koblitz.de>
This commit is contained in:
parent
8557b458e2
commit
32e5b5ee6b
@ -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;
|
||||
|
@ -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;i<priv->n_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,
|
||||
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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,
|
||||
};
|
||||
|
@ -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,
|
||||
};
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user