Commit 947c8746 authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Jakub Kicinski

net: dsa: assign a bridge number even without TX forwarding offload

The service where DSA assigns a unique bridge number for each forwarding
domain is useful even for drivers which do not implement the TX
forwarding offload feature.

For example, drivers might use the dp->bridge_num for FDB isolation.

So rename ds->num_fwd_offloading_bridges to ds->max_num_bridges, and
calculate a unique bridge_num for all drivers that set this value.
Signed-off-by: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Reviewed-by: default avatarAlvin Šipraga <alsi@bang-olufsen.dk>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 3f9bb030
...@@ -3186,8 +3186,8 @@ static int mv88e6xxx_setup(struct dsa_switch *ds) ...@@ -3186,8 +3186,8 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
* time. * time.
*/ */
if (mv88e6xxx_has_pvt(chip)) if (mv88e6xxx_has_pvt(chip))
ds->num_fwd_offloading_bridges = MV88E6XXX_MAX_PVT_SWITCHES - ds->max_num_bridges = MV88E6XXX_MAX_PVT_SWITCHES -
ds->dst->last_switch - 1; ds->dst->last_switch - 1;
mv88e6xxx_reg_lock(chip); mv88e6xxx_reg_lock(chip);
......
...@@ -3139,7 +3139,7 @@ static int sja1105_setup(struct dsa_switch *ds) ...@@ -3139,7 +3139,7 @@ static int sja1105_setup(struct dsa_switch *ds)
ds->vlan_filtering_is_global = true; ds->vlan_filtering_is_global = true;
ds->untag_bridge_pvid = true; ds->untag_bridge_pvid = true;
/* tag_8021q has 3 bits for the VBID, and the value 0 is reserved */ /* tag_8021q has 3 bits for the VBID, and the value 0 is reserved */
ds->num_fwd_offloading_bridges = 7; ds->max_num_bridges = 7;
/* Advertise the 8 egress queues */ /* Advertise the 8 egress queues */
ds->num_tx_queues = SJA1105_NUM_TC; ds->num_tx_queues = SJA1105_NUM_TC;
......
...@@ -413,12 +413,12 @@ struct dsa_switch { ...@@ -413,12 +413,12 @@ struct dsa_switch {
*/ */
unsigned int num_lag_ids; unsigned int num_lag_ids;
/* Drivers that support bridge forwarding offload should set this to /* Drivers that support bridge forwarding offload or FDB isolation
* the maximum number of bridges spanning the same switch tree (or all * should set this to the maximum number of bridges spanning the same
* trees, in the case of cross-tree bridging support) that can be * switch tree (or all trees, in the case of cross-tree bridging
* offloaded. * support) that can be offloaded.
*/ */
unsigned int num_fwd_offloading_bridges; unsigned int max_num_bridges;
size_t num_ports; size_t num_ports;
}; };
......
...@@ -152,7 +152,9 @@ unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max) ...@@ -152,7 +152,9 @@ unsigned int dsa_bridge_num_get(const struct net_device *bridge_dev, int max)
unsigned int bridge_num = dsa_bridge_num_find(bridge_dev); unsigned int bridge_num = dsa_bridge_num_find(bridge_dev);
if (!bridge_num) { if (!bridge_num) {
/* First port that offloads TX forwarding for this bridge */ /* First port that requests FDB isolation or TX forwarding
* offload for this bridge
*/
bridge_num = find_next_zero_bit(&dsa_fwd_offloading_bridges, bridge_num = find_next_zero_bit(&dsa_fwd_offloading_bridges,
DSA_MAX_NUM_OFFLOADING_BRIDGES, DSA_MAX_NUM_OFFLOADING_BRIDGES,
1); 1);
......
...@@ -271,19 +271,15 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp) ...@@ -271,19 +271,15 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
} }
static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp, static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp,
struct net_device *bridge_dev) struct net_device *bridge_dev,
unsigned int bridge_num)
{ {
unsigned int bridge_num = dp->bridge_num;
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
/* No bridge TX forwarding offload => do nothing */ /* No bridge TX forwarding offload => do nothing */
if (!ds->ops->port_bridge_tx_fwd_unoffload || !dp->bridge_num) if (!ds->ops->port_bridge_tx_fwd_unoffload || !bridge_num)
return; return;
dp->bridge_num = 0;
dsa_bridge_num_put(bridge_dev, bridge_num);
/* Notify the chips only once the offload has been deactivated, so /* Notify the chips only once the offload has been deactivated, so
* that they can update their configuration accordingly. * that they can update their configuration accordingly.
*/ */
...@@ -292,31 +288,60 @@ static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp, ...@@ -292,31 +288,60 @@ static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp,
} }
static bool dsa_port_bridge_tx_fwd_offload(struct dsa_port *dp, static bool dsa_port_bridge_tx_fwd_offload(struct dsa_port *dp,
struct net_device *bridge_dev) struct net_device *bridge_dev,
unsigned int bridge_num)
{ {
struct dsa_switch *ds = dp->ds; struct dsa_switch *ds = dp->ds;
unsigned int bridge_num;
int err; int err;
if (!ds->ops->port_bridge_tx_fwd_offload) /* FDB isolation is required for TX forwarding offload */
return false; if (!ds->ops->port_bridge_tx_fwd_offload || !bridge_num)
bridge_num = dsa_bridge_num_get(bridge_dev,
ds->num_fwd_offloading_bridges);
if (!bridge_num)
return false; return false;
dp->bridge_num = bridge_num;
/* Notify the driver */ /* Notify the driver */
err = ds->ops->port_bridge_tx_fwd_offload(ds, dp->index, bridge_dev, err = ds->ops->port_bridge_tx_fwd_offload(ds, dp->index, bridge_dev,
bridge_num); bridge_num);
if (err) {
dsa_port_bridge_tx_fwd_unoffload(dp, bridge_dev); return err ? false : true;
return false; }
static int dsa_port_bridge_create(struct dsa_port *dp,
struct net_device *br,
struct netlink_ext_ack *extack)
{
struct dsa_switch *ds = dp->ds;
unsigned int bridge_num;
dp->bridge_dev = br;
if (!ds->max_num_bridges)
return 0;
bridge_num = dsa_bridge_num_get(br, ds->max_num_bridges);
if (!bridge_num) {
NL_SET_ERR_MSG_MOD(extack,
"Range of offloadable bridges exceeded");
return -EOPNOTSUPP;
} }
return true; dp->bridge_num = bridge_num;
return 0;
}
static void dsa_port_bridge_destroy(struct dsa_port *dp,
const struct net_device *br)
{
struct dsa_switch *ds = dp->ds;
dp->bridge_dev = NULL;
if (ds->max_num_bridges) {
int bridge_num = dp->bridge_num;
dp->bridge_num = 0;
dsa_bridge_num_put(br, bridge_num);
}
} }
int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
...@@ -336,7 +361,9 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, ...@@ -336,7 +361,9 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
/* Here the interface is already bridged. Reflect the current /* Here the interface is already bridged. Reflect the current
* configuration so that drivers can program their chips accordingly. * configuration so that drivers can program their chips accordingly.
*/ */
dp->bridge_dev = br; err = dsa_port_bridge_create(dp, br, extack);
if (err)
return err;
brport_dev = dsa_port_to_bridge_port(dp); brport_dev = dsa_port_to_bridge_port(dp);
...@@ -344,7 +371,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, ...@@ -344,7 +371,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
if (err) if (err)
goto out_rollback; goto out_rollback;
tx_fwd_offload = dsa_port_bridge_tx_fwd_offload(dp, br); tx_fwd_offload = dsa_port_bridge_tx_fwd_offload(dp, br,
dp->bridge_num);
err = switchdev_bridge_port_offload(brport_dev, dev, dp, err = switchdev_bridge_port_offload(brport_dev, dev, dp,
&dsa_slave_switchdev_notifier, &dsa_slave_switchdev_notifier,
...@@ -366,7 +394,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br, ...@@ -366,7 +394,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
out_rollback_unbridge: out_rollback_unbridge:
dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info); dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
out_rollback: out_rollback:
dp->bridge_dev = NULL; dsa_port_bridge_destroy(dp, br);
return err; return err;
} }
...@@ -393,14 +421,15 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) ...@@ -393,14 +421,15 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
.port = dp->index, .port = dp->index,
.br = br, .br = br,
}; };
int bridge_num = dp->bridge_num;
int err; int err;
/* Here the port is already unbridged. Reflect the current configuration /* Here the port is already unbridged. Reflect the current configuration
* so that drivers can program their chips accordingly. * so that drivers can program their chips accordingly.
*/ */
dp->bridge_dev = NULL; dsa_port_bridge_destroy(dp, br);
dsa_port_bridge_tx_fwd_unoffload(dp, br); dsa_port_bridge_tx_fwd_unoffload(dp, br, bridge_num);
err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info); err = dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
if (err) if (err)
......
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