Merge branch 'dsa_to_port-loops'

Vladimir Oltean says:

====================
Remove the "dsa_to_port in a loop" antipattern

v1->v2: more patches
v2->v3: less patches

As opposed to previous series, I would now like to first refactor the
DSA core, since that sees fewer patches than drivers, and make the
helpers available. Since the refactoring is fairly noisy, I don't want
to force it on driver maintainers right away, patches can be submitted
independently.

The original cover letter is below:

The DSA core and drivers currently iterate too much through the port
list of a switch. For example, this snippet:

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

		ds->ops->change_tag_protocol(ds, port, tag_ops->proto);
	}

iterates through ds->num_ports once, and then calls dsa_is_cpu_port to
filter out the other types of ports. But that function has a hidden call
to dsa_to_port() in it, which contains:

	list_for_each_entry(dp, &dst->ports, list)
		if (dp->ds == ds && dp->index == p)
			return dp;

where the only thing we wanted to know in the first place was whether
dp->type == DSA_PORT_TYPE_CPU or not.

So it seems that the problem is that we are not iterating with the right
variable. We have an "int port" but in fact need a "struct dsa_port *dp".

This has started being an issue since this patch series:
https://patchwork.ozlabs.org/project/netdev/cover/20191020031941.3805884-1-vivien.didelot@gmail.com/

The currently proposed set of changes iterates like this:

	dsa_switch_for_each_cpu_port(cpu_dp, ds)
		err = ds->ops->change_tag_protocol(ds, cpu_dp->index,
						   tag_ops->proto);

which iterates directly over ds->dst->ports, which is a list of struct
dsa_port *dp. This makes it much easier and more efficient to check
dp->type.

As a nice side effect, with the proposed driver API, driver writers are
now encouraged to use more efficient patterns, and not only due to less
iterations through the port list. For example, something like this:

	for (port = 0; port < ds->num_ports; port++)
		do_something();

probably does not need to do_something() for the ports that are disabled
in the device tree. But adding extra code for that would look like this:

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

		do_something();
	}

and therefore, it is understandable that some driver writers may decide
to not bother. This patch series introduces a "dsa_switch_for_each_available_port"
macro which comes at no extra cost in terms of lines of code / number of
braces to the driver writer, but it has the "dsa_is_unused_port" check
embedded within it.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2021-10-21 12:44:07 +01:00
commit ce2729731a
11 changed files with 224 additions and 214 deletions

View File

@ -394,7 +394,8 @@ static int sja1105_init_virtual_links(struct sja1105_private *priv,
vl_lookup[k].vlanid = rule->key.vl.vid;
vl_lookup[k].vlanprior = rule->key.vl.pcp;
} else {
u16 vid = dsa_8021q_rx_vid(priv->ds, port);
struct dsa_port *dp = dsa_to_port(priv->ds, port);
u16 vid = dsa_tag_8021q_rx_vid(dp);
vl_lookup[k].vlanid = vid;
vl_lookup[k].vlanprior = 0;

View File

@ -9,6 +9,7 @@
#include <linux/types.h>
struct dsa_switch;
struct dsa_port;
struct sk_buff;
struct net_device;
@ -45,9 +46,9 @@ void dsa_tag_8021q_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port,
u16 dsa_8021q_bridge_tx_fwd_offload_vid(int bridge_num);
u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port);
u16 dsa_tag_8021q_tx_vid(const struct dsa_port *dp);
u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port);
u16 dsa_tag_8021q_rx_vid(const struct dsa_port *dp);
int dsa_8021q_rx_switch_id(u16 vid);

View File

@ -474,14 +474,41 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p)
return dsa_to_port(ds, p)->type == DSA_PORT_TYPE_USER;
}
#define dsa_tree_for_each_user_port(_dp, _dst) \
list_for_each_entry((_dp), &(_dst)->ports, list) \
if (dsa_port_is_user((_dp)))
#define dsa_switch_for_each_port(_dp, _ds) \
list_for_each_entry((_dp), &(_ds)->dst->ports, list) \
if ((_dp)->ds == (_ds))
#define dsa_switch_for_each_port_safe(_dp, _next, _ds) \
list_for_each_entry_safe((_dp), (_next), &(_ds)->dst->ports, list) \
if ((_dp)->ds == (_ds))
#define dsa_switch_for_each_port_continue_reverse(_dp, _ds) \
list_for_each_entry_continue_reverse((_dp), &(_ds)->dst->ports, list) \
if ((_dp)->ds == (_ds))
#define dsa_switch_for_each_available_port(_dp, _ds) \
dsa_switch_for_each_port((_dp), (_ds)) \
if (!dsa_port_is_unused((_dp)))
#define dsa_switch_for_each_user_port(_dp, _ds) \
dsa_switch_for_each_port((_dp), (_ds)) \
if (dsa_port_is_user((_dp)))
#define dsa_switch_for_each_cpu_port(_dp, _ds) \
dsa_switch_for_each_port((_dp), (_ds)) \
if (dsa_port_is_cpu((_dp)))
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;
}

View File

@ -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;
}

View File

@ -399,11 +399,8 @@ static int dsa_tree_setup_cpu_ports(struct dsa_switch_tree *dst)
if (!dsa_port_is_cpu(cpu_dp))
continue;
list_for_each_entry(dp, &dst->ports, list) {
/* Prefer a local CPU port */
if (dp->ds != cpu_dp->ds)
continue;
/* Prefer a local CPU port */
dsa_switch_for_each_port(dp, cpu_dp->ds) {
/* Prefer the first local CPU port found */
if (dp->cpu_dp)
continue;
@ -802,17 +799,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",
@ -853,12 +849,10 @@ static int dsa_switch_setup(struct dsa_switch *ds)
/* Setup devlink port instances now, so that the switch
* setup() can register regions etc, against the ports
*/
list_for_each_entry(dp, &ds->dst->ports, list) {
if (dp->ds == ds) {
err = dsa_port_devlink_setup(dp);
if (err)
goto unregister_devlink_ports;
}
dsa_switch_for_each_port(dp, ds) {
err = dsa_port_devlink_setup(dp);
if (err)
goto unregister_devlink_ports;
}
err = dsa_switch_register_notifier(ds);
@ -902,9 +896,8 @@ teardown:
unregister_notifier:
dsa_switch_unregister_notifier(ds);
unregister_devlink_ports:
list_for_each_entry(dp, &ds->dst->ports, list)
if (dp->ds == ds)
dsa_port_devlink_teardown(dp);
dsa_switch_for_each_port(dp, ds)
dsa_port_devlink_teardown(dp);
devlink_free(ds->devlink);
ds->devlink = NULL;
return err;
@ -932,9 +925,8 @@ static void dsa_switch_teardown(struct dsa_switch *ds)
dsa_switch_unregister_notifier(ds);
if (ds->devlink) {
list_for_each_entry(dp, &ds->dst->ports, list)
if (dp->ds == ds)
dsa_port_devlink_teardown(dp);
dsa_switch_for_each_port(dp, ds)
dsa_port_devlink_teardown(dp);
devlink_free(ds->devlink);
ds->devlink = NULL;
}
@ -1150,7 +1142,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)
@ -1181,8 +1173,8 @@ static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index)
struct dsa_switch_tree *dst = ds->dst;
struct dsa_port *dp;
list_for_each_entry(dp, &dst->ports, list)
if (dp->ds == ds && dp->index == index)
dsa_switch_for_each_port(dp, ds)
if (dp->index == index)
return dp;
dp = kzalloc(sizeof(*dp), GFP_KERNEL);
@ -1523,12 +1515,9 @@ static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd)
static void dsa_switch_release_ports(struct dsa_switch *ds)
{
struct dsa_switch_tree *dst = ds->dst;
struct dsa_port *dp, *next;
list_for_each_entry_safe(dp, next, &dst->ports, list) {
if (dp->ds != ds)
continue;
dsa_switch_for_each_port_safe(dp, next, ds) {
list_del(&dp->list);
kfree(dp);
}
@ -1620,13 +1609,7 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
mutex_lock(&dsa2_mutex);
rtnl_lock();
list_for_each_entry(dp, &ds->dst->ports, list) {
if (dp->ds != ds)
continue;
if (!dsa_port_is_user(dp))
continue;
dsa_switch_for_each_user_port(dp, ds) {
master = dp->cpu_dp->master;
slave_dev = dp->slave;

View File

@ -515,14 +515,15 @@ 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
* enter an inconsistent state: deny changing the VLAN awareness state
* as long as we have 8021q uppers.
*/
if (vlan_filtering && dsa_is_user_port(ds, dp->index)) {
if (vlan_filtering && dsa_port_is_user(dp)) {
struct net_device *upper_dev, *slave = dp->slave;
struct net_device *br = dp->bridge_dev;
struct list_head *iter;
@ -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;
@ -1041,7 +1038,7 @@ static void dsa_port_phylink_mac_link_down(struct phylink_config *config,
struct phy_device *phydev = NULL;
struct dsa_switch *ds = dp->ds;
if (dsa_is_user_port(ds, dp->index))
if (dsa_port_is_user(dp))
phydev = dp->slave->phydev;
if (!ds->ops->phylink_mac_link_down) {

View File

@ -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);

View File

@ -17,14 +17,11 @@
static unsigned int dsa_switch_fastest_ageing_time(struct dsa_switch *ds,
unsigned int ageing_time)
{
int i;
for (i = 0; i < ds->num_ports; ++i) {
struct dsa_port *dp = dsa_to_port(ds, i);
struct dsa_port *dp;
dsa_switch_for_each_port(dp, ds)
if (dp->ageing_time && dp->ageing_time < ageing_time)
ageing_time = dp->ageing_time;
}
return ageing_time;
}
@ -49,10 +46,10 @@ static int dsa_switch_ageing_time(struct dsa_switch *ds,
return 0;
}
static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
struct dsa_notifier_mtu_info *info)
static bool dsa_port_mtu_match(struct dsa_port *dp,
struct dsa_notifier_mtu_info *info)
{
if (ds->index == info->sw_index && port == info->port)
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
@ -61,7 +58,7 @@ static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
if (info->targeted_match)
return false;
if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
if (dsa_port_is_dsa(dp) || dsa_port_is_cpu(dp))
return true;
return false;
@ -70,14 +67,16 @@ static bool dsa_switch_mtu_match(struct dsa_switch *ds, int port,
static int dsa_switch_mtu(struct dsa_switch *ds,
struct dsa_notifier_mtu_info *info)
{
int port, ret;
struct dsa_port *dp;
int ret;
if (!ds->ops->port_change_mtu)
return -EOPNOTSUPP;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_mtu_match(ds, port, info)) {
ret = ds->ops->port_change_mtu(ds, port, info->mtu);
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_mtu_match(dp, info)) {
ret = ds->ops->port_change_mtu(ds, dp->index,
info->mtu);
if (ret)
return ret;
}
@ -120,7 +119,8 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
struct netlink_ext_ack extack = {0};
bool change_vlan_filtering = false;
bool vlan_filtering;
int err, port;
struct dsa_port *dp;
int err;
if (dst->index == info->tree_index && ds->index == info->sw_index &&
ds->ops->port_bridge_leave)
@ -150,10 +150,10 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
* VLAN-aware bridge.
*/
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;
bridge_dev = dsa_to_port(ds, port)->bridge_dev;
bridge_dev = dp->bridge_dev;
if (bridge_dev && br_vlan_enabled(bridge_dev)) {
change_vlan_filtering = false;
@ -179,19 +179,19 @@ static int dsa_switch_bridge_leave(struct dsa_switch *ds,
* DSA links) that sit between the targeted port on which the notifier was
* emitted and its dedicated CPU port.
*/
static bool dsa_switch_host_address_match(struct dsa_switch *ds, int port,
int info_sw_index, int info_port)
static bool dsa_port_host_address_match(struct dsa_port *dp,
int info_sw_index, int info_port)
{
struct dsa_port *targeted_dp, *cpu_dp;
struct dsa_switch *targeted_ds;
targeted_ds = dsa_switch_find(ds->dst->index, info_sw_index);
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(ds, targeted_ds))
return port == dsa_towards_port(ds, cpu_dp->ds->index,
cpu_dp->index);
if (dsa_switch_is_upstream_of(dp->ds, targeted_ds))
return dp->index == dsa_towards_port(dp->ds, cpu_dp->ds->index,
cpu_dp->index);
return false;
}
@ -209,11 +209,12 @@ static struct dsa_mac_addr *dsa_mac_addr_find(struct list_head *addr_list,
return NULL;
}
static int dsa_switch_do_mdb_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
static int dsa_port_do_mdb_add(struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb)
{
struct dsa_port *dp = dsa_to_port(ds, port);
struct dsa_switch *ds = dp->ds;
struct dsa_mac_addr *a;
int port = dp->index;
int err;
/* No need to bother with refcounting for user ports */
@ -244,11 +245,12 @@ static int dsa_switch_do_mdb_add(struct dsa_switch *ds, int port,
return 0;
}
static int dsa_switch_do_mdb_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb)
static int dsa_port_do_mdb_del(struct dsa_port *dp,
const struct switchdev_obj_port_mdb *mdb)
{
struct dsa_port *dp = dsa_to_port(ds, port);
struct dsa_switch *ds = dp->ds;
struct dsa_mac_addr *a;
int port = dp->index;
int err;
/* No need to bother with refcounting for user ports */
@ -274,11 +276,12 @@ static int dsa_switch_do_mdb_del(struct dsa_switch *ds, int port,
return 0;
}
static int dsa_switch_do_fdb_add(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
static int dsa_port_do_fdb_add(struct dsa_port *dp, const unsigned char *addr,
u16 vid)
{
struct dsa_port *dp = dsa_to_port(ds, port);
struct dsa_switch *ds = dp->ds;
struct dsa_mac_addr *a;
int port = dp->index;
int err;
/* No need to bother with refcounting for user ports */
@ -309,11 +312,12 @@ static int dsa_switch_do_fdb_add(struct dsa_switch *ds, int port,
return 0;
}
static int dsa_switch_do_fdb_del(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid)
static int dsa_port_do_fdb_del(struct dsa_port *dp, const unsigned char *addr,
u16 vid)
{
struct dsa_port *dp = dsa_to_port(ds, port);
struct dsa_switch *ds = dp->ds;
struct dsa_mac_addr *a;
int port = dp->index;
int err;
/* No need to bother with refcounting for user ports */
@ -342,17 +346,16 @@ static int dsa_switch_do_fdb_del(struct dsa_switch *ds, int port,
static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
struct dsa_notifier_fdb_info *info)
{
struct dsa_port *dp;
int err = 0;
int port;
if (!ds->ops->port_fdb_add)
return -EOPNOTSUPP;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_host_address_match(ds, port, info->sw_index,
info->port)) {
err = dsa_switch_do_fdb_add(ds, port, info->addr,
info->vid);
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_host_address_match(dp, info->sw_index,
info->port)) {
err = dsa_port_do_fdb_add(dp, info->addr, info->vid);
if (err)
break;
}
@ -364,17 +367,16 @@ static int dsa_switch_host_fdb_add(struct dsa_switch *ds,
static int dsa_switch_host_fdb_del(struct dsa_switch *ds,
struct dsa_notifier_fdb_info *info)
{
struct dsa_port *dp;
int err = 0;
int port;
if (!ds->ops->port_fdb_del)
return -EOPNOTSUPP;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_host_address_match(ds, port, info->sw_index,
info->port)) {
err = dsa_switch_do_fdb_del(ds, port, info->addr,
info->vid);
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_host_address_match(dp, info->sw_index,
info->port)) {
err = dsa_port_do_fdb_del(dp, info->addr, info->vid);
if (err)
break;
}
@ -387,22 +389,24 @@ 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);
struct dsa_port *dp = dsa_to_port(ds, port);
if (!ds->ops->port_fdb_add)
return -EOPNOTSUPP;
return dsa_switch_do_fdb_add(ds, port, info->addr, info->vid);
return dsa_port_do_fdb_add(dp, info->addr, info->vid);
}
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);
struct dsa_port *dp = dsa_to_port(ds, port);
if (!ds->ops->port_fdb_del)
return -EOPNOTSUPP;
return dsa_switch_do_fdb_del(ds, port, info->addr, info->vid);
return dsa_port_do_fdb_del(dp, info->addr, info->vid);
}
static int dsa_switch_hsr_join(struct dsa_switch *ds,
@ -468,37 +472,39 @@ 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);
struct dsa_port *dp = dsa_to_port(ds, port);
if (!ds->ops->port_mdb_add)
return -EOPNOTSUPP;
return dsa_switch_do_mdb_add(ds, port, info->mdb);
return dsa_port_do_mdb_add(dp, info->mdb);
}
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);
struct dsa_port *dp = dsa_to_port(ds, port);
if (!ds->ops->port_mdb_del)
return -EOPNOTSUPP;
return dsa_switch_do_mdb_del(ds, port, info->mdb);
return dsa_port_do_mdb_del(dp, info->mdb);
}
static int dsa_switch_host_mdb_add(struct dsa_switch *ds,
struct dsa_notifier_mdb_info *info)
{
struct dsa_port *dp;
int err = 0;
int port;
if (!ds->ops->port_mdb_add)
return -EOPNOTSUPP;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_host_address_match(ds, port, info->sw_index,
info->port)) {
err = dsa_switch_do_mdb_add(ds, port, info->mdb);
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_host_address_match(dp, info->sw_index,
info->port)) {
err = dsa_port_do_mdb_add(dp, info->mdb);
if (err)
break;
}
@ -510,16 +516,16 @@ static int dsa_switch_host_mdb_add(struct dsa_switch *ds,
static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
struct dsa_notifier_mdb_info *info)
{
struct dsa_port *dp;
int err = 0;
int port;
if (!ds->ops->port_mdb_del)
return -EOPNOTSUPP;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_host_address_match(ds, port, info->sw_index,
info->port)) {
err = dsa_switch_do_mdb_del(ds, port, info->mdb);
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_host_address_match(dp, info->sw_index,
info->port)) {
err = dsa_port_do_mdb_del(dp, info->mdb);
if (err)
break;
}
@ -528,13 +534,13 @@ static int dsa_switch_host_mdb_del(struct dsa_switch *ds,
return err;
}
static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port,
struct dsa_notifier_vlan_info *info)
static bool dsa_port_vlan_match(struct dsa_port *dp,
struct dsa_notifier_vlan_info *info)
{
if (ds->index == info->sw_index && port == info->port)
if (dp->ds->index == info->sw_index && dp->index == info->port)
return true;
if (dsa_is_dsa_port(ds, port))
if (dsa_port_is_dsa(dp))
return true;
return false;
@ -543,14 +549,15 @@ static bool dsa_switch_vlan_match(struct dsa_switch *ds, int port,
static int dsa_switch_vlan_add(struct dsa_switch *ds,
struct dsa_notifier_vlan_info *info)
{
int port, err;
struct dsa_port *dp;
int err;
if (!ds->ops->port_vlan_add)
return -EOPNOTSUPP;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_vlan_match(ds, port, info)) {
err = ds->ops->port_vlan_add(ds, port, info->vlan,
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_vlan_match(dp, info)) {
err = ds->ops->port_vlan_add(ds, dp->index, info->vlan,
info->extack);
if (err)
return err;
@ -579,38 +586,34 @@ static int dsa_switch_change_tag_proto(struct dsa_switch *ds,
struct dsa_notifier_tag_proto_info *info)
{
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)
return -EOPNOTSUPP;
ASSERT_RTNL();
for (port = 0; port < ds->num_ports; port++) {
if (!dsa_is_cpu_port(ds, port))
continue;
err = ds->ops->change_tag_protocol(ds, port, tag_ops->proto);
dsa_switch_for_each_cpu_port(cpu_dp, ds) {
err = ds->ops->change_tag_protocol(ds, cpu_dp->index,
tag_ops->proto);
if (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
* the remaining bits which are "duplicated for faster access", and the
* bits that depend on the tagger, such as the MTU.
*/
for (port = 0; port < ds->num_ports; port++) {
if (dsa_is_user_port(ds, port)) {
struct net_device *slave;
dsa_switch_for_each_user_port(dp, ds) {
struct net_device *slave = dp->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 */
dsa_slave_change_mtu(slave, slave->mtu);
}
/* rtnl_mutex is held in dsa_tree_change_tag_proto */
dsa_slave_change_mtu(slave, slave->mtu);
}
return 0;

View File

@ -77,22 +77,22 @@ EXPORT_SYMBOL_GPL(dsa_8021q_bridge_tx_fwd_offload_vid);
/* Returns the VID to be inserted into the frame from xmit for switch steering
* instructions on egress. Encodes switch ID and port ID.
*/
u16 dsa_8021q_tx_vid(struct dsa_switch *ds, int port)
u16 dsa_tag_8021q_tx_vid(const struct dsa_port *dp)
{
return DSA_8021Q_DIR_TX | DSA_8021Q_SWITCH_ID(ds->index) |
DSA_8021Q_PORT(port);
return DSA_8021Q_DIR_TX | DSA_8021Q_SWITCH_ID(dp->ds->index) |
DSA_8021Q_PORT(dp->index);
}
EXPORT_SYMBOL_GPL(dsa_8021q_tx_vid);
EXPORT_SYMBOL_GPL(dsa_tag_8021q_tx_vid);
/* Returns the VID that will be installed as pvid for this switch port, sent as
* tagged egress towards the CPU port and decoded by the rcv function.
*/
u16 dsa_8021q_rx_vid(struct dsa_switch *ds, int port)
u16 dsa_tag_8021q_rx_vid(const struct dsa_port *dp)
{
return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(ds->index) |
DSA_8021Q_PORT(port);
return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(dp->ds->index) |
DSA_8021Q_PORT(dp->index);
}
EXPORT_SYMBOL_GPL(dsa_8021q_rx_vid);
EXPORT_SYMBOL_GPL(dsa_tag_8021q_rx_vid);
/* Returns the decoded switch ID from the RX VID. */
int dsa_8021q_rx_switch_id(u16 vid)
@ -138,12 +138,13 @@ dsa_tag_8021q_vlan_find(struct dsa_8021q_context *ctx, int port, u16 vid)
return NULL;
}
static int dsa_switch_do_tag_8021q_vlan_add(struct dsa_switch *ds, int port,
u16 vid, u16 flags)
static int dsa_port_do_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid,
u16 flags)
{
struct dsa_8021q_context *ctx = ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port);
struct dsa_8021q_context *ctx = dp->ds->tag_8021q_ctx;
struct dsa_switch *ds = dp->ds;
struct dsa_tag_8021q_vlan *v;
int port = dp->index;
int err;
/* No need to bother with refcounting for user ports */
@ -174,12 +175,12 @@ static int dsa_switch_do_tag_8021q_vlan_add(struct dsa_switch *ds, int port,
return 0;
}
static int dsa_switch_do_tag_8021q_vlan_del(struct dsa_switch *ds, int port,
u16 vid)
static int dsa_port_do_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid)
{
struct dsa_8021q_context *ctx = ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port);
struct dsa_8021q_context *ctx = dp->ds->tag_8021q_ctx;
struct dsa_switch *ds = dp->ds;
struct dsa_tag_8021q_vlan *v;
int port = dp->index;
int err;
/* No need to bother with refcounting for user ports */
@ -206,14 +207,16 @@ static int dsa_switch_do_tag_8021q_vlan_del(struct dsa_switch *ds, int port,
}
static bool
dsa_switch_tag_8021q_vlan_match(struct dsa_switch *ds, int port,
struct dsa_notifier_tag_8021q_vlan_info *info)
dsa_port_tag_8021q_vlan_match(struct dsa_port *dp,
struct dsa_notifier_tag_8021q_vlan_info *info)
{
if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
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 port == info->port;
return dp->index == info->port;
return false;
}
@ -221,7 +224,8 @@ dsa_switch_tag_8021q_vlan_match(struct dsa_switch *ds, int port,
int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
struct dsa_notifier_tag_8021q_vlan_info *info)
{
int port, err;
struct dsa_port *dp;
int err;
/* Since we use dsa_broadcast(), there might be other switches in other
* trees which don't support tag_8021q, so don't return an error.
@ -231,21 +235,20 @@ int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
if (!ds->ops->tag_8021q_vlan_add || !ds->tag_8021q_ctx)
return 0;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_tag_8021q_vlan_match(ds, port, info)) {
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_tag_8021q_vlan_match(dp, info)) {
u16 flags = 0;
if (dsa_is_user_port(ds, port))
if (dsa_port_is_user(dp))
flags |= BRIDGE_VLAN_INFO_UNTAGGED;
if (vid_is_dsa_8021q_rxvlan(info->vid) &&
dsa_8021q_rx_switch_id(info->vid) == ds->index &&
dsa_8021q_rx_source_port(info->vid) == port)
dsa_8021q_rx_source_port(info->vid) == dp->index)
flags |= BRIDGE_VLAN_INFO_PVID;
err = dsa_switch_do_tag_8021q_vlan_add(ds, port,
info->vid,
flags);
err = dsa_port_do_tag_8021q_vlan_add(dp, info->vid,
flags);
if (err)
return err;
}
@ -257,15 +260,15 @@ int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
int dsa_switch_tag_8021q_vlan_del(struct dsa_switch *ds,
struct dsa_notifier_tag_8021q_vlan_info *info)
{
int port, err;
struct dsa_port *dp;
int err;
if (!ds->ops->tag_8021q_vlan_del || !ds->tag_8021q_ctx)
return 0;
for (port = 0; port < ds->num_ports; port++) {
if (dsa_switch_tag_8021q_vlan_match(ds, port, info)) {
err = dsa_switch_do_tag_8021q_vlan_del(ds, port,
info->vid);
dsa_switch_for_each_port(dp, ds) {
if (dsa_port_tag_8021q_vlan_match(dp, info)) {
err = dsa_port_do_tag_8021q_vlan_del(dp, info->vid);
if (err)
return err;
}
@ -321,15 +324,14 @@ int dsa_switch_tag_8021q_vlan_del(struct dsa_switch *ds,
* +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+
* swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3
*/
static bool dsa_tag_8021q_bridge_match(struct dsa_switch *ds, int port,
struct dsa_notifier_bridge_info *info)
static bool
dsa_port_tag_8021q_bridge_match(struct dsa_port *dp,
struct dsa_notifier_bridge_info *info)
{
struct dsa_port *dp = dsa_to_port(ds, port);
/* Don't match on self */
if (ds->dst->index == info->tree_index &&
ds->index == info->sw_index &&
port == info->port)
if (dp->ds->dst->index == info->tree_index &&
dp->ds->index == info->sw_index &&
dp->index == info->port)
return false;
if (dsa_port_is_user(dp))
@ -343,21 +345,21 @@ int dsa_tag_8021q_bridge_join(struct dsa_switch *ds,
{
struct dsa_switch *targeted_ds;
struct dsa_port *targeted_dp;
struct dsa_port *dp;
u16 targeted_rx_vid;
int err, port;
int err;
if (!ds->tag_8021q_ctx)
return 0;
targeted_ds = dsa_switch_find(info->tree_index, info->sw_index);
targeted_dp = dsa_to_port(targeted_ds, info->port);
targeted_rx_vid = dsa_8021q_rx_vid(targeted_ds, info->port);
targeted_rx_vid = dsa_tag_8021q_rx_vid(targeted_dp);
for (port = 0; port < ds->num_ports; port++) {
struct dsa_port *dp = dsa_to_port(ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ds, port);
dsa_switch_for_each_port(dp, ds) {
u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
if (!dsa_tag_8021q_bridge_match(ds, port, info))
if (!dsa_port_tag_8021q_bridge_match(dp, info))
continue;
/* Install the RX VID of the targeted port in our VLAN table */
@ -379,21 +381,20 @@ int dsa_tag_8021q_bridge_leave(struct dsa_switch *ds,
{
struct dsa_switch *targeted_ds;
struct dsa_port *targeted_dp;
struct dsa_port *dp;
u16 targeted_rx_vid;
int port;
if (!ds->tag_8021q_ctx)
return 0;
targeted_ds = dsa_switch_find(info->tree_index, info->sw_index);
targeted_dp = dsa_to_port(targeted_ds, info->port);
targeted_rx_vid = dsa_8021q_rx_vid(targeted_ds, info->port);
targeted_rx_vid = dsa_tag_8021q_rx_vid(targeted_dp);
for (port = 0; port < ds->num_ports; port++) {
struct dsa_port *dp = dsa_to_port(ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ds, port);
dsa_switch_for_each_port(dp, ds) {
u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
if (!dsa_tag_8021q_bridge_match(ds, port, info))
if (!dsa_port_tag_8021q_bridge_match(dp, info))
continue;
/* Remove the RX VID of the targeted port from our VLAN table */
@ -432,8 +433,8 @@ static int dsa_tag_8021q_port_setup(struct dsa_switch *ds, int port)
{
struct dsa_8021q_context *ctx = ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ds, port);
u16 tx_vid = dsa_8021q_tx_vid(ds, port);
u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
struct net_device *master;
int err;
@ -477,8 +478,8 @@ static void dsa_tag_8021q_port_teardown(struct dsa_switch *ds, int port)
{
struct dsa_8021q_context *ctx = ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ds, port);
u16 tx_vid = dsa_8021q_tx_vid(ds, port);
u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
struct net_device *master;
/* The CPU port is implicitly configured by

View File

@ -39,9 +39,9 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
struct ethhdr *hdr = eth_hdr(skb);
if (ocelot_ptp_rew_op(skb) || is_link_local_ether_addr(hdr->h_dest))

View File

@ -158,10 +158,7 @@ static u16 sja1105_xmit_tpid(struct dsa_port *dp)
* we're sure about that). It may not be on this port though, so we
* need to find it.
*/
list_for_each_entry(other_dp, &ds->dst->ports, list) {
if (other_dp->ds != ds)
continue;
dsa_switch_for_each_port(other_dp, ds) {
if (!other_dp->bridge_dev)
continue;
@ -238,9 +235,9 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
struct net_device *netdev)
{
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
if (skb->offload_fwd_mark)
return sja1105_imprecise_xmit(skb, netdev);
@ -266,9 +263,9 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb,
{
struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone;
struct dsa_port *dp = dsa_slave_to_port(netdev);
u16 tx_vid = dsa_8021q_tx_vid(dp->ds, dp->index);
u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
__be32 *tx_trailer;
__be16 *tx_header;
int trailer_pos;