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

Merge branch 'DSA-tag_8021q-cleanup'

Vladimir Oltean says:

====================
DSA tag_8021q cleanup

This small series tries to consolidate the VLAN handling in DSA a little
bit. It reworks tag_8021q to be minimally invasive to the dsa_switch_ops
structure. This makes the rest of the code a bit easier to follow.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents a8c16e8e 88236591
...@@ -210,14 +210,13 @@ struct sja1105_private { ...@@ -210,14 +210,13 @@ struct sja1105_private {
struct dsa_switch *ds; struct dsa_switch *ds;
struct list_head dsa_8021q_vlans; struct list_head dsa_8021q_vlans;
struct list_head bridge_vlans; struct list_head bridge_vlans;
struct list_head crosschip_links;
struct sja1105_flow_block flow_block; struct sja1105_flow_block flow_block;
struct sja1105_port ports[SJA1105_NUM_PORTS]; struct sja1105_port ports[SJA1105_NUM_PORTS];
/* Serializes transmission of management frames so that /* Serializes transmission of management frames so that
* the switch doesn't confuse them with one another. * the switch doesn't confuse them with one another.
*/ */
struct mutex mgmt_lock; struct mutex mgmt_lock;
bool expect_dsa_8021q; struct dsa_8021q_context *dsa_8021q_ctx;
enum sja1105_vlan_state vlan_state; enum sja1105_vlan_state vlan_state;
struct sja1105_cbs_entry *cbs; struct sja1105_cbs_entry *cbs;
struct sja1105_tagger_data tagger_data; struct sja1105_tagger_data tagger_data;
......
This diff is collapsed.
...@@ -5,37 +5,47 @@ ...@@ -5,37 +5,47 @@
#ifndef _NET_DSA_8021Q_H #ifndef _NET_DSA_8021Q_H
#define _NET_DSA_8021Q_H #define _NET_DSA_8021Q_H
#include <linux/refcount.h>
#include <linux/types.h> #include <linux/types.h>
struct dsa_switch; struct dsa_switch;
struct sk_buff; struct sk_buff;
struct net_device; struct net_device;
struct packet_type; struct packet_type;
struct dsa_8021q_context;
struct dsa_8021q_crosschip_link { struct dsa_8021q_crosschip_link {
struct list_head list; struct list_head list;
int port; int port;
struct dsa_switch *other_ds; struct dsa_8021q_context *other_ctx;
int other_port; int other_port;
refcount_t refcount; refcount_t refcount;
}; };
struct dsa_8021q_ops {
int (*vlan_add)(struct dsa_switch *ds, int port, u16 vid, u16 flags);
int (*vlan_del)(struct dsa_switch *ds, int port, u16 vid);
};
struct dsa_8021q_context {
const struct dsa_8021q_ops *ops;
struct dsa_switch *ds;
struct list_head crosschip_links;
};
#define DSA_8021Q_N_SUBVLAN 8 #define DSA_8021Q_N_SUBVLAN 8
#if IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q) #if IS_ENABLED(CONFIG_NET_DSA_TAG_8021Q)
int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, int dsa_8021q_setup(struct dsa_8021q_context *ctx, bool enabled);
bool enabled);
int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_join(struct dsa_8021q_context *ctx, int port,
struct dsa_switch *other_ds, struct dsa_8021q_context *other_ctx,
int other_port, int other_port);
struct list_head *crosschip_links);
int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_leave(struct dsa_8021q_context *ctx, int port,
struct dsa_switch *other_ds, struct dsa_8021q_context *other_ctx,
int other_port, int other_port);
struct list_head *crosschip_links);
struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev, struct sk_buff *dsa_8021q_xmit(struct sk_buff *skb, struct net_device *netdev,
u16 tpid, u16 tci); u16 tpid, u16 tci);
...@@ -56,24 +66,21 @@ bool vid_is_dsa_8021q(u16 vid); ...@@ -56,24 +66,21 @@ bool vid_is_dsa_8021q(u16 vid);
#else #else
int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int index, int dsa_8021q_setup(struct dsa_8021q_context *ctx, bool enabled)
bool enabled)
{ {
return 0; return 0;
} }
int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_join(struct dsa_8021q_context *ctx, int port,
struct dsa_switch *other_ds, struct dsa_8021q_context *other_ctx,
int other_port, int other_port)
struct list_head *crosschip_links)
{ {
return 0; return 0;
} }
int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_leave(struct dsa_8021q_context *ctx, int port,
struct dsa_switch *other_ds, struct dsa_8021q_context *other_ctx,
int other_port, int other_port)
struct list_head *crosschip_links)
{ {
return 0; return 0;
} }
......
...@@ -164,8 +164,6 @@ int dsa_port_vlan_add(struct dsa_port *dp, ...@@ -164,8 +164,6 @@ int dsa_port_vlan_add(struct dsa_port *dp,
struct switchdev_trans *trans); struct switchdev_trans *trans);
int dsa_port_vlan_del(struct dsa_port *dp, int dsa_port_vlan_del(struct dsa_port *dp,
const struct switchdev_obj_port_vlan *vlan); const struct switchdev_obj_port_vlan *vlan);
int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags);
int dsa_port_vid_del(struct dsa_port *dp, u16 vid);
int dsa_port_link_register_of(struct dsa_port *dp); int dsa_port_link_register_of(struct dsa_port *dp);
void dsa_port_link_unregister_of(struct dsa_port *dp); void dsa_port_link_unregister_of(struct dsa_port *dp);
extern const struct phylink_mac_ops dsa_port_phylink_mac_ops; extern const struct phylink_mac_ops dsa_port_phylink_mac_ops;
......
...@@ -433,39 +433,6 @@ int dsa_port_vlan_del(struct dsa_port *dp, ...@@ -433,39 +433,6 @@ int dsa_port_vlan_del(struct dsa_port *dp,
return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info); return dsa_port_notify(dp, DSA_NOTIFIER_VLAN_DEL, &info);
} }
int dsa_port_vid_add(struct dsa_port *dp, u16 vid, u16 flags)
{
struct switchdev_obj_port_vlan vlan = {
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
.flags = flags,
.vid_begin = vid,
.vid_end = vid,
};
struct switchdev_trans trans;
int err;
trans.ph_prepare = true;
err = dsa_port_vlan_add(dp, &vlan, &trans);
if (err)
return err;
trans.ph_prepare = false;
return dsa_port_vlan_add(dp, &vlan, &trans);
}
EXPORT_SYMBOL(dsa_port_vid_add);
int dsa_port_vid_del(struct dsa_port *dp, u16 vid)
{
struct switchdev_obj_port_vlan vlan = {
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
.vid_begin = vid,
.vid_end = vid,
};
return dsa_port_vlan_del(dp, &vlan);
}
EXPORT_SYMBOL(dsa_port_vid_del);
static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp) static struct phy_device *dsa_port_get_phy_device(struct dsa_port *dp)
{ {
struct device_node *phy_dn; struct device_node *phy_dn;
......
...@@ -1233,7 +1233,15 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, ...@@ -1233,7 +1233,15 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
u16 vid) u16 vid)
{ {
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_port *dp = dsa_slave_to_port(dev);
struct switchdev_obj_port_vlan vlan = {
.obj.id = SWITCHDEV_OBJ_ID_PORT_VLAN,
.vid_begin = vid,
.vid_end = vid,
/* This API only allows programming tagged, non-PVID VIDs */
.flags = 0,
};
struct bridge_vlan_info info; struct bridge_vlan_info info;
struct switchdev_trans trans;
int ret; int ret;
/* Check for a possible bridge VLAN entry now since there is no /* Check for a possible bridge VLAN entry now since there is no
...@@ -1252,11 +1260,25 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto, ...@@ -1252,11 +1260,25 @@ static int dsa_slave_vlan_rx_add_vid(struct net_device *dev, __be16 proto,
return -EBUSY; return -EBUSY;
} }
ret = dsa_port_vid_add(dp, vid, 0); /* User port... */
trans.ph_prepare = true;
ret = dsa_port_vlan_add(dp, &vlan, &trans);
if (ret)
return ret;
trans.ph_prepare = false;
ret = dsa_port_vlan_add(dp, &vlan, &trans);
if (ret) if (ret)
return ret; return ret;
ret = dsa_port_vid_add(dp->cpu_dp, vid, 0); /* And CPU port... */
trans.ph_prepare = true;
ret = dsa_port_vlan_add(dp->cpu_dp, &vlan, &trans);
if (ret)
return ret;
trans.ph_prepare = false;
ret = dsa_port_vlan_add(dp->cpu_dp, &vlan, &trans);
if (ret) if (ret)
return ret; return ret;
...@@ -1267,6 +1289,12 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, ...@@ -1267,6 +1289,12 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
u16 vid) u16 vid)
{ {
struct dsa_port *dp = dsa_slave_to_port(dev); struct dsa_port *dp = dsa_slave_to_port(dev);
struct switchdev_obj_port_vlan vlan = {
.vid_begin = vid,
.vid_end = vid,
/* This API only allows programming tagged, non-PVID VIDs */
.flags = 0,
};
struct bridge_vlan_info info; struct bridge_vlan_info info;
int ret; int ret;
...@@ -1289,7 +1317,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto, ...@@ -1289,7 +1317,7 @@ static int dsa_slave_vlan_rx_kill_vid(struct net_device *dev, __be16 proto,
/* Do not deprogram the CPU port as it may be shared with other user /* Do not deprogram the CPU port as it may be shared with other user
* ports which can be members of this VLAN as well. * ports which can be members of this VLAN as well.
*/ */
return dsa_port_vid_del(dp, vid); return dsa_port_vlan_del(dp, &vlan);
} }
struct dsa_hw_port { struct dsa_hw_port {
......
...@@ -146,15 +146,15 @@ EXPORT_SYMBOL_GPL(vid_is_dsa_8021q); ...@@ -146,15 +146,15 @@ EXPORT_SYMBOL_GPL(vid_is_dsa_8021q);
* user explicitly configured this @vid through the bridge core, then the @vid * user explicitly configured this @vid through the bridge core, then the @vid
* is installed again, but this time with the flags from the bridge layer. * is installed again, but this time with the flags from the bridge layer.
*/ */
static int dsa_8021q_vid_apply(struct dsa_switch *ds, int port, u16 vid, static int dsa_8021q_vid_apply(struct dsa_8021q_context *ctx, int port, u16 vid,
u16 flags, bool enabled) u16 flags, bool enabled)
{ {
struct dsa_port *dp = dsa_to_port(ds, port); struct dsa_port *dp = dsa_to_port(ctx->ds, port);
if (enabled) if (enabled)
return dsa_port_vid_add(dp, vid, flags); return ctx->ops->vlan_add(ctx->ds, dp->index, vid, flags);
return dsa_port_vid_del(dp, vid); return ctx->ops->vlan_del(ctx->ds, dp->index, vid);
} }
/* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single /* RX VLAN tagging (left) and TX VLAN tagging (right) setup shown for a single
...@@ -209,17 +209,18 @@ static int dsa_8021q_vid_apply(struct dsa_switch *ds, int port, u16 vid, ...@@ -209,17 +209,18 @@ static int dsa_8021q_vid_apply(struct dsa_switch *ds, int port, u16 vid,
* +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+ * +-+-----+-+-----+-+-----+-+-----+-+ +-+-----+-+-----+-+-----+-+-----+-+
* swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3 * swp0 swp1 swp2 swp3 swp0 swp1 swp2 swp3
*/ */
int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) static int dsa_8021q_setup_port(struct dsa_8021q_context *ctx, int port,
bool enabled)
{ {
int upstream = dsa_upstream_port(ds, port); int upstream = dsa_upstream_port(ctx->ds, port);
u16 rx_vid = dsa_8021q_rx_vid(ds, port); u16 rx_vid = dsa_8021q_rx_vid(ctx->ds, port);
u16 tx_vid = dsa_8021q_tx_vid(ds, port); u16 tx_vid = dsa_8021q_tx_vid(ctx->ds, port);
int i, err; int i, err;
/* The CPU port is implicitly configured by /* The CPU port is implicitly configured by
* configuring the front-panel ports * configuring the front-panel ports
*/ */
if (!dsa_is_user_port(ds, port)) if (!dsa_is_user_port(ctx->ds, port))
return 0; return 0;
/* Add this user port's RX VID to the membership list of all others /* Add this user port's RX VID to the membership list of all others
...@@ -227,7 +228,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) ...@@ -227,7 +228,7 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
* L2 forwarding rules still take precedence when there are no VLAN * L2 forwarding rules still take precedence when there are no VLAN
* restrictions, so there are no concerns about leaking traffic. * restrictions, so there are no concerns about leaking traffic.
*/ */
for (i = 0; i < ds->num_ports; i++) { for (i = 0; i < ctx->ds->num_ports; i++) {
u16 flags; u16 flags;
if (i == upstream) if (i == upstream)
...@@ -240,9 +241,10 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) ...@@ -240,9 +241,10 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
/* The RX VID is a regular VLAN on all others */ /* The RX VID is a regular VLAN on all others */
flags = BRIDGE_VLAN_INFO_UNTAGGED; flags = BRIDGE_VLAN_INFO_UNTAGGED;
err = dsa_8021q_vid_apply(ds, i, rx_vid, flags, enabled); err = dsa_8021q_vid_apply(ctx, i, rx_vid, flags, enabled);
if (err) { if (err) {
dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n", dev_err(ctx->ds->dev,
"Failed to apply RX VID %d to port %d: %d\n",
rx_vid, port, err); rx_vid, port, err);
return err; return err;
} }
...@@ -251,80 +253,100 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled) ...@@ -251,80 +253,100 @@ int dsa_port_setup_8021q_tagging(struct dsa_switch *ds, int port, bool enabled)
/* CPU port needs to see this port's RX VID /* CPU port needs to see this port's RX VID
* as tagged egress. * as tagged egress.
*/ */
err = dsa_8021q_vid_apply(ds, upstream, rx_vid, 0, enabled); err = dsa_8021q_vid_apply(ctx, upstream, rx_vid, 0, enabled);
if (err) { if (err) {
dev_err(ds->dev, "Failed to apply RX VID %d to port %d: %d\n", dev_err(ctx->ds->dev,
"Failed to apply RX VID %d to port %d: %d\n",
rx_vid, port, err); rx_vid, port, err);
return err; return err;
} }
/* Finally apply the TX VID on this port and on the CPU port */ /* Finally apply the TX VID on this port and on the CPU port */
err = dsa_8021q_vid_apply(ds, port, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED, err = dsa_8021q_vid_apply(ctx, port, tx_vid, BRIDGE_VLAN_INFO_UNTAGGED,
enabled); enabled);
if (err) { if (err) {
dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n", dev_err(ctx->ds->dev,
"Failed to apply TX VID %d on port %d: %d\n",
tx_vid, port, err); tx_vid, port, err);
return err; return err;
} }
err = dsa_8021q_vid_apply(ds, upstream, tx_vid, 0, enabled); err = dsa_8021q_vid_apply(ctx, upstream, tx_vid, 0, enabled);
if (err) { if (err) {
dev_err(ds->dev, "Failed to apply TX VID %d on port %d: %d\n", dev_err(ctx->ds->dev,
"Failed to apply TX VID %d on port %d: %d\n",
tx_vid, upstream, err); tx_vid, upstream, err);
return err; return err;
} }
return err; return err;
} }
EXPORT_SYMBOL_GPL(dsa_port_setup_8021q_tagging);
static int dsa_8021q_crosschip_link_apply(struct dsa_switch *ds, int port, int dsa_8021q_setup(struct dsa_8021q_context *ctx, bool enabled)
struct dsa_switch *other_ds, {
int rc, port;
for (port = 0; port < ctx->ds->num_ports; port++) {
rc = dsa_8021q_setup_port(ctx, port, enabled);
if (rc < 0) {
dev_err(ctx->ds->dev,
"Failed to setup VLAN tagging for port %d: %d\n",
port, rc);
return rc;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(dsa_8021q_setup);
static int dsa_8021q_crosschip_link_apply(struct dsa_8021q_context *ctx,
int port,
struct dsa_8021q_context *other_ctx,
int other_port, bool enabled) int other_port, bool enabled)
{ {
u16 rx_vid = dsa_8021q_rx_vid(ds, port); u16 rx_vid = dsa_8021q_rx_vid(ctx->ds, port);
/* @rx_vid of local @ds port @port goes to @other_port of /* @rx_vid of local @ds port @port goes to @other_port of
* @other_ds * @other_ds
*/ */
return dsa_8021q_vid_apply(other_ds, other_port, rx_vid, return dsa_8021q_vid_apply(other_ctx, other_port, rx_vid,
BRIDGE_VLAN_INFO_UNTAGGED, enabled); BRIDGE_VLAN_INFO_UNTAGGED, enabled);
} }
static int dsa_8021q_crosschip_link_add(struct dsa_switch *ds, int port, static int dsa_8021q_crosschip_link_add(struct dsa_8021q_context *ctx, int port,
struct dsa_switch *other_ds, struct dsa_8021q_context *other_ctx,
int other_port, int other_port)
struct list_head *crosschip_links)
{ {
struct dsa_8021q_crosschip_link *c; struct dsa_8021q_crosschip_link *c;
list_for_each_entry(c, crosschip_links, list) { list_for_each_entry(c, &ctx->crosschip_links, list) {
if (c->port == port && c->other_ds == other_ds && if (c->port == port && c->other_ctx == other_ctx &&
c->other_port == other_port) { c->other_port == other_port) {
refcount_inc(&c->refcount); refcount_inc(&c->refcount);
return 0; return 0;
} }
} }
dev_dbg(ds->dev, "adding crosschip link from port %d to %s port %d\n", dev_dbg(ctx->ds->dev,
port, dev_name(other_ds->dev), other_port); "adding crosschip link from port %d to %s port %d\n",
port, dev_name(other_ctx->ds->dev), other_port);
c = kzalloc(sizeof(*c), GFP_KERNEL); c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c) if (!c)
return -ENOMEM; return -ENOMEM;
c->port = port; c->port = port;
c->other_ds = other_ds; c->other_ctx = other_ctx;
c->other_port = other_port; c->other_port = other_port;
refcount_set(&c->refcount, 1); refcount_set(&c->refcount, 1);
list_add(&c->list, crosschip_links); list_add(&c->list, &ctx->crosschip_links);
return 0; return 0;
} }
static void dsa_8021q_crosschip_link_del(struct dsa_switch *ds, static void dsa_8021q_crosschip_link_del(struct dsa_8021q_context *ctx,
struct dsa_8021q_crosschip_link *c, struct dsa_8021q_crosschip_link *c,
struct list_head *crosschip_links,
bool *keep) bool *keep)
{ {
*keep = !refcount_dec_and_test(&c->refcount); *keep = !refcount_dec_and_test(&c->refcount);
...@@ -332,9 +354,9 @@ static void dsa_8021q_crosschip_link_del(struct dsa_switch *ds, ...@@ -332,9 +354,9 @@ static void dsa_8021q_crosschip_link_del(struct dsa_switch *ds,
if (*keep) if (*keep)
return; return;
dev_dbg(ds->dev, dev_dbg(ctx->ds->dev,
"deleting crosschip link from port %d to %s port %d\n", "deleting crosschip link from port %d to %s port %d\n",
c->port, dev_name(c->other_ds->dev), c->other_port); c->port, dev_name(c->other_ctx->ds->dev), c->other_port);
list_del(&c->list); list_del(&c->list);
kfree(c); kfree(c);
...@@ -347,64 +369,58 @@ static void dsa_8021q_crosschip_link_del(struct dsa_switch *ds, ...@@ -347,64 +369,58 @@ static void dsa_8021q_crosschip_link_del(struct dsa_switch *ds,
* or untagged: it doesn't matter, since it should never egress a frame having * or untagged: it doesn't matter, since it should never egress a frame having
* our @rx_vid. * our @rx_vid.
*/ */
int dsa_8021q_crosschip_bridge_join(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_join(struct dsa_8021q_context *ctx, int port,
struct dsa_switch *other_ds, struct dsa_8021q_context *other_ctx,
int other_port, int other_port)
struct list_head *crosschip_links)
{ {
/* @other_upstream is how @other_ds reaches us. If we are part /* @other_upstream is how @other_ds reaches us. If we are part
* of disjoint trees, then we are probably connected through * of disjoint trees, then we are probably connected through
* our CPU ports. If we're part of the same tree though, we should * our CPU ports. If we're part of the same tree though, we should
* probably use dsa_towards_port. * probably use dsa_towards_port.
*/ */
int other_upstream = dsa_upstream_port(other_ds, other_port); int other_upstream = dsa_upstream_port(other_ctx->ds, other_port);
int rc; int rc;
rc = dsa_8021q_crosschip_link_add(ds, port, other_ds, rc = dsa_8021q_crosschip_link_add(ctx, port, other_ctx, other_port);
other_port, crosschip_links);
if (rc) if (rc)
return rc; return rc;
rc = dsa_8021q_crosschip_link_apply(ds, port, other_ds, rc = dsa_8021q_crosschip_link_apply(ctx, port, other_ctx,
other_port, true); other_port, true);
if (rc) if (rc)
return rc; return rc;
rc = dsa_8021q_crosschip_link_add(ds, port, other_ds, rc = dsa_8021q_crosschip_link_add(ctx, port, other_ctx, other_upstream);
other_upstream,
crosschip_links);
if (rc) if (rc)
return rc; return rc;
return dsa_8021q_crosschip_link_apply(ds, port, other_ds, return dsa_8021q_crosschip_link_apply(ctx, port, other_ctx,
other_upstream, true); other_upstream, true);
} }
EXPORT_SYMBOL_GPL(dsa_8021q_crosschip_bridge_join); EXPORT_SYMBOL_GPL(dsa_8021q_crosschip_bridge_join);
int dsa_8021q_crosschip_bridge_leave(struct dsa_switch *ds, int port, int dsa_8021q_crosschip_bridge_leave(struct dsa_8021q_context *ctx, int port,
struct dsa_switch *other_ds, struct dsa_8021q_context *other_ctx,
int other_port, int other_port)
struct list_head *crosschip_links)
{ {
int other_upstream = dsa_upstream_port(other_ds, other_port); int other_upstream = dsa_upstream_port(other_ctx->ds, other_port);
struct dsa_8021q_crosschip_link *c, *n; struct dsa_8021q_crosschip_link *c, *n;
list_for_each_entry_safe(c, n, crosschip_links, list) { list_for_each_entry_safe(c, n, &ctx->crosschip_links, list) {
if (c->port == port && c->other_ds == other_ds && if (c->port == port && c->other_ctx == other_ctx &&
(c->other_port == other_port || (c->other_port == other_port ||
c->other_port == other_upstream)) { c->other_port == other_upstream)) {
struct dsa_switch *other_ds = c->other_ds; struct dsa_8021q_context *other_ctx = c->other_ctx;
int other_port = c->other_port; int other_port = c->other_port;
bool keep; bool keep;
int rc; int rc;
dsa_8021q_crosschip_link_del(ds, c, crosschip_links, dsa_8021q_crosschip_link_del(ctx, c, &keep);
&keep);
if (keep) if (keep)
continue; continue;
rc = dsa_8021q_crosschip_link_apply(ds, port, rc = dsa_8021q_crosschip_link_apply(ctx, port,
other_ds, other_ctx,
other_port, other_port,
false); false);
if (rc) if (rc)
......
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