Skip to content

Commit

Permalink
Merge branch 'rework-dsa-bridge-tx-forwarding-offload-api'
Browse files Browse the repository at this point in the history
Vladimir Oltean says:

====================
Rework DSA bridge TX forwarding offload API

This change set is preparation work for DSA support of bridge FDB
isolation. It replaces struct net_device *dp->bridge_dev with a struct
dsa_bridge *dp->bridge that contains some extra information about that
bridge, like a unique number kept by DSA.

Up until now we computed that number only with the bridge TX forwarding
offload feature, but it will be needed for other features too, like for
isolation of FDB entries belonging to different bridges. Hardware
implementations vary, but one common pattern seems to be the presence of
a FID field which can be associated with that bridge number kept by DSA.
The idea was outlined here:
https://patchwork.kernel.org/project/netdevbpf/patch/20210818120150.892647-16-vladimir.oltean@nxp.com/
(the difference being that with this new proposal, drivers would not
need to call dsa_bridge_num_find, instead the bridge_num would be part
of the struct dsa_bridge :: num passed as argument).

No functional change is intended for drivers that don't already make use
of the bridge TX forwarding offload. I've tested the changes on the
felix, sja1105 and mv88e6xxx drivers, but nonetheless I'm copying all
DSA driver maintainers due to API changes that are taking place.

Compared to v1 and v2, the amount of patches is larger, but the contents
is mostly the same, just split up hopefully a bit better for review.
====================

Link: https://lore.kernel.org/r/20211206165758.1553882-1-vladimir.oltean@nxp.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
  • Loading branch information
Jakub Kicinski committed Dec 8, 2021
2 parents 1fe5b01 + 857fdd7 commit 3a262c7
Showing 26 changed files with 440 additions and 369 deletions.
9 changes: 5 additions & 4 deletions drivers/net/dsa/b53/b53_common.c
Original file line number Diff line number Diff line change
@@ -1860,7 +1860,8 @@ 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,
bool *tx_fwd_offload)
{
struct b53_device *dev = ds->priv;
s8 cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
@@ -1887,7 +1888,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_to_port(ds, i)->bridge_dev != br)
if (!dsa_port_offloads_bridge(dsa_to_port(ds, i), &bridge))
continue;

/* Add this local port to the remote port VLAN control
@@ -1911,7 +1912,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];
@@ -1923,7 +1924,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_to_port(ds, i)->bridge_dev != 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);
5 changes: 3 additions & 2 deletions drivers/net/dsa/b53/b53_priv.h
Original file line number Diff line number Diff line change
@@ -324,8 +324,9 @@ 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,
bool *tx_fwd_offload);
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,
9 changes: 5 additions & 4 deletions drivers/net/dsa/dsa_loop.c
Original file line number Diff line number Diff line change
@@ -167,19 +167,20 @@ 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,
bool *tx_fwd_offload)
{
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,
5 changes: 3 additions & 2 deletions drivers/net/dsa/hirschmann/hellcreek.c
Original file line number Diff line number Diff line change
@@ -674,7 +674,8 @@ 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,
bool *tx_fwd_offload)
{
struct hellcreek *hellcreek = ds->priv;

@@ -691,7 +692,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;

7 changes: 4 additions & 3 deletions drivers/net/dsa/lan9303-core.c
Original file line number Diff line number Diff line change
@@ -1103,12 +1103,13 @@ 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,
bool *tx_fwd_offload)
{
struct lan9303 *chip = ds->priv;

dev_dbg(chip->dev, "%s(port %d)\n", __func__, port);
if (dsa_to_port(ds, 1)->bridge_dev == dsa_to_port(ds, 2)->bridge_dev) {
if (dsa_port_bridge_same(dsa_to_port(ds, 1), dsa_to_port(ds, 2))) {
lan9303_bridge_ports(chip);
chip->is_bridged = true; /* unleash stp_state_set() */
}
@@ -1117,7 +1118,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;

25 changes: 14 additions & 11 deletions drivers/net/dsa/lantiq_gswip.c
Original file line number Diff line number Diff line change
@@ -759,7 +759,7 @@ static int gswip_port_vlan_filtering(struct dsa_switch *ds, int port,
bool vlan_filtering,
struct netlink_ext_ack *extack)
{
struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
struct gswip_priv *priv = ds->priv;

/* Do not allow changing the VLAN filtering options while in bridge */
@@ -1146,16 +1146,18 @@ 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,
bool *tx_fwd_offload)
{
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);
@@ -1166,25 +1168,26 @@ 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,
const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack)
{
struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
struct gswip_priv *priv = ds->priv;
struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
unsigned int max_ports = priv->hw_info->max_ports;
int pos = max_ports;
int i, idx = -1;
@@ -1229,8 +1232,8 @@ static int gswip_port_vlan_add(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan,
struct netlink_ext_ack *extack)
{
struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
struct gswip_priv *priv = ds->priv;
struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
int err;
@@ -1254,8 +1257,8 @@ static int gswip_port_vlan_add(struct dsa_switch *ds, int port,
static int gswip_port_vlan_del(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_vlan *vlan)
{
struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
struct gswip_priv *priv = ds->priv;
struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;

/* We have to receive all packets on the CPU port and should not
@@ -1340,8 +1343,8 @@ static void gswip_port_stp_state_set(struct dsa_switch *ds, int port, u8 state)
static int gswip_port_fdb(struct dsa_switch *ds, int port,
const unsigned char *addr, u16 vid, bool add)
{
struct net_device *bridge = dsa_port_bridge_dev_get(dsa_to_port(ds, port));
struct gswip_priv *priv = ds->priv;
struct net_device *bridge = dsa_to_port(ds, port)->bridge_dev;
struct gswip_pce_table_entry mac_bridge = {0,};
unsigned int cpu_port = priv->hw_info->cpu_port;
int fid = -1;
7 changes: 4 additions & 3 deletions drivers/net/dsa/microchip/ksz_common.c
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ void ksz_update_port_member(struct ksz_device *dev, int port)
continue;
if (port == i)
continue;
if (!dp->bridge_dev || dp->bridge_dev != other_dp->bridge_dev)
if (!dsa_port_bridge_same(dp, other_dp))
continue;

if (other_p->stp_state == BR_STATE_FORWARDING &&
@@ -192,7 +192,8 @@ 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,
bool *tx_fwd_offload)
{
/* port_stp_state_set() will be called after to put the port in
* appropriate state so there is no need to do anything.
@@ -203,7 +204,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.
4 changes: 2 additions & 2 deletions drivers/net/dsa/microchip/ksz_common.h
Original file line number Diff line number Diff line change
@@ -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, bool *tx_fwd_offload);
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);
58 changes: 33 additions & 25 deletions drivers/net/dsa/mt7530.c
Original file line number Diff line number Diff line change
@@ -1186,29 +1186,33 @@ 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, bool *tx_fwd_offload)
{
struct mt7530_priv *priv = ds->priv;
struct dsa_port *dp = dsa_to_port(ds, port), *other_dp;
u32 port_bitmap = BIT(MT7530_CPU_PORT);
int i;
struct mt7530_priv *priv = ds->priv;

mutex_lock(&priv->reg_mutex);

for (i = 0; i < MT7530_NUM_PORTS; i++) {
dsa_switch_for_each_user_port(other_dp, ds) {
int other_port = other_dp->index;

if (dp == other_dp)
continue;

/* Add this port to the port matrix of the other ports in the
* same bridge. If the port is disabled, port matrix is kept
* and not being setup until the port becomes enabled.
*/
if (dsa_is_user_port(ds, i) && i != port) {
if (dsa_to_port(ds, i)->bridge_dev != bridge)
continue;
if (priv->ports[i].enable)
mt7530_set(priv, MT7530_PCR_P(i),
PCR_MATRIX(BIT(port)));
priv->ports[i].pm |= PCR_MATRIX(BIT(port));
if (!dsa_port_offloads_bridge(other_dp, &bridge))
continue;

port_bitmap |= BIT(i);
}
if (priv->ports[other_port].enable)
mt7530_set(priv, MT7530_PCR_P(other_port),
PCR_MATRIX(BIT(port)));
priv->ports[other_port].pm |= PCR_MATRIX(BIT(port));

port_bitmap |= BIT(other_port);
}

/* Add the all other ports to this port matrix. */
@@ -1236,7 +1240,7 @@ mt7530_port_set_vlan_unaware(struct dsa_switch *ds, int port)
/* This is called after .port_bridge_leave when leaving a VLAN-aware
* bridge. Don't set standalone ports to fallback mode.
*/
if (dsa_to_port(ds, port)->bridge_dev)
if (dsa_port_bridge_dev_get(dsa_to_port(ds, port)))
mt7530_rmw(priv, MT7530_PCR_P(port), PCR_PORT_VLAN_MASK,
MT7530_PORT_FALLBACK_MODE);

@@ -1299,26 +1303,30 @@ 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;
int i;

mutex_lock(&priv->reg_mutex);

for (i = 0; i < MT7530_NUM_PORTS; i++) {
dsa_switch_for_each_user_port(other_dp, ds) {
int other_port = other_dp->index;

if (dp == other_dp)
continue;

/* Remove this port from the port matrix of the other ports
* in the same bridge. If the port is disabled, port matrix
* is kept and not being setup until the port becomes enabled.
*/
if (dsa_is_user_port(ds, i) && i != port) {
if (dsa_to_port(ds, i)->bridge_dev != bridge)
continue;
if (priv->ports[i].enable)
mt7530_clear(priv, MT7530_PCR_P(i),
PCR_MATRIX(BIT(port)));
priv->ports[i].pm &= ~PCR_MATRIX(BIT(port));
}
if (!dsa_port_offloads_bridge(other_dp, &bridge))
continue;

if (priv->ports[other_port].enable)
mt7530_clear(priv, MT7530_PCR_P(other_port),
PCR_MATRIX(BIT(port)));
priv->ports[other_port].pm &= ~PCR_MATRIX(BIT(port));
}

/* Set the cpu port to be the only one in the port matrix of
Loading

0 comments on commit 3a262c7

Please sign in to comment.