Commit 8ab38ed7 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dsa-cross-chip-notifier-cleanup'



Vladimir Oltean says:

====================
DSA cross-chip notifier cleanups

This patch set makes the following improvements:

- Cross-chip notifiers pass a switch index, port index, sometimes tree
  index, all as integers. Sometimes we need to recover the struct
  dsa_port based on those integers. That recovery involves traversing a
  list. By passing directly a pointer to the struct dsa_port we can
  avoid that, and the indices passed previously can still be obtained
  from the passed struct dsa_port.

- Resetting VLAN filtering on a switch has explicit code to make it run
  on a single switch, so it has no place to stay in the cross-chip
  notifier code. Move it out.

- Changing the MTU on a user port affects only that single port, yet the
  code passes through the cross-chip notifier layer where all switches
  are notified. Avoid that.

- Other related cosmetic changes in the MTU changing procedure.

Apart from the slight improvement in performance given by
(a) doing less work in cross-chip notifiers
(b) emitting less cross-chip notifiers
we also end up with about 100 less lines of code.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents cc4bdef2 be6ff966
Loading
Loading
Loading
Loading
+8 −20
Original line number Diff line number Diff line
@@ -54,18 +54,15 @@ struct dsa_notifier_ageing_time_info {

/* DSA_NOTIFIER_BRIDGE_* */
struct dsa_notifier_bridge_info {
	const struct dsa_port *dp;
	struct dsa_bridge bridge;
	int tree_index;
	int sw_index;
	int port;
	bool tx_fwd_offload;
	struct netlink_ext_ack *extack;
};

/* DSA_NOTIFIER_FDB_* */
struct dsa_notifier_fdb_info {
	int sw_index;
	int port;
	const struct dsa_port *dp;
	const unsigned char *addr;
	u16 vid;
	struct dsa_db db;
@@ -81,34 +78,28 @@ struct dsa_notifier_lag_fdb_info {

/* DSA_NOTIFIER_MDB_* */
struct dsa_notifier_mdb_info {
	const struct dsa_port *dp;
	const struct switchdev_obj_port_mdb *mdb;
	int sw_index;
	int port;
	struct dsa_db db;
};

/* DSA_NOTIFIER_LAG_* */
struct dsa_notifier_lag_info {
	const struct dsa_port *dp;
	struct dsa_lag lag;
	int sw_index;
	int port;

	struct netdev_lag_upper_info *info;
};

/* DSA_NOTIFIER_VLAN_* */
struct dsa_notifier_vlan_info {
	const struct dsa_port *dp;
	const struct switchdev_obj_port_vlan *vlan;
	int sw_index;
	int port;
	struct netlink_ext_ack *extack;
};

/* DSA_NOTIFIER_MTU */
struct dsa_notifier_mtu_info {
	bool targeted_match;
	int sw_index;
	int port;
	const struct dsa_port *dp;
	int mtu;
};

@@ -119,9 +110,7 @@ struct dsa_notifier_tag_proto_info {

/* DSA_NOTIFIER_TAG_8021Q_VLAN_* */
struct dsa_notifier_tag_8021q_vlan_info {
	int tree_index;
	int sw_index;
	int port;
	const struct dsa_port *dp;
	u16 vid;
};

@@ -241,8 +230,7 @@ int dsa_port_mst_enable(struct dsa_port *dp, bool on,
			struct netlink_ext_ack *extack);
int dsa_port_vlan_msti(struct dsa_port *dp,
		       const struct switchdev_vlan_msti *msti);
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
			bool targeted_match);
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu);
int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
		     u16 vid);
int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
+78 −50
Original line number Diff line number Diff line
@@ -242,6 +242,59 @@ void dsa_port_disable(struct dsa_port *dp)
	rtnl_unlock();
}

static void dsa_port_reset_vlan_filtering(struct dsa_port *dp,
					  struct dsa_bridge bridge)
{
	struct netlink_ext_ack extack = {0};
	bool change_vlan_filtering = false;
	struct dsa_switch *ds = dp->ds;
	bool vlan_filtering;
	int err;

	if (ds->needs_standalone_vlan_filtering &&
	    !br_vlan_enabled(bridge.dev)) {
		change_vlan_filtering = true;
		vlan_filtering = true;
	} else if (!ds->needs_standalone_vlan_filtering &&
		   br_vlan_enabled(bridge.dev)) {
		change_vlan_filtering = true;
		vlan_filtering = false;
	}

	/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
	 * event for changing vlan_filtering setting upon slave ports leaving
	 * it. That is a good thing, because that lets us handle it and also
	 * handle the case where the switch's vlan_filtering setting is global
	 * (not per port). When that happens, the correct moment to trigger the
	 * vlan_filtering callback is only when the last port leaves the last
	 * VLAN-aware bridge.
	 */
	if (change_vlan_filtering && ds->vlan_filtering_is_global) {
		dsa_switch_for_each_port(dp, ds) {
			struct net_device *br = dsa_port_bridge_dev_get(dp);

			if (br && br_vlan_enabled(br)) {
				change_vlan_filtering = false;
				break;
			}
		}
	}

	if (!change_vlan_filtering)
		return;

	err = dsa_port_vlan_filtering(dp, vlan_filtering, &extack);
	if (extack._msg) {
		dev_err(ds->dev, "port %d: %s\n", dp->index,
			extack._msg);
	}
	if (err && err != -EOPNOTSUPP) {
		dev_err(ds->dev,
			"port %d failed to reset VLAN filtering to %d: %pe\n",
		       dp->index, vlan_filtering, ERR_PTR(err));
	}
}

static int dsa_port_inherit_brport_flags(struct dsa_port *dp,
					 struct netlink_ext_ack *extack)
{
@@ -313,7 +366,8 @@ static int dsa_port_switchdev_sync_attrs(struct dsa_port *dp,
	return 0;
}

static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp,
					    struct dsa_bridge bridge)
{
	/* Configure the port for standalone mode (no address learning,
	 * flood everything).
@@ -333,7 +387,7 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
	 */
	dsa_port_set_state_now(dp, BR_STATE_FORWARDING, true);

	/* VLAN filtering is handled by dsa_switch_bridge_leave */
	dsa_port_reset_vlan_filtering(dp, bridge);

	/* Ageing time may be global to the switch chip, so don't change it
	 * here because we have no good reason (or value) to change it to.
@@ -405,9 +459,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
			 struct netlink_ext_ack *extack)
{
	struct dsa_notifier_bridge_info info = {
		.tree_index = dp->ds->dst->index,
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.extack = extack,
	};
	struct net_device *dev = dp->slave;
@@ -476,9 +528,7 @@ void dsa_port_pre_bridge_leave(struct dsa_port *dp, struct net_device *br)
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
{
	struct dsa_notifier_bridge_info info = {
		.tree_index = dp->ds->dst->index,
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
	};
	int err;

@@ -501,15 +551,14 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
			"port %d failed to notify DSA_NOTIFIER_BRIDGE_LEAVE: %pe\n",
			dp->index, ERR_PTR(err));

	dsa_port_switchdev_unsync_attrs(dp);
	dsa_port_switchdev_unsync_attrs(dp, info.bridge);
}

int dsa_port_lag_change(struct dsa_port *dp,
			struct netdev_lag_lower_state_info *linfo)
{
	struct dsa_notifier_lag_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
	};
	bool tx_enabled;

@@ -578,8 +627,7 @@ int dsa_port_lag_join(struct dsa_port *dp, struct net_device *lag_dev,
		      struct netlink_ext_ack *extack)
{
	struct dsa_notifier_lag_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.info = uinfo,
	};
	struct net_device *bridge_dev;
@@ -624,8 +672,7 @@ void dsa_port_lag_leave(struct dsa_port *dp, struct net_device *lag_dev)
{
	struct net_device *br = dsa_port_bridge_dev_get(dp);
	struct dsa_notifier_lag_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
	};
	int err;

@@ -883,13 +930,10 @@ int dsa_port_vlan_msti(struct dsa_port *dp,
	return ds->ops->vlan_msti_set(ds, *dp->bridge, msti);
}

int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu,
			bool targeted_match)
int dsa_port_mtu_change(struct dsa_port *dp, int new_mtu)
{
	struct dsa_notifier_mtu_info info = {
		.sw_index = dp->ds->index,
		.targeted_match = targeted_match,
		.port = dp->index,
		.dp = dp,
		.mtu = new_mtu,
	};

@@ -900,8 +944,7 @@ int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr,
		     u16 vid)
{
	struct dsa_notifier_fdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.addr = addr,
		.vid = vid,
		.db = {
@@ -924,8 +967,7 @@ int dsa_port_fdb_del(struct dsa_port *dp, const unsigned char *addr,
		     u16 vid)
{
	struct dsa_notifier_fdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.addr = addr,
		.vid = vid,
		.db = {
@@ -945,8 +987,7 @@ static int dsa_port_host_fdb_add(struct dsa_port *dp,
				 struct dsa_db db)
{
	struct dsa_notifier_fdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.addr = addr,
		.vid = vid,
		.db = db,
@@ -997,8 +1038,7 @@ static int dsa_port_host_fdb_del(struct dsa_port *dp,
				 struct dsa_db db)
{
	struct dsa_notifier_fdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.addr = addr,
		.vid = vid,
		.db = db,
@@ -1093,8 +1133,7 @@ int dsa_port_mdb_add(const struct dsa_port *dp,
		     const struct switchdev_obj_port_mdb *mdb)
{
	struct dsa_notifier_mdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.mdb = mdb,
		.db = {
			.type = DSA_DB_BRIDGE,
@@ -1112,8 +1151,7 @@ int dsa_port_mdb_del(const struct dsa_port *dp,
		     const struct switchdev_obj_port_mdb *mdb)
{
	struct dsa_notifier_mdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.mdb = mdb,
		.db = {
			.type = DSA_DB_BRIDGE,
@@ -1132,8 +1170,7 @@ static int dsa_port_host_mdb_add(const struct dsa_port *dp,
				 struct dsa_db db)
{
	struct dsa_notifier_mdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.mdb = mdb,
		.db = db,
	};
@@ -1177,8 +1214,7 @@ static int dsa_port_host_mdb_del(const struct dsa_port *dp,
				 struct dsa_db db)
{
	struct dsa_notifier_mdb_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.mdb = mdb,
		.db = db,
	};
@@ -1222,8 +1258,7 @@ int dsa_port_vlan_add(struct dsa_port *dp,
		      struct netlink_ext_ack *extack)
{
	struct dsa_notifier_vlan_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.vlan = vlan,
		.extack = extack,
	};
@@ -1235,8 +1270,7 @@ int dsa_port_vlan_del(struct dsa_port *dp,
		      const struct switchdev_obj_port_vlan *vlan)
{
	struct dsa_notifier_vlan_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.vlan = vlan,
	};

@@ -1248,8 +1282,7 @@ int dsa_port_host_vlan_add(struct dsa_port *dp,
			   struct netlink_ext_ack *extack)
{
	struct dsa_notifier_vlan_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.vlan = vlan,
		.extack = extack,
	};
@@ -1269,8 +1302,7 @@ int dsa_port_host_vlan_del(struct dsa_port *dp,
			   const struct switchdev_obj_port_vlan *vlan)
{
	struct dsa_notifier_vlan_info info = {
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.vlan = vlan,
	};
	struct dsa_port *cpu_dp = dp->cpu_dp;
@@ -1689,9 +1721,7 @@ void dsa_port_hsr_leave(struct dsa_port *dp, struct net_device *hsr)
int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast)
{
	struct dsa_notifier_tag_8021q_vlan_info info = {
		.tree_index = dp->ds->dst->index,
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.vid = vid,
	};

@@ -1704,9 +1734,7 @@ int dsa_port_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid, bool broadcast)
void dsa_port_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid, bool broadcast)
{
	struct dsa_notifier_tag_8021q_vlan_info info = {
		.tree_index = dp->ds->dst->index,
		.sw_index = dp->ds->index,
		.port = dp->index,
		.dp = dp,
		.vid = vid,
	};
	int err;
+11 −20
Original line number Diff line number Diff line
@@ -1806,11 +1806,9 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
{
	struct net_device *master = dsa_slave_to_master(dev);
	struct dsa_port *dp = dsa_slave_to_port(dev);
	struct dsa_slave_priv *p = netdev_priv(dev);
	struct dsa_switch *ds = p->dp->ds;
	struct dsa_port *dp_iter;
	struct dsa_port *cpu_dp;
	int port = p->dp->index;
	struct dsa_port *cpu_dp = dp->cpu_dp;
	struct dsa_switch *ds = dp->ds;
	struct dsa_port *other_dp;
	int largest_mtu = 0;
	int new_master_mtu;
	int old_master_mtu;
@@ -1821,33 +1819,28 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
	if (!ds->ops->port_change_mtu)
		return -EOPNOTSUPP;

	list_for_each_entry(dp_iter, &ds->dst->ports, list) {
	dsa_tree_for_each_user_port(other_dp, ds->dst) {
		int slave_mtu;

		if (!dsa_port_is_user(dp_iter))
			continue;

		/* During probe, this function will be called for each slave
		 * device, while not all of them have been allocated. That's
		 * ok, it doesn't change what the maximum is, so ignore it.
		 */
		if (!dp_iter->slave)
		if (!other_dp->slave)
			continue;

		/* Pretend that we already applied the setting, which we
		 * actually haven't (still haven't done all integrity checks)
		 */
		if (dp_iter == dp)
		if (dp == other_dp)
			slave_mtu = new_mtu;
		else
			slave_mtu = dp_iter->slave->mtu;
			slave_mtu = other_dp->slave->mtu;

		if (largest_mtu < slave_mtu)
			largest_mtu = slave_mtu;
	}

	cpu_dp = dsa_to_port(ds, port)->cpu_dp;

	mtu_limit = min_t(int, master->max_mtu, dev->max_mtu);
	old_master_mtu = master->mtu;
	new_master_mtu = largest_mtu + dsa_tag_protocol_overhead(cpu_dp->tag_ops);
@@ -1866,15 +1859,14 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
			goto out_master_failed;

		/* We only need to propagate the MTU of the CPU port to
		 * upstream switches, so create a non-targeted notifier which
		 * updates all switches.
		 * upstream switches, so emit a notifier which updates them.
		 */
		err = dsa_port_mtu_change(cpu_dp, cpu_mtu, false);
		err = dsa_port_mtu_change(cpu_dp, cpu_mtu);
		if (err)
			goto out_cpu_failed;
	}

	err = dsa_port_mtu_change(dp, new_mtu, true);
	err = ds->ops->port_change_mtu(ds, dp->index, new_mtu);
	if (err)
		goto out_port_failed;

@@ -1887,8 +1879,7 @@ int dsa_slave_change_mtu(struct net_device *dev, int new_mtu)
out_port_failed:
	if (new_master_mtu != old_master_mtu)
		dsa_port_mtu_change(cpu_dp, old_master_mtu -
				    dsa_tag_protocol_overhead(cpu_dp->tag_ops),
				    false);
				    dsa_tag_protocol_overhead(cpu_dp->tag_ops));
out_cpu_failed:
	if (new_master_mtu != old_master_mtu)
		dev_set_mtu(master, old_master_mtu);
+48 −140
Original line number Diff line number Diff line
@@ -49,19 +49,7 @@ static int dsa_switch_ageing_time(struct dsa_switch *ds,
static bool dsa_port_mtu_match(struct dsa_port *dp,
			       struct dsa_notifier_mtu_info *info)
{
	if (dp->ds->index == info->sw_index && dp->index == info->port)
		return true;

	/* Do not propagate to other switches in the tree if the notifier was
	 * targeted for a single switch.
	 */
	if (info->targeted_match)
		return false;

	if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
		return true;

	return false;
	return dp == info->dp || dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp);
}

static int dsa_switch_mtu(struct dsa_switch *ds,
@@ -88,25 +76,26 @@ static int dsa_switch_mtu(struct dsa_switch *ds,
static int dsa_switch_bridge_join(struct dsa_switch *ds,
				  struct dsa_notifier_bridge_info *info)
{
	struct dsa_switch_tree *dst = ds->dst;
	int err;

	if (dst->index == info->tree_index && ds->index == info->sw_index) {
	if (info->dp->ds == ds) {
		if (!ds->ops->port_bridge_join)
			return -EOPNOTSUPP;

		err = ds->ops->port_bridge_join(ds, info->port, info->bridge,
		err = ds->ops->port_bridge_join(ds, info->dp->index,
						info->bridge,
						&info->tx_fwd_offload,
						info->extack);
		if (err)
			return err;
	}

	if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
	    ds->ops->crosschip_bridge_join) {
		err = ds->ops->crosschip_bridge_join(ds, info->tree_index,
						     info->sw_index,
						     info->port, info->bridge,
	if (info->dp->ds != ds && ds->ops->crosschip_bridge_join) {
		err = ds->ops->crosschip_bridge_join(ds,
						     info->dp->ds->dst->index,
						     info->dp->ds->index,
						     info->dp->index,
						     info->bridge,
						     info->extack);
		if (err)
			return err;
@@ -115,79 +104,18 @@ static int dsa_switch_bridge_join(struct dsa_switch *ds,
	return 0;
}

static int dsa_switch_sync_vlan_filtering(struct dsa_switch *ds,
					  struct dsa_notifier_bridge_info *info)
{
	struct netlink_ext_ack extack = {0};
	bool change_vlan_filtering = false;
	bool vlan_filtering;
	struct dsa_port *dp;
	int err;

	if (ds->needs_standalone_vlan_filtering &&
	    !br_vlan_enabled(info->bridge.dev)) {
		change_vlan_filtering = true;
		vlan_filtering = true;
	} else if (!ds->needs_standalone_vlan_filtering &&
		   br_vlan_enabled(info->bridge.dev)) {
		change_vlan_filtering = true;
		vlan_filtering = false;
	}

	/* If the bridge was vlan_filtering, the bridge core doesn't trigger an
	 * event for changing vlan_filtering setting upon slave ports leaving
	 * it. That is a good thing, because that lets us handle it and also
	 * handle the case where the switch's vlan_filtering setting is global
	 * (not per port). When that happens, the correct moment to trigger the
	 * vlan_filtering callback is only when the last port leaves the last
	 * VLAN-aware bridge.
	 */
	if (change_vlan_filtering && ds->vlan_filtering_is_global) {
		dsa_switch_for_each_port(dp, ds) {
			struct net_device *br = dsa_port_bridge_dev_get(dp);

			if (br && br_vlan_enabled(br)) {
				change_vlan_filtering = false;
				break;
			}
		}
	}

	if (change_vlan_filtering) {
		err = dsa_port_vlan_filtering(dsa_to_port(ds, info->port),
					      vlan_filtering, &extack);
		if (extack._msg)
			dev_err(ds->dev, "port %d: %s\n", info->port,
				extack._msg);
		if (err && err != -EOPNOTSUPP)
			return err;
	}

	return 0;
}

static int dsa_switch_bridge_leave(struct dsa_switch *ds,
				   struct dsa_notifier_bridge_info *info)
{
	struct dsa_switch_tree *dst = ds->dst;
	int err;
	if (info->dp->ds == ds && ds->ops->port_bridge_leave)
		ds->ops->port_bridge_leave(ds, info->dp->index, info->bridge);

	if (dst->index == info->tree_index && ds->index == info->sw_index &&
	    ds->ops->port_bridge_leave)
		ds->ops->port_bridge_leave(ds, info->port, info->bridge);

	if ((dst->index != info->tree_index || ds->index != info->sw_index) &&
	    ds->ops->crosschip_bridge_leave)
		ds->ops->crosschip_bridge_leave(ds, info->tree_index,
						info->sw_index, info->port,
	if (info->dp->ds != ds && ds->ops->crosschip_bridge_leave)
		ds->ops->crosschip_bridge_leave(ds, info->dp->ds->dst->index,
						info->dp->ds->index,
						info->dp->index,
						info->bridge);

	if (ds->dst->index == info->tree_index && ds->index == info->sw_index) {
		err = dsa_switch_sync_vlan_filtering(ds, info);
		if (err)
			return err;
	}

	return 0;
}

@@ -196,16 +124,11 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
 * emitted and its dedicated CPU port.
 */
static bool dsa_port_host_address_match(struct dsa_port *dp,
					int info_sw_index, int info_port)
					const struct dsa_port *targeted_dp)
{
	struct dsa_port *targeted_dp, *cpu_dp;
	struct dsa_switch *targeted_ds;
	struct dsa_port *cpu_dp = targeted_dp->cpu_dp;

	targeted_ds = dsa_switch_find(dp->ds->dst->index, info_sw_index);
	targeted_dp = dsa_to_port(targeted_ds, info_port);
	cpu_dp = targeted_dp->cpu_dp;

	if (dsa_switch_is_upstream_of(dp->ds, targeted_ds))
	if (dsa_switch_is_upstream_of(dp->ds, targeted_dp->ds))
		return dp->index == dsa_towards_port(dp->ds, cpu_dp->ds->index,
						     cpu_dp->index);

@@ -473,8 +396,7 @@ static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
		return -EOPNOTSUPP;

	dsa_switch_for_each_port(dp, ds) {
		if (dsa_port_host_address_match(dp, info->sw_index,
						info->port)) {
		if (dsa_port_host_address_match(dp, info->dp)) {
			err = dsa_port_do_fdb_add(dp, info->addr, info->vid,
						  info->db);
			if (err)
@@ -495,8 +417,7 @@ static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
		return -EOPNOTSUPP;

	dsa_switch_for_each_port(dp, ds) {
		if (dsa_port_host_address_match(dp, info->sw_index,
						info->port)) {
		if (dsa_port_host_address_match(dp, info->dp)) {
			err = dsa_port_do_fdb_del(dp, info->addr, info->vid,
						  info->db);
			if (err)
@@ -510,7 +431,7 @@ static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
static int dsa_switch_fdb_add(struct dsa_switch *ds,
			      struct dsa_notifier_fdb_info *info)
{
	int port = dsa_towards_port(ds, info->sw_index, info->port);
	int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
	struct dsa_port *dp = dsa_to_port(ds, port);

	if (!ds->ops->port_fdb_add)
@@ -522,7 +443,7 @@ static int dsa_switch_fdb_add(struct dsa_switch *ds,
static int dsa_switch_fdb_del(struct dsa_switch *ds,
			      struct dsa_notifier_fdb_info *info)
{
	int port = dsa_towards_port(ds, info->sw_index, info->port);
	int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
	struct dsa_port *dp = dsa_to_port(ds, port);

	if (!ds->ops->port_fdb_del)
@@ -570,12 +491,12 @@ static int dsa_switch_lag_fdb_del(struct dsa_switch *ds,
static int dsa_switch_lag_change(struct dsa_switch *ds,
				 struct dsa_notifier_lag_info *info)
{
	if (ds->index == info->sw_index && ds->ops->port_lag_change)
		return ds->ops->port_lag_change(ds, info->port);
	if (info->dp->ds == ds && ds->ops->port_lag_change)
		return ds->ops->port_lag_change(ds, info->dp->index);

	if (ds->index != info->sw_index && ds->ops->crosschip_lag_change)
		return ds->ops->crosschip_lag_change(ds, info->sw_index,
						     info->port);
	if (info->dp->ds != ds && ds->ops->crosschip_lag_change)
		return ds->ops->crosschip_lag_change(ds, info->dp->ds->index,
						     info->dp->index);

	return 0;
}
@@ -583,13 +504,13 @@ static int dsa_switch_lag_change(struct dsa_switch *ds,
static int dsa_switch_lag_join(struct dsa_switch *ds,
			       struct dsa_notifier_lag_info *info)
{
	if (ds->index == info->sw_index && ds->ops->port_lag_join)
		return ds->ops->port_lag_join(ds, info->port, info->lag,
	if (info->dp->ds == ds && ds->ops->port_lag_join)
		return ds->ops->port_lag_join(ds, info->dp->index, info->lag,
					      info->info);

	if (ds->index != info->sw_index && ds->ops->crosschip_lag_join)
		return ds->ops->crosschip_lag_join(ds, info->sw_index,
						   info->port, info->lag,
	if (info->dp->ds != ds && ds->ops->crosschip_lag_join)
		return ds->ops->crosschip_lag_join(ds, info->dp->ds->index,
						   info->dp->index, info->lag,
						   info->info);

	return -EOPNOTSUPP;
@@ -598,12 +519,12 @@ static int dsa_switch_lag_join(struct dsa_switch *ds,
static int dsa_switch_lag_leave(struct dsa_switch *ds,
				struct dsa_notifier_lag_info *info)
{
	if (ds->index == info->sw_index && ds->ops->port_lag_leave)
		return ds->ops->port_lag_leave(ds, info->port, info->lag);
	if (info->dp->ds == ds && ds->ops->port_lag_leave)
		return ds->ops->port_lag_leave(ds, info->dp->index, info->lag);

	if (ds->index != info->sw_index && ds->ops->crosschip_lag_leave)
		return ds->ops->crosschip_lag_leave(ds, info->sw_index,
						    info->port, info->lag);
	if (info->dp->ds != ds && ds->ops->crosschip_lag_leave)
		return ds->ops->crosschip_lag_leave(ds, info->dp->ds->index,
						    info->dp->index, info->lag);

	return -EOPNOTSUPP;
}
@@ -611,7 +532,7 @@ static int dsa_switch_lag_leave(struct dsa_switch *ds,
static int dsa_switch_mdb_add(struct dsa_switch *ds,
			      struct dsa_notifier_mdb_info *info)
{
	int port = dsa_towards_port(ds, info->sw_index, info->port);
	int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
	struct dsa_port *dp = dsa_to_port(ds, port);

	if (!ds->ops->port_mdb_add)
@@ -623,7 +544,7 @@ static int dsa_switch_mdb_add(struct dsa_switch *ds,
static int dsa_switch_mdb_del(struct dsa_switch *ds,
			      struct dsa_notifier_mdb_info *info)
{
	int port = dsa_towards_port(ds, info->sw_index, info->port);
	int port = dsa_towards_port(ds, info->dp->ds->index, info->dp->index);
	struct dsa_port *dp = dsa_to_port(ds, port);

	if (!ds->ops->port_mdb_del)
@@ -642,8 +563,7 @@ static int dsa_switch_host_mdb_add(struct dsa_switch *ds,
		return -EOPNOTSUPP;

	dsa_switch_for_each_port(dp, ds) {
		if (dsa_port_host_address_match(dp, info->sw_index,
						info->port)) {
		if (dsa_port_host_address_match(dp, info->dp)) {
			err = dsa_port_do_mdb_add(dp, info->mdb, info->db);
			if (err)
				break;
@@ -663,8 +583,7 @@ static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
		return -EOPNOTSUPP;

	dsa_switch_for_each_port(dp, ds) {
		if (dsa_port_host_address_match(dp, info->sw_index,
						info->port)) {
		if (dsa_port_host_address_match(dp, info->dp)) {
			err = dsa_port_do_mdb_del(dp, info->mdb, info->db);
			if (err)
				break;
@@ -678,29 +597,18 @@ static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
static bool dsa_port_vlan_match(struct dsa_port *dp,
				struct dsa_notifier_vlan_info *info)
{
	if (dp->ds->index == info->sw_index && dp->index == info->port)
		return true;

	if (dsa_port_is_dsa(dp))
		return true;

	return false;
	return dsa_port_is_dsa(dp) || dp == info->dp;
}

/* Host VLANs match on the targeted port's CPU port, and on all DSA ports
 * (upstream and downstream) of that switch and its upstream switches.
 */
static bool dsa_port_host_vlan_match(struct dsa_port *dp,
				     struct dsa_notifier_vlan_info *info)
				     const struct dsa_port *targeted_dp)
{
	struct dsa_port *targeted_dp, *cpu_dp;
	struct dsa_switch *targeted_ds;

	targeted_ds = dsa_switch_find(dp->ds->dst->index, info->sw_index);
	targeted_dp = dsa_to_port(targeted_ds, info->port);
	cpu_dp = targeted_dp->cpu_dp;
	struct dsa_port *cpu_dp = targeted_dp->cpu_dp;

	if (dsa_switch_is_upstream_of(dp->ds, targeted_ds))
	if (dsa_switch_is_upstream_of(dp->ds, targeted_dp->ds))
		return dsa_port_is_dsa(dp) || dp == cpu_dp;

	return false;
@@ -858,7 +766,7 @@ static int dsa_switch_host_vlan_add(struct dsa_switch *ds,
		return -EOPNOTSUPP;

	dsa_switch_for_each_port(dp, ds) {
		if (dsa_port_host_vlan_match(dp, info)) {
		if (dsa_port_host_vlan_match(dp, info->dp)) {
			err = dsa_port_do_vlan_add(dp, info->vlan,
						   info->extack);
			if (err)
@@ -879,7 +787,7 @@ static int dsa_switch_host_vlan_del(struct dsa_switch *ds,
		return -EOPNOTSUPP;

	dsa_switch_for_each_port(dp, ds) {
		if (dsa_port_host_vlan_match(dp, info)) {
		if (dsa_port_host_vlan_match(dp, info->dp)) {
			err = dsa_port_do_vlan_del(dp, info->vlan);
			if (err)
				return err;
+1 −9
Original line number Diff line number Diff line
@@ -196,15 +196,7 @@ static bool
dsa_port_tag_8021q_vlan_match(struct dsa_port *dp,
			      struct dsa_notifier_tag_8021q_vlan_info *info)
{
	struct dsa_switch *ds = dp->ds;

	if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
		return true;

	if (ds->dst->index == info->tree_index && ds->index == info->sw_index)
		return dp->index == info->port;

	return false;
	return dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp) || dp == info->dp;
}

int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,