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

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
...@@ -504,12 +504,11 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p) ...@@ -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) static inline u32 dsa_user_ports(struct dsa_switch *ds)
{ {
struct dsa_port *dp;
u32 mask = 0; u32 mask = 0;
int p;
for (p = 0; p < ds->num_ports; p++) dsa_switch_for_each_user_port(dp, ds)
if (dsa_is_user_port(ds, p)) mask |= BIT(dp->index);
mask |= BIT(p);
return mask; return mask;
} }
......
...@@ -280,23 +280,22 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -280,23 +280,22 @@ static int dsa_switch_rcv(struct sk_buff *skb, struct net_device *dev,
} }
#ifdef CONFIG_PM_SLEEP #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; return dp->type == DSA_PORT_TYPE_USER && dp->slave;
} }
int dsa_switch_suspend(struct dsa_switch *ds) int dsa_switch_suspend(struct dsa_switch *ds)
{ {
int i, ret = 0; struct dsa_port *dp;
int ret = 0;
/* Suspend slave network devices */ /* Suspend slave network devices */
for (i = 0; i < ds->num_ports; i++) { dsa_switch_for_each_port(dp, ds) {
if (!dsa_is_port_initialized(ds, i)) if (!dsa_port_is_initialized(dp))
continue; continue;
ret = dsa_slave_suspend(dsa_to_port(ds, i)->slave); ret = dsa_slave_suspend(dp->slave);
if (ret) if (ret)
return ret; return ret;
} }
...@@ -310,7 +309,8 @@ EXPORT_SYMBOL_GPL(dsa_switch_suspend); ...@@ -310,7 +309,8 @@ EXPORT_SYMBOL_GPL(dsa_switch_suspend);
int dsa_switch_resume(struct dsa_switch *ds) int dsa_switch_resume(struct dsa_switch *ds)
{ {
int i, ret = 0; struct dsa_port *dp;
int ret = 0;
if (ds->ops->resume) if (ds->ops->resume)
ret = ds->ops->resume(ds); ret = ds->ops->resume(ds);
...@@ -319,11 +319,11 @@ int dsa_switch_resume(struct dsa_switch *ds) ...@@ -319,11 +319,11 @@ int dsa_switch_resume(struct dsa_switch *ds)
return ret; return ret;
/* Resume slave network devices */ /* Resume slave network devices */
for (i = 0; i < ds->num_ports; i++) { dsa_switch_for_each_port(dp, ds) {
if (!dsa_is_port_initialized(ds, i)) if (!dsa_port_is_initialized(dp))
continue; continue;
ret = dsa_slave_resume(dsa_to_port(ds, i)->slave); ret = dsa_slave_resume(dp->slave);
if (ret) if (ret)
return ret; return ret;
} }
......
...@@ -802,17 +802,16 @@ static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds) ...@@ -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; const struct dsa_device_ops *tag_ops = ds->dst->tag_ops;
struct dsa_switch_tree *dst = ds->dst; struct dsa_switch_tree *dst = ds->dst;
int port, err; struct dsa_port *cpu_dp;
int err;
if (tag_ops->proto == dst->default_proto) if (tag_ops->proto == dst->default_proto)
return 0; return 0;
for (port = 0; port < ds->num_ports; port++) { dsa_switch_for_each_cpu_port(cpu_dp, ds) {
if (!dsa_is_cpu_port(ds, port))
continue;
rtnl_lock(); 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(); rtnl_unlock();
if (err) { if (err) {
dev_err(ds->dev, "Unable to use tag protocol \"%s\": %pe\n", 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, ...@@ -1150,7 +1149,7 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
goto out_unlock; goto out_unlock;
list_for_each_entry(dp, &dst->ports, list) { list_for_each_entry(dp, &dst->ports, list) {
if (!dsa_is_user_port(dp->ds, dp->index)) if (!dsa_port_is_user(dp))
continue; continue;
if (dp->slave->flags & IFF_UP) if (dp->slave->flags & IFF_UP)
......
...@@ -515,7 +515,8 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp, ...@@ -515,7 +515,8 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp,
struct netlink_ext_ack *extack) struct netlink_ext_ack *extack)
{ {
struct dsa_switch *ds = dp->ds; 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". /* 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 * 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, ...@@ -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 ports of the same switch device and one of them has a
* different setting than what is being requested. * 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; struct net_device *other_bridge;
other_bridge = dsa_to_port(ds, i)->bridge_dev; other_bridge = other_dp->bridge_dev;
if (!other_bridge) if (!other_bridge)
continue; continue;
/* If it's the same bridge, it also has same /* 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, ...@@ -607,20 +608,16 @@ int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
return err; return err;
if (ds->vlan_filtering_is_global) { if (ds->vlan_filtering_is_global) {
int port; struct dsa_port *other_dp;
ds->vlan_filtering = vlan_filtering; ds->vlan_filtering = vlan_filtering;
for (port = 0; port < ds->num_ports; port++) { dsa_switch_for_each_user_port(other_dp, ds) {
struct net_device *slave; struct net_device *slave = dp->slave;
if (!dsa_is_user_port(ds, port))
continue;
/* We might be called in the unbind path, so not /* We might be called in the unbind path, so not
* all slave devices might still be registered. * all slave devices might still be registered.
*/ */
slave = dsa_to_port(ds, port)->slave;
if (!slave) if (!slave)
continue; continue;
......
...@@ -2368,7 +2368,7 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb, ...@@ -2368,7 +2368,7 @@ static int dsa_slave_netdevice_event(struct notifier_block *nb,
dst = cpu_dp->ds->dst; dst = cpu_dp->ds->dst;
list_for_each_entry(dp, &dst->ports, list) { list_for_each_entry(dp, &dst->ports, list) {
if (!dsa_is_user_port(dp->ds, dp->index)) if (!dsa_port_is_user(dp))
continue; continue;
list_add(&dp->slave->close_list, &close_list); list_add(&dp->slave->close_list, &close_list);
......
...@@ -17,14 +17,11 @@ ...@@ -17,14 +17,11 @@
static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds, static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds,
unsigned int ageing_time) unsigned int ageing_time)
{ {
int i; struct dsa_port *dp;
for (i = 0; i < ds->num_ports; ++i) {
struct dsa_port *dp = dsa_to_port(ds, i);
dsa_switch_for_each_port(dp, ds)
if (dp->ageing_time && dp->ageing_time < ageing_time) if (dp->ageing_time && dp->ageing_time < ageing_time)
ageing_time = dp->ageing_time; ageing_time = dp->ageing_time;
}
return ageing_time; return ageing_time;
} }
...@@ -120,7 +117,8 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, ...@@ -120,7 +117,8 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
struct netlink_ext_ack extack = {0}; struct netlink_ext_ack extack = {0};
bool change_vlan_filtering = false; bool change_vlan_filtering = false;
bool vlan_filtering; bool vlan_filtering;
int err, port; struct dsa_port *dp;
int err;
if (dst->index == info->tree_index && ds->index == info->sw_index && if (dst->index == info->tree_index && ds->index == info->sw_index &&
ds->ops->port_bridge_leave) ds->ops->port_bridge_leave)
...@@ -150,10 +148,10 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds, ...@@ -150,10 +148,10 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
* VLAN-aware bridge. * VLAN-aware bridge.
*/ */
if (change_vlan_filtering && ds->vlan_filtering_is_global) { if (change_vlan_filtering && ds->vlan_filtering_is_global) {
for (port = 0; port < ds->num_ports; port++) { dsa_switch_for_each_port(dp, ds) {
struct net_device *bridge_dev; struct net_device *bridge_dev;
bridge_dev = dsa_to_port(ds, port)->bridge_dev; bridge_dev = dp->bridge_dev;
if (bridge_dev && br_vlan_enabled(bridge_dev)) { if (bridge_dev && br_vlan_enabled(bridge_dev)) {
change_vlan_filtering = false; change_vlan_filtering = false;
...@@ -579,38 +577,34 @@ static int dsa_switch_change_tag_proto(struct dsa_switch *ds, ...@@ -579,38 +577,34 @@ static int dsa_switch_change_tag_proto(struct dsa_switch *ds,
struct dsa_notifier_tag_proto_info *info) struct dsa_notifier_tag_proto_info *info)
{ {
const struct dsa_device_ops *tag_ops = info->tag_ops; const struct dsa_device_ops *tag_ops = info->tag_ops;
int port, err; struct dsa_port *dp, *cpu_dp;
int err;
if (!ds->ops->change_tag_protocol) if (!ds->ops->change_tag_protocol)
return -EOPNOTSUPP; return -EOPNOTSUPP;
ASSERT_RTNL(); ASSERT_RTNL();
for (port = 0; port < ds->num_ports; port++) { dsa_switch_for_each_cpu_port(cpu_dp, ds) {
if (!dsa_is_cpu_port(ds, port)) err = ds->ops->change_tag_protocol(ds, cpu_dp->index,
continue; tag_ops->proto);
err = ds->ops->change_tag_protocol(ds, port, tag_ops->proto);
if (err) if (err)
return err; return err;
dsa_port_set_tag_protocol(dsa_to_port(ds, port), tag_ops); dsa_port_set_tag_protocol(cpu_dp, tag_ops);
} }
/* Now that changing the tag protocol can no longer fail, let's update /* Now that changing the tag protocol can no longer fail, let's update
* the remaining bits which are "duplicated for faster access", and the * the remaining bits which are "duplicated for faster access", and the
* bits that depend on the tagger, such as the MTU. * bits that depend on the tagger, such as the MTU.
*/ */
for (port = 0; port < ds->num_ports; port++) { dsa_switch_for_each_user_port(dp, ds) {
if (dsa_is_user_port(ds, port)) { struct net_device *slave = dp->slave;
struct net_device *slave;
slave = dsa_to_port(ds, port)->slave; dsa_slave_setup_tagger(slave);
dsa_slave_setup_tagger(slave);
/* rtnl_mutex is held in dsa_tree_change_tag_proto */ /* rtnl_mutex is held in dsa_tree_change_tag_proto */
dsa_slave_change_mtu(slave, slave->mtu); dsa_slave_change_mtu(slave, slave->mtu);
}
} }
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment