Commit ce272973 authored by David S. Miller's avatar David S. Miller

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: default avatarDavid S. Miller <davem@davemloft.net>
parents dedb0809 992e5cc7
...@@ -394,7 +394,8 @@ static int sja1105_init_virtual_links(struct sja1105_private *priv, ...@@ -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].vlanid = rule->key.vl.vid;
vl_lookup[k].vlanprior = rule->key.vl.pcp; vl_lookup[k].vlanprior = rule->key.vl.pcp;
} else { } 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].vlanid = vid;
vl_lookup[k].vlanprior = 0; vl_lookup[k].vlanprior = 0;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include <linux/types.h> #include <linux/types.h>
struct dsa_switch; struct dsa_switch;
struct dsa_port;
struct sk_buff; struct sk_buff;
struct net_device; struct net_device;
...@@ -45,9 +46,9 @@ void dsa_tag_8021q_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port, ...@@ -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_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); int dsa_8021q_rx_switch_id(u16 vid);
......
...@@ -474,14 +474,41 @@ static inline bool dsa_is_user_port(struct dsa_switch *ds, int p) ...@@ -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; 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) 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;
} }
......
...@@ -399,11 +399,8 @@ static int dsa_tree_setup_cpu_ports(struct dsa_switch_tree *dst) ...@@ -399,11 +399,8 @@ static int dsa_tree_setup_cpu_ports(struct dsa_switch_tree *dst)
if (!dsa_port_is_cpu(cpu_dp)) if (!dsa_port_is_cpu(cpu_dp))
continue; continue;
list_for_each_entry(dp, &dst->ports, list) { /* Prefer a local CPU port */
/* Prefer a local CPU port */ dsa_switch_for_each_port(dp, cpu_dp->ds) {
if (dp->ds != cpu_dp->ds)
continue;
/* Prefer the first local CPU port found */ /* Prefer the first local CPU port found */
if (dp->cpu_dp) if (dp->cpu_dp)
continue; continue;
...@@ -802,17 +799,16 @@ static int dsa_switch_setup_tag_protocol(struct dsa_switch *ds) ...@@ -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; 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",
...@@ -853,12 +849,10 @@ static int dsa_switch_setup(struct dsa_switch *ds) ...@@ -853,12 +849,10 @@ static int dsa_switch_setup(struct dsa_switch *ds)
/* Setup devlink port instances now, so that the switch /* Setup devlink port instances now, so that the switch
* setup() can register regions etc, against the ports * setup() can register regions etc, against the ports
*/ */
list_for_each_entry(dp, &ds->dst->ports, list) { dsa_switch_for_each_port(dp, ds) {
if (dp->ds == ds) { err = dsa_port_devlink_setup(dp);
err = dsa_port_devlink_setup(dp); if (err)
if (err) goto unregister_devlink_ports;
goto unregister_devlink_ports;
}
} }
err = dsa_switch_register_notifier(ds); err = dsa_switch_register_notifier(ds);
...@@ -902,9 +896,8 @@ static int dsa_switch_setup(struct dsa_switch *ds) ...@@ -902,9 +896,8 @@ static int dsa_switch_setup(struct dsa_switch *ds)
unregister_notifier: unregister_notifier:
dsa_switch_unregister_notifier(ds); dsa_switch_unregister_notifier(ds);
unregister_devlink_ports: unregister_devlink_ports:
list_for_each_entry(dp, &ds->dst->ports, list) dsa_switch_for_each_port(dp, ds)
if (dp->ds == ds) dsa_port_devlink_teardown(dp);
dsa_port_devlink_teardown(dp);
devlink_free(ds->devlink); devlink_free(ds->devlink);
ds->devlink = NULL; ds->devlink = NULL;
return err; return err;
...@@ -932,9 +925,8 @@ static void dsa_switch_teardown(struct dsa_switch *ds) ...@@ -932,9 +925,8 @@ static void dsa_switch_teardown(struct dsa_switch *ds)
dsa_switch_unregister_notifier(ds); dsa_switch_unregister_notifier(ds);
if (ds->devlink) { if (ds->devlink) {
list_for_each_entry(dp, &ds->dst->ports, list) dsa_switch_for_each_port(dp, ds)
if (dp->ds == ds) dsa_port_devlink_teardown(dp);
dsa_port_devlink_teardown(dp);
devlink_free(ds->devlink); devlink_free(ds->devlink);
ds->devlink = NULL; ds->devlink = NULL;
} }
...@@ -1150,7 +1142,7 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst, ...@@ -1150,7 +1142,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)
...@@ -1181,8 +1173,8 @@ static struct dsa_port *dsa_port_touch(struct dsa_switch *ds, int index) ...@@ -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_switch_tree *dst = ds->dst;
struct dsa_port *dp; struct dsa_port *dp;
list_for_each_entry(dp, &dst->ports, list) dsa_switch_for_each_port(dp, ds)
if (dp->ds == ds && dp->index == index) if (dp->index == index)
return dp; return dp;
dp = kzalloc(sizeof(*dp), GFP_KERNEL); dp = kzalloc(sizeof(*dp), GFP_KERNEL);
...@@ -1523,12 +1515,9 @@ static int dsa_switch_parse(struct dsa_switch *ds, struct dsa_chip_data *cd) ...@@ -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) static void dsa_switch_release_ports(struct dsa_switch *ds)
{ {
struct dsa_switch_tree *dst = ds->dst;
struct dsa_port *dp, *next; struct dsa_port *dp, *next;
list_for_each_entry_safe(dp, next, &dst->ports, list) { dsa_switch_for_each_port_safe(dp, next, ds) {
if (dp->ds != ds)
continue;
list_del(&dp->list); list_del(&dp->list);
kfree(dp); kfree(dp);
} }
...@@ -1620,13 +1609,7 @@ void dsa_switch_shutdown(struct dsa_switch *ds) ...@@ -1620,13 +1609,7 @@ void dsa_switch_shutdown(struct dsa_switch *ds)
mutex_lock(&dsa2_mutex); mutex_lock(&dsa2_mutex);
rtnl_lock(); rtnl_lock();
list_for_each_entry(dp, &ds->dst->ports, list) { dsa_switch_for_each_user_port(dp, ds) {
if (dp->ds != ds)
continue;
if (!dsa_port_is_user(dp))
continue;
master = dp->cpu_dp->master; master = dp->cpu_dp->master;
slave_dev = dp->slave; slave_dev = dp->slave;
......
...@@ -515,14 +515,15 @@ static bool dsa_port_can_apply_vlan_filtering(struct dsa_port *dp, ...@@ -515,14 +515,15 @@ 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
* enter an inconsistent state: deny changing the VLAN awareness state * enter an inconsistent state: deny changing the VLAN awareness state
* as long as we have 8021q uppers. * 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 *upper_dev, *slave = dp->slave;
struct net_device *br = dp->bridge_dev; struct net_device *br = dp->bridge_dev;
struct list_head *iter; struct list_head *iter;
...@@ -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;
...@@ -1041,7 +1038,7 @@ static void dsa_port_phylink_mac_link_down(struct phylink_config *config, ...@@ -1041,7 +1038,7 @@ static void dsa_port_phylink_mac_link_down(struct phylink_config *config,
struct phy_device *phydev = NULL; struct phy_device *phydev = NULL;
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
if (dsa_is_user_port(ds, dp->index)) if (dsa_port_is_user(dp))
phydev = dp->slave->phydev; phydev = dp->slave->phydev;
if (!ds->ops->phylink_mac_link_down) { if (!ds->ops->phylink_mac_link_down) {
......
...@@ -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);
......
This diff is collapsed.
...@@ -77,22 +77,22 @@ EXPORT_SYMBOL_GPL(dsa_8021q_bridge_tx_fwd_offload_vid); ...@@ -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 /* Returns the VID to be inserted into the frame from xmit for switch steering
* instructions on egress. Encodes switch ID and port ID. * 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) | return DSA_8021Q_DIR_TX | DSA_8021Q_SWITCH_ID(dp->ds->index) |
DSA_8021Q_PORT(port); 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 /* 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. * 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) | return DSA_8021Q_DIR_RX | DSA_8021Q_SWITCH_ID(dp->ds->index) |
DSA_8021Q_PORT(port); 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. */ /* Returns the decoded switch ID from the RX VID. */
int dsa_8021q_rx_switch_id(u16 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) ...@@ -138,12 +138,13 @@ dsa_tag_8021q_vlan_find(struct dsa_8021q_context *ctx, int port, u16 vid)
return NULL; return NULL;
} }
static int dsa_switch_do_tag_8021q_vlan_add(struct dsa_switch *ds, int port, static int dsa_port_do_tag_8021q_vlan_add(struct dsa_port *dp, u16 vid,
u16 vid, u16 flags) u16 flags)
{ {
struct dsa_8021q_context *ctx = ds->tag_8021q_ctx; struct dsa_8021q_context *ctx = dp->ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port); struct dsa_switch *ds = dp->ds;
struct dsa_tag_8021q_vlan *v; struct dsa_tag_8021q_vlan *v;
int port = dp->index;
int err; int err;
/* No need to bother with refcounting for user ports */ /* 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, ...@@ -174,12 +175,12 @@ static int dsa_switch_do_tag_8021q_vlan_add(struct dsa_switch *ds, int port,
return 0; return 0;
} }
static int dsa_switch_do_tag_8021q_vlan_del(struct dsa_switch *ds, int port, static int dsa_port_do_tag_8021q_vlan_del(struct dsa_port *dp, u16 vid)
u16 vid)
{ {
struct dsa_8021q_context *ctx = ds->tag_8021q_ctx; struct dsa_8021q_context *ctx = dp->ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port); struct dsa_switch *ds = dp->ds;
struct dsa_tag_8021q_vlan *v; struct dsa_tag_8021q_vlan *v;
int port = dp->index;
int err; int err;
/* No need to bother with refcounting for user ports */ /* 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, ...@@ -206,14 +207,16 @@ static int dsa_switch_do_tag_8021q_vlan_del(struct dsa_switch *ds, int port,
} }
static bool static bool
dsa_switch_tag_8021q_vlan_match(struct dsa_switch *ds, int port, dsa_port_tag_8021q_vlan_match(struct dsa_port *dp,
struct dsa_notifier_tag_8021q_vlan_info *info) 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; return true;
if (ds->dst->index == info->tree_index && ds->index == info->sw_index) if (ds->dst->index == info->tree_index && ds->index == info->sw_index)
return port == info->port; return dp->index == info->port;
return false; return false;
} }
...@@ -221,7 +224,8 @@ dsa_switch_tag_8021q_vlan_match(struct dsa_switch *ds, int port, ...@@ -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, int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds,
struct dsa_notifier_tag_8021q_vlan_info *info) 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 /* 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. * 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, ...@@ -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) if (!ds->ops->tag_8021q_vlan_add || !ds->tag_8021q_ctx)
return 0; return 0;
for (port = 0; port < ds->num_ports; port++) { dsa_switch_for_each_port(dp, ds) {
if (dsa_switch_tag_8021q_vlan_match(ds, port, info)) { if (dsa_port_tag_8021q_vlan_match(dp, info)) {
u16 flags = 0; u16 flags = 0;
if (dsa_is_user_port(ds, port)) if (dsa_port_is_user(dp))
flags |= BRIDGE_VLAN_INFO_UNTAGGED; flags |= BRIDGE_VLAN_INFO_UNTAGGED;
if (vid_is_dsa_8021q_rxvlan(info->vid) && if (vid_is_dsa_8021q_rxvlan(info->vid) &&
dsa_8021q_rx_switch_id(info->vid) == ds->index && 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; flags |= BRIDGE_VLAN_INFO_PVID;
err = dsa_switch_do_tag_8021q_vlan_add(ds, port, err = dsa_port_do_tag_8021q_vlan_add(dp, info->vid,
info->vid, flags);
flags);
if (err) if (err)
return err; return err;
} }
...@@ -257,15 +260,15 @@ int dsa_switch_tag_8021q_vlan_add(struct dsa_switch *ds, ...@@ -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, int dsa_switch_tag_8021q_vlan_del(struct dsa_switch *ds,
struct dsa_notifier_tag_8021q_vlan_info *info) 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) if (!ds->ops->tag_8021q_vlan_del || !ds->tag_8021q_ctx)
return 0; return 0;
for (port = 0; port < ds->num_ports; port++) { dsa_switch_for_each_port(dp, ds) {
if (dsa_switch_tag_8021q_vlan_match(ds, port, info)) { if (dsa_port_tag_8021q_vlan_match(dp, info)) {
err = dsa_switch_do_tag_8021q_vlan_del(ds, port, err = dsa_port_do_tag_8021q_vlan_del(dp, info->vid);
info->vid);
if (err) if (err)
return err; return err;
} }
...@@ -321,15 +324,14 @@ int dsa_switch_tag_8021q_vlan_del(struct dsa_switch *ds, ...@@ -321,15 +324,14 @@ int dsa_switch_tag_8021q_vlan_del(struct dsa_switch *ds,
* +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+ * +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+
* swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3 * swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3
*/ */
static bool dsa_tag_8021q_bridge_match(struct dsa_switch *ds, int port, static bool
struct dsa_notifier_bridge_info *info) 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 */ /* Don't match on self */
if (ds->dst->index == info->tree_index && if (dp->ds->dst->index == info->tree_index &&
ds->index == info->sw_index && dp->ds->index == info->sw_index &&
port == info->port) dp->index == info->port)
return false; return false;
if (dsa_port_is_user(dp)) if (dsa_port_is_user(dp))
...@@ -343,21 +345,21 @@ int dsa_tag_8021q_bridge_join(struct dsa_switch *ds, ...@@ -343,21 +345,21 @@ int dsa_tag_8021q_bridge_join(struct dsa_switch *ds,
{ {
struct dsa_switch *targeted_ds; struct dsa_switch *targeted_ds;
struct dsa_port *targeted_dp; struct dsa_port *targeted_dp;
struct dsa_port *dp;
u16 targeted_rx_vid; u16 targeted_rx_vid;
int err, port; int err;
if (!ds->tag_8021q_ctx) if (!ds->tag_8021q_ctx)
return 0; return 0;
targeted_ds = dsa_switch_find(info->tree_index, info->sw_index); targeted_ds = dsa_switch_find(info->tree_index, info->sw_index);
targeted_dp = dsa_to_port(targeted_ds, info->port); 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++) { dsa_switch_for_each_port(dp, ds) {
struct dsa_port *dp = dsa_to_port(ds, port); u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
u16 rx_vid = dsa_8021q_rx_vid(ds, port);
if (!dsa_tag_8021q_bridge_match(ds, port, info)) if (!dsa_port_tag_8021q_bridge_match(dp, info))
continue; continue;
/* Install the RX VID of the targeted port in our VLAN table */ /* 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, ...@@ -379,21 +381,20 @@ int dsa_tag_8021q_bridge_leave(struct dsa_switch *ds,
{ {
struct dsa_switch *targeted_ds; struct dsa_switch *targeted_ds;
struct dsa_port *targeted_dp; struct dsa_port *targeted_dp;
struct dsa_port *dp;
u16 targeted_rx_vid; u16 targeted_rx_vid;
int port;
if (!ds->tag_8021q_ctx) if (!ds->tag_8021q_ctx)
return 0; return 0;
targeted_ds = dsa_switch_find(info->tree_index, info->sw_index); targeted_ds = dsa_switch_find(info->tree_index, info->sw_index);
targeted_dp = dsa_to_port(targeted_ds, info->port); 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++) { dsa_switch_for_each_port(dp, ds) {
struct dsa_port *dp = dsa_to_port(ds, port); u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
u16 rx_vid = dsa_8021q_rx_vid(ds, port);
if (!dsa_tag_8021q_bridge_match(ds, port, info)) if (!dsa_port_tag_8021q_bridge_match(dp, info))
continue; continue;
/* Remove the RX VID of the targeted port from our VLAN table */ /* 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) ...@@ -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_8021q_context *ctx = ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port); struct dsa_port *dp = dsa_to_port(ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ds, port); u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
u16 tx_vid = dsa_8021q_tx_vid(ds, port); u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
struct net_device *master; struct net_device *master;
int err; int err;
...@@ -477,8 +478,8 @@ static void dsa_tag_8021q_port_teardown(struct dsa_switch *ds, int port) ...@@ -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_8021q_context *ctx = ds->tag_8021q_ctx;
struct dsa_port *dp = dsa_to_port(ds, port); struct dsa_port *dp = dsa_to_port(ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ds, port); u16 rx_vid = dsa_tag_8021q_rx_vid(dp);
u16 tx_vid = dsa_8021q_tx_vid(ds, port); u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
struct net_device *master; struct net_device *master;
/* The CPU port is implicitly configured by /* The CPU port is implicitly configured by
......
...@@ -39,9 +39,9 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb, ...@@ -39,9 +39,9 @@ static struct sk_buff *ocelot_xmit(struct sk_buff *skb,
struct net_device *netdev) struct net_device *netdev)
{ {
struct dsa_port *dp = dsa_slave_to_port(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); u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
struct ethhdr *hdr = eth_hdr(skb); struct ethhdr *hdr = eth_hdr(skb);
if (ocelot_ptp_rew_op(skb) || is_link_local_ether_addr(hdr->h_dest)) if (ocelot_ptp_rew_op(skb) || is_link_local_ether_addr(hdr->h_dest))
......
...@@ -158,10 +158,7 @@ static u16 sja1105_xmit_tpid(struct dsa_port *dp) ...@@ -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 * we're sure about that). It may not be on this port though, so we
* need to find it. * need to find it.
*/ */
list_for_each_entry(other_dp, &ds->dst->ports, list) { dsa_switch_for_each_port(other_dp, ds) {
if (other_dp->ds != ds)
continue;
if (!other_dp->bridge_dev) if (!other_dp->bridge_dev)
continue; continue;
...@@ -238,9 +235,9 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb, ...@@ -238,9 +235,9 @@ static struct sk_buff *sja1105_xmit(struct sk_buff *skb,
struct net_device *netdev) struct net_device *netdev)
{ {
struct dsa_port *dp = dsa_slave_to_port(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); u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
if (skb->offload_fwd_mark) if (skb->offload_fwd_mark)
return sja1105_imprecise_xmit(skb, netdev); return sja1105_imprecise_xmit(skb, netdev);
...@@ -266,9 +263,9 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb, ...@@ -266,9 +263,9 @@ static struct sk_buff *sja1110_xmit(struct sk_buff *skb,
{ {
struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone; struct sk_buff *clone = SJA1105_SKB_CB(skb)->clone;
struct dsa_port *dp = dsa_slave_to_port(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); u16 queue_mapping = skb_get_queue_mapping(skb);
u8 pcp = netdev_txq_to_tc(netdev, queue_mapping); u8 pcp = netdev_txq_to_tc(netdev, queue_mapping);
u16 tx_vid = dsa_tag_8021q_tx_vid(dp);
__be32 *tx_trailer; __be32 *tx_trailer;
__be16 *tx_header; __be16 *tx_header;
int trailer_pos; int trailer_pos;
......
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