return idx;
}
+/**
+ * rtldsa_find_lag_group_from_port() - Find lag group of current port
+ * @priv: private data of rtldsa switch
+ * @port: port id of potential LAG member
+ * Return: -ENOENT when port does not belong to any lag group, lag id otherwise
+ */
+static int rtldsa_find_lag_group_from_port(struct rtl838x_switch_priv *priv, int port)
+{
+ if (!(priv->lagmembers & BIT_ULL(port)))
+ return -ENOENT;
+
+ /* port is a lag member */
+ for (int lag_group = 0; lag_group < MAX_LAGS; lag_group++) {
+ if (priv->lags_port_members[lag_group] & BIT_ULL(port))
+ return lag_group;
+ }
+
+ return -ENOENT;
+}
+
+/**
+ * rtldsa_93xx_prepare_lag_fdb() - Prepare fdb entry for LAG
+ * @e: L2 entry data
+ * @lag_group: lag id of the trunk group
+ */
+inline void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group)
+{
+ if (e && lag_group >= 0) {
+ e->is_trunk = true;
+ e->trunk = lag_group;
+ }
+}
+
static int rtldsa_port_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid,
const struct dsa_db db)
struct rtl838x_l2_entry e;
int err = 0, idx;
u64 seed = priv->r->l2_hash_seed(mac, vid);
+ int lag_group = rtldsa_find_lag_group_from_port(priv, port);
- if (priv->lag_non_primary & BIT_ULL(port)) {
- pr_debug("%s: %d is lag slave. ignore\n", __func__, port);
- return 0;
+ if (lag_group >= 0 && priv->r->prepare_lag_fdb) {
+ priv->r->prepare_lag_fdb(&e, lag_group);
+ } else {
+ if (priv->lag_non_primary & BIT_ULL(port)) {
+ pr_debug("%s: %d is lag slave but prepare_lag_fdb is not supported. ignore\n",
+ __func__, port);
+ return 0;
+ }
}
mutex_lock(&priv->reg_mutex);
struct rtl838x_l2_entry e;
int err = 0, idx;
u64 seed = priv->r->l2_hash_seed(mac, vid);
+ int lag_group = rtldsa_find_lag_group_from_port(priv, port);
+
+ if (lag_group >= 0 && priv->r->prepare_lag_fdb)
+ priv->r->prepare_lag_fdb(&e, lag_group);
pr_debug("In %s, mac %llx, vid: %d\n", __func__, mac, vid);
+
mutex_lock(&priv->reg_mutex);
idx = rtldsa_find_l2_hash_entry(priv, seed, true, &e);
if (!e.valid)
continue;
+ // Ignore trunk fdb entries
+ if (e.is_trunk)
+ continue;
+
if (e.port == port || e.port == RTL930X_PORT_IGNORE)
cb(e.mac, e.vid, e.is_static, data);
if (!e.valid)
continue;
+ // Ignore trunk fdb entries
+ if (e.is_trunk)
+ continue;
+
if (e.port == port)
cb(e.mac, e.vid, e.is_static, data);
}
}
pr_info("port_lag_del: group %d, port %d\n", group, port);
priv->lagmembers &= ~BIT_ULL(port);
- priv->lag_primary[group] = -1;
priv->lag_non_primary &= ~BIT_ULL(port);
pr_debug("lag_members = %llX\n", priv->lagmembers);
err = rtl83xx_lag_del(priv->ds, group, port);
goto out;
}
+ /* To re-elect primary interface, just remove the first interface in
+ * this-group's interfaces from non-primary
+ */
+ if (priv->lags_port_members[group]) {
+ priv->lag_primary[group] = fls64(priv->lags_port_members[group]);
+ priv->lag_non_primary &= ~BIT_ULL(priv->lag_primary[group]);
+ }
+
+ /* No need to update fdb entries since they make use of trunk_id for entry.
+ * The primary interface is only calculated at time of
+ * port_fdb_dump
+ */
+
out:
mutex_unlock(&priv->reg_mutex);
return 0;
void (*led_init)(struct rtl838x_switch_priv *priv);
void (*qos_init)(struct rtl838x_switch_priv *priv);
int (*trk_mbr_ctr)(int group);
+ void (*lag_switch_init)(struct rtl838x_switch_priv *priv);
+ void (*prepare_lag_fdb)(struct rtl838x_l2_entry *e, int lag_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,
int rtldsa_93xx_lag_set_distribution_algorithm(struct rtl838x_switch_priv *priv,
int group, int algoidx, u32 algomsk);
+void rtldsa_93xx_prepare_lag_fdb(struct rtl838x_l2_entry *e, int lag_group);
+
void rtldsa_counters_lock_register(struct rtl838x_switch_priv *priv, int port)
__acquires(&priv->ports[port].counters.lock);
void rtldsa_counters_unlock_register(struct rtl838x_switch_priv *priv, int port)