Skip to content

Commit

Permalink
net: dsa: keep the bridge_dev and bridge_num as part of the same stru…
Browse files Browse the repository at this point in the history
…cture

The main desire behind this is to provide coherent bridge information to
the fast path without locking.

For example, right now we set dp->bridge_dev and dp->bridge_num from
separate code paths, it is theoretically possible for a packet
transmission to read these two port properties consecutively and find a
bridge number which does not correspond with the bridge device.

Another desire is to start passing more complex bridge information to
dsa_switch_ops functions. For example, with FDB isolation, it is
expected that drivers will need to be passed the bridge which requested
an FDB/MDB entry to be offloaded, and along with that bridge_dev, the
associated bridge_num should be passed too, in case the driver might
want to implement an isolation scheme based on that number.

We already pass the {bridge_dev, bridge_num} pair to the TX forwarding
offload switch API, however we'd like to remove that and squash it into
the basic bridge join/leave API. So that means we need to pass this
pair to the bridge join/leave API.

During dsa_port_bridge_leave, first we unset dp->bridge_dev, then we
call the driver's .port_bridge_leave with what used to be our
dp->bridge_dev, but provided as an argument.

When bridge_dev and bridge_num get folded into a single structure, we
need to preserve this behavior in dsa_port_bridge_leave: we need a copy
of what used to be in dp->bridge.

Switch drivers check bridge membership by comparing dp->bridge_dev with
the provided bridge_dev, but now, if we provide the struct dsa_bridge as
a pointer, they cannot keep comparing dp->bridge to the provided
pointer, since this only points to an on-stack copy. To make this
obvious and prevent driver writers from forgetting and doing stupid
things, in this new API, the struct dsa_bridge is provided as a full
structure (not very large, contains an int and a pointer) instead of a
pointer. An explicit comparison function needs to be used to determine
bridge membership: dsa_port_offloads_bridge().

Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: Alvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Vladimir Oltean authored and Jakub Kicinski committed Dec 8, 2021
1 parent 6a43cba commit d3eed0e
Show file tree
Hide file tree
Showing 23 changed files with 177 additions and 148 deletions.
8 changes: 4 additions & 4 deletions drivers/net/dsa/b53/b53_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1860,7 +1860,7 @@ int b53_mdb_del(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL(b53_mdb_del);

int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br)
int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge)
{
struct b53_device *dev = ds->priv;
s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
Expand All @@ -1887,7 +1887,7 @@ int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br)
b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(port), &pvlan);

b53_for_each_port(dev, i) {
if (dsa_port_bridge_dev_get(dsa_to_port(ds, i)) != br)
if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
continue;

/* Add this local port to the remote port VLAN control
Expand All @@ -1911,7 +1911,7 @@ int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br)
}
EXPORT_SYMBOL(b53_br_join);

void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br)
void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge)
{
struct b53_device *dev = ds->priv;
struct b53_vlan *vl = &dev->vlans[0];
Expand All @@ -1923,7 +1923,7 @@ void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *br)

b53_for_each_port(dev, i) {
/* Don't touch the remaining ports */
if (dsa_port_bridge_dev_get(dsa_to_port(ds, i)) != br)
if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
continue;

b53_read16(dev, B53_PVLAN_PAGE, B53_PVLAN_PORT_MASK(i), &reg);
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/dsa/b53/b53_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,8 +324,8 @@ void b53_get_strings(struct dsa_switch *ds, int port, u32 stringset,
void b53_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *data);
int b53_get_sset_count(struct dsa_switch *ds, int port, int sset);
void b53_get_ethtool_phy_stats(struct dsa_switch *ds, int port, uint64_t *data);
int b53_br_join(struct dsa_switch *ds, int port, struct net_device *bridge);
void b53_br_leave(struct dsa_switch *ds, int port, struct net_device *bridge);
int b53_br_join(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
void b53_br_leave(struct dsa_switch *ds, int port, struct dsa_bridge bridge);
void b53_br_set_stp_state(struct dsa_switch *ds, int port, u8 state);
void b53_br_fast_age(struct dsa_switch *ds, int port);
int b53_br_flags_pre(struct dsa_switch *ds, int port,
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/dsa/dsa_loop.c
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,19 @@ static int dsa_loop_phy_write(struct dsa_switch *ds, int port,
}

static int dsa_loop_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *bridge)
struct dsa_bridge bridge)
{
dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
__func__, port, bridge->name);
__func__, port, bridge.dev->name);

return 0;
}

static void dsa_loop_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *bridge)
struct dsa_bridge bridge)
{
dev_dbg(ds->dev, "%s: port: %d, bridge: %s\n",
__func__, port, bridge->name);
__func__, port, bridge.dev->name);
}

static void dsa_loop_port_stp_state_set(struct dsa_switch *ds, int port,
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/dsa/hirschmann/hellcreek.c
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,7 @@ static int hellcreek_bridge_flags(struct dsa_switch *ds, int port,
}

static int hellcreek_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct hellcreek *hellcreek = ds->priv;

Expand All @@ -691,7 +691,7 @@ static int hellcreek_port_bridge_join(struct dsa_switch *ds, int port,
}

static void hellcreek_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct hellcreek *hellcreek = ds->priv;

Expand Down
4 changes: 2 additions & 2 deletions drivers/net/dsa/lan9303-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1103,7 +1103,7 @@ static void lan9303_port_disable(struct dsa_switch *ds, int port)
}

static int lan9303_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct lan9303 *chip = ds->priv;

Expand All @@ -1117,7 +1117,7 @@ static int lan9303_port_bridge_join(struct dsa_switch *ds, int port,
}

static void lan9303_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct lan9303 *chip = ds->priv;

Expand Down
14 changes: 8 additions & 6 deletions drivers/net/dsa/lantiq_gswip.c
Original file line number Diff line number Diff line change
Expand Up @@ -1146,16 +1146,17 @@ static int gswip_vlan_remove(struct gswip_priv *priv,
}

static int gswip_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *bridge)
struct dsa_bridge bridge)
{
struct net_device *br = bridge.dev;
struct gswip_priv *priv = ds->priv;
int err;

/* When the bridge uses VLAN filtering we have to configure VLAN
* specific bridges. No bridge is configured here.
*/
if (!br_vlan_enabled(bridge)) {
err = gswip_vlan_add_unaware(priv, bridge, port);
if (!br_vlan_enabled(br)) {
err = gswip_vlan_add_unaware(priv, br, port);
if (err)
return err;
priv->port_vlan_filter &= ~BIT(port);
Expand All @@ -1166,17 +1167,18 @@ static int gswip_port_bridge_join(struct dsa_switch *ds, int port,
}

static void gswip_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *bridge)
struct dsa_bridge bridge)
{
struct net_device *br = bridge.dev;
struct gswip_priv *priv = ds->priv;

gswip_add_single_port_br(priv, port, true);

/* When the bridge uses VLAN filtering we have to configure VLAN
* specific bridges. No bridge is configured here.
*/
if (!br_vlan_enabled(bridge))
gswip_vlan_remove(priv, bridge, port, 0, true, false);
if (!br_vlan_enabled(br))
gswip_vlan_remove(priv, br, port, 0, true, false);
}

static int gswip_port_vlan_prepare(struct dsa_switch *ds, int port,
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/dsa/microchip/ksz_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf)
EXPORT_SYMBOL_GPL(ksz_get_ethtool_stats);

int ksz_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
/* port_stp_state_set() will be called after to put the port in
* appropriate state so there is no need to do anything.
Expand All @@ -203,7 +203,7 @@ int ksz_port_bridge_join(struct dsa_switch *ds, int port,
EXPORT_SYMBOL_GPL(ksz_port_bridge_join);

void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
/* port_stp_state_set() will be called after to put the port in
* forwarding state so there is no need to do anything.
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/dsa/microchip/ksz_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,9 @@ void ksz_mac_link_down(struct dsa_switch *ds, int port, unsigned int mode,
int ksz_sset_count(struct dsa_switch *ds, int port, int sset);
void ksz_get_ethtool_stats(struct dsa_switch *ds, int port, uint64_t *buf);
int ksz_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br);
struct dsa_bridge bridge);
void ksz_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br);
struct dsa_bridge bridge);
void ksz_port_fast_age(struct dsa_switch *ds, int port);
int ksz_port_fdb_dump(struct dsa_switch *ds, int port, dsa_fdb_dump_cb_t *cb,
void *data);
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/dsa/mt7530.c
Original file line number Diff line number Diff line change
Expand Up @@ -1186,7 +1186,7 @@ mt7530_port_bridge_flags(struct dsa_switch *ds, int port,

static int
mt7530_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *bridge)
struct dsa_bridge bridge)
{
struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
u32 port_bitmap = BIT(MT7530_CPU_PORT);
Expand All @@ -1204,7 +1204,7 @@ mt7530_port_bridge_join(struct dsa_switch *ds, int port,
* same bridge. If the port is disabled, port matrix is kept
* and not being setup until the port becomes enabled.
*/
if (dsa_port_bridge_dev_get(other_dp) != bridge)
if (!dsa_port_offloads_bridge(other_dp, &bridge))
continue;

if (priv->ports[other_port].enable)
Expand Down Expand Up @@ -1303,7 +1303,7 @@ mt7530_port_set_vlan_aware(struct dsa_switch *ds, int port)

static void
mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *bridge)
struct dsa_bridge bridge)
{
struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
struct mt7530_priv *priv = ds->priv;
Expand All @@ -1320,7 +1320,7 @@ mt7530_port_bridge_leave(struct dsa_switch *ds, int port,
* in the same bridge. If the port is disabled, port matrix
* is kept and not being setup until the port becomes enabled.
*/
if (dsa_port_bridge_dev_get(other_dp) != bridge)
if (!dsa_port_offloads_bridge(other_dp, &bridge))
continue;

if (priv->ports[other_port].enable)
Expand Down
26 changes: 12 additions & 14 deletions drivers/net/dsa/mv88e6xxx/chip.c
Original file line number Diff line number Diff line change
Expand Up @@ -2410,15 +2410,15 @@ static int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
}

static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
struct net_device *br)
struct dsa_bridge bridge)
{
struct dsa_switch *ds = chip->ds;
struct dsa_switch_tree *dst = ds->dst;
struct dsa_port *dp;
int err;

list_for_each_entry(dp, &dst->ports, list) {
if (dsa_port_bridge_dev_get(dp) == br) {
if (dsa_port_offloads_bridge(dp, &bridge)) {
if (dp->ds == ds) {
/* This is a local bridge group member,
* remap its Port VLAN Map.
Expand All @@ -2442,14 +2442,14 @@ static int mv88e6xxx_bridge_map(struct mv88e6xxx_chip *chip,
}

static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;

mv88e6xxx_reg_lock(chip);

err = mv88e6xxx_bridge_map(chip, br);
err = mv88e6xxx_bridge_map(chip, bridge);
if (err)
goto unlock;

Expand All @@ -2464,14 +2464,14 @@ static int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
}

static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;

mv88e6xxx_reg_lock(chip);

if (mv88e6xxx_bridge_map(chip, br) ||
if (mv88e6xxx_bridge_map(chip, bridge) ||
mv88e6xxx_port_vlan_map(chip, port))
dev_err(ds->dev, "failed to remap in-chip Port VLAN\n");

Expand All @@ -2486,7 +2486,7 @@ static void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port,

static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,
int tree_index, int sw_index,
int port, struct net_device *br)
int port, struct dsa_bridge bridge)
{
struct mv88e6xxx_chip *chip = ds->priv;
int err;
Expand All @@ -2503,7 +2503,7 @@ static int mv88e6xxx_crosschip_bridge_join(struct dsa_switch *ds,

static void mv88e6xxx_crosschip_bridge_leave(struct dsa_switch *ds,
int tree_index, int sw_index,
int port, struct net_device *br)
int port, struct dsa_bridge bridge)
{
struct mv88e6xxx_chip *chip = ds->priv;

Expand Down Expand Up @@ -2535,19 +2535,17 @@ static int mv88e6xxx_map_virtual_bridge_to_pvt(struct dsa_switch *ds,
}

static int mv88e6xxx_bridge_tx_fwd_offload(struct dsa_switch *ds, int port,
struct net_device *br,
unsigned int bridge_num)
struct dsa_bridge bridge)
{
return mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge_num);
return mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
}

static void mv88e6xxx_bridge_tx_fwd_unoffload(struct dsa_switch *ds, int port,
struct net_device *br,
unsigned int bridge_num)
struct dsa_bridge bridge)
{
int err;

err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge_num);
err = mv88e6xxx_map_virtual_bridge_to_pvt(ds, bridge.num);
if (err) {
dev_err(ds->dev, "failed to remap cross-chip Port VLAN: %pe\n",
ERR_PTR(err));
Expand Down
8 changes: 4 additions & 4 deletions drivers/net/dsa/ocelot/felix.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,21 +706,21 @@ static int felix_bridge_flags(struct dsa_switch *ds, int port,
}

static int felix_bridge_join(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct ocelot *ocelot = ds->priv;

ocelot_port_bridge_join(ocelot, port, br);
ocelot_port_bridge_join(ocelot, port, bridge.dev);

return 0;
}

static void felix_bridge_leave(struct dsa_switch *ds, int port,
struct net_device *br)
struct dsa_bridge bridge)
{
struct ocelot *ocelot = ds->priv;

ocelot_port_bridge_leave(ocelot, port, br);
ocelot_port_bridge_leave(ocelot, port, bridge.dev);
}

static int felix_lag_join(struct dsa_switch *ds, int port,
Expand Down
12 changes: 6 additions & 6 deletions drivers/net/dsa/qca8k.c
Original file line number Diff line number Diff line change
Expand Up @@ -1810,8 +1810,8 @@ qca8k_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
QCA8K_PORT_LOOKUP_STATE_MASK, stp_state);
}

static int
qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
static int qca8k_port_bridge_join(struct dsa_switch *ds, int port,
struct dsa_bridge bridge)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
int port_mask, cpu_port;
Expand All @@ -1823,7 +1823,7 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
if (dsa_is_cpu_port(ds, i))
continue;
if (dsa_port_bridge_dev_get(dsa_to_port(ds, i)) != br)
if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
continue;
/* Add this port to the portvlan mask of the other ports
* in the bridge
Expand All @@ -1844,8 +1844,8 @@ qca8k_port_bridge_join(struct dsa_switch *ds, int port, struct net_device *br)
return ret;
}

static void
qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)
static void qca8k_port_bridge_leave(struct dsa_switch *ds, int port,
struct dsa_bridge bridge)
{
struct qca8k_priv *priv = (struct qca8k_priv *)ds->priv;
int cpu_port, i;
Expand All @@ -1855,7 +1855,7 @@ qca8k_port_bridge_leave(struct dsa_switch *ds, int port, struct net_device *br)
for (i = 0; i < QCA8K_NUM_PORTS; i++) {
if (dsa_is_cpu_port(ds, i))
continue;
if (dsa_port_bridge_dev_get(dsa_to_port(ds, i)) != br)
if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
continue;
/* Remove this port to the portvlan mask of the other ports
* in the bridge
Expand Down
Loading

0 comments on commit d3eed0e

Please sign in to comment.