Commit d0004a02 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by David S. Miller
Browse files

net: dsa: remove the "dsa_to_port in a loop" antipattern from the core



Ever since Vivien's conversion of the ds->ports array into a dst->ports
list, and the introduction of dsa_to_port, iterations through the ports
of a switch became quadratic whenever dsa_to_port was needed.

dsa_to_port can either be called directly, or indirectly through the
dsa_is_{user,cpu,dsa,unused}_port helpers.

Use the newly introduced dsa_switch_for_each_port() iteration macro
that works with the iterator variable being a struct dsa_port *dp
directly, and not an int i. It is an expensive variable to go from i to
dp, but cheap to go from dp to i.

This macro iterates through the entire ds->dst->ports list and filters
by the ports belonging just to the switch provided as argument.

Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 82b31898
Loading
Loading
Loading
Loading
+3 −4
Original line number Diff line number Diff line
@@ -504,12 +504,11 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)

static inline u32 dsa_user_ports(struct dsa_switch *ds)
{
	struct dsa_port *dp;
	u32 mask = 0;
	int p;

	for (p = 0; p < ds->num_ports; p++)
		if (dsa_is_user_port(ds, p))
			mask |= BIT(p);
	dsa_switch_for_each_user_port(dp, ds)
		mask |= BIT(dp->index);

	return mask;
}
+11 −11
Original line number Diff line number Diff line
@@ -280,23 +280,22 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
}

#ifdef CONFIG_PM_SLEEP
static bool dsa_is_port_initialized(struct dsa_switch *ds, int p)
static bool dsa_port_is_initialized(const struct dsa_port *dp)
{
	const struct dsa_port *dp = dsa_to_port(ds, p);

	return dp->type == DSA_PORT_TYPE_USER && dp->slave;
}

int dsa_switch_suspend(struct dsa_switch *ds)
{
	int i, ret = 0;
	struct dsa_port *dp;
	int ret = 0;

	/* Suspend slave network devices */
	for (i = 0; i < ds->num_ports; i++) {
		if (!dsa_is_port_initialized(ds, i))
	dsa_switch_for_each_port(dp, ds) {
		if (!dsa_port_is_initialized(dp))
			continue;

		ret = dsa_slave_suspend(dsa_to_port(ds, i)->slave);
		ret = dsa_slave_suspend(dp->slave);
		if (ret)
			return ret;
	}
@@ -310,7 +309,8 @@ EXPORT_SYMBOL_GPL(dsa_switch_suspend);

int dsa_switch_resume(struct dsa_switch *ds)
{
	int i, ret = 0;
	struct dsa_port *dp;
	int ret = 0;

	if (ds->ops->resume)
		ret = ds->ops->resume(ds);
@@ -319,11 +319,11 @@ int dsa_switch_resume(struct dsa_switch *ds)
		return ret;

	/* Resume slave network devices */
	for (i = 0; i < ds->num_ports; i++) {
		if (!dsa_is_port_initialized(ds, i))
	dsa_switch_for_each_port(dp, ds) {
		if (!dsa_port_is_initialized(dp))
			continue;

		ret = dsa_slave_resume(dsa_to_port(ds, i)->slave);
		ret = dsa_slave_resume(dp->slave);
		if (ret)
			return ret;
	}
+6 −7
Original line number Diff line number Diff line
@@ -802,17 +802,16 @@ static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds)
{
	const struct dsa_device_ops *tag_ops = ds->dst->tag_ops;
	struct dsa_switch_tree *dst = ds->dst;
	int port, err;
	struct dsa_port *cpu_dp;
	int err;

	if (tag_ops->proto == dst->default_proto)
		return 0;

	for (port = 0; port < ds->num_ports; port++) {
		if (!dsa_is_cpu_port(ds, port))
			continue;

	dsa_switch_for_each_cpu_port(cpu_dp, ds) {
		rtnl_lock();
		err = ds->ops->change_tag_protocol(ds, port, tag_ops->proto);
		err = ds->ops->change_tag_protocol(ds, cpu_dp->index,
						   tag_ops->proto);
		rtnl_unlock();
		if (err) {
			dev_err(ds->dev, "Unable to use tag protocol \"%s\": %pe\n",
@@ -1150,7 +1149,7 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
		goto out_unlock;

	list_for_each_entry(dp, &dst->ports, list) {
		if (!dsa_is_user_port(dp->ds, dp->index))
		if (!dsa_port_is_user(dp))
			continue;

		if (dp->slave->flags & IFF_UP)
+7 −10
Original line number Diff line number Diff line
@@ -515,7 +515,8 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
					      struct netlink_ext_ack *extack)
{
	struct dsa_switch *ds = dp->ds;
	int err, i;
	struct dsa_port *other_dp;
	int err;

	/* VLAN awareness was off, so the question is "can we turn it on".
	 * We may have had 8021q uppers, those need to go. Make sure we don't
@@ -557,10 +558,10 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
	 * different ports of the same switch device and one of them has a
	 * different setting than what is being requested.
	 */
	for (i = 0; i < ds->num_ports; i++) {
	dsa_switch_for_each_port(other_dp, ds) {
		struct net_device *other_bridge;

		other_bridge = dsa_to_port(ds, i)->bridge_dev;
		other_bridge = other_dp->bridge_dev;
		if (!other_bridge)
			continue;
		/* If it's the same bridge, it also has same
@@ -607,20 +608,16 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
		return err;

	if (ds->vlan_filtering_is_global) {
		int port;
		struct dsa_port *other_dp;

		ds->vlan_filtering = vlan_filtering;

		for (port = 0; port < ds->num_ports; port++) {
			struct net_device *slave;

			if (!dsa_is_user_port(ds, port))
				continue;
		dsa_switch_for_each_user_port(other_dp, ds) {
			struct net_device *slave = dp->slave;

			/* We might be called in the unbind path, so not
			 * all slave devices might still be registered.
			 */
			slave = dsa_to_port(ds, port)->slave;
			if (!slave)
				continue;

+1 −1
Original line number Diff line number Diff line
@@ -2368,7 +2368,7 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
		dst = cpu_dp->ds->dst;

		list_for_each_entry(dp, &dst->ports, list) {
			if (!dsa_is_user_port(dp->ds, dp->index))
			if (!dsa_port_is_user(dp))
				continue;

			list_add(&dp->slave->close_list, &close_list);
Loading