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

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
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3186,7 +3186,7 @@ static int mv88e6xxx_setup(struct dsa_switch *ds)
	 * time.
	 */
	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;

	mv88e6xxx_reg_lock(chip);
+1 −1
Original line number Diff line number Diff line
@@ -3139,7 +3139,7 @@ static int sja1105_setup(struct dsa_switch *ds)
	ds->vlan_filtering_is_global = true;
	ds->untag_bridge_pvid = true;
	/* 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 */
	ds->num_tx_queues = SJA1105_NUM_TC;
+5 −5
Original line number Diff line number Diff line
@@ -413,12 +413,12 @@ struct dsa_switch {
	 */
	unsigned int		num_lag_ids;

	/* Drivers that support bridge forwarding offload should set this to
	 * the maximum number of bridges spanning the same switch tree (or all
	 * trees, in the case of cross-tree bridging support) that can be
	 * offloaded.
	/* Drivers that support bridge forwarding offload or FDB isolation
	 * should set this to the maximum number of bridges spanning the same
	 * switch tree (or all trees, in the case of cross-tree bridging
	 * support) that can be offloaded.
	 */
	unsigned int		num_fwd_offloading_bridges;
	unsigned int		max_num_bridges;

	size_t num_ports;
};
+3 −1
Original line number Diff line number Diff line
@@ -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);

	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,
						DSA_MAX_NUM_OFFLOADING_BRIDGES,
						1);
+55 −26
Original line number Diff line number Diff line
@@ -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,
					     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;

	/* 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;

	dp->bridge_num = 0;

	dsa_bridge_num_put(bridge_dev, bridge_num);

	/* Notify the chips only once the offload has been deactivated, so
	 * that they can update their configuration accordingly.
	 */
@@ -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,
					   struct net_device *bridge_dev)
					   struct net_device *bridge_dev,
					   unsigned int bridge_num)
{
	struct dsa_switch *ds = dp->ds;
	unsigned int bridge_num;
	int err;

	if (!ds->ops->port_bridge_tx_fwd_offload)
		return false;

	bridge_num = dsa_bridge_num_get(bridge_dev,
					ds->num_fwd_offloading_bridges);
	if (!bridge_num)
	/* FDB isolation is required for TX forwarding offload */
	if (!ds->ops->port_bridge_tx_fwd_offload || !bridge_num)
		return false;

	dp->bridge_num = bridge_num;

	/* Notify the driver */
	err = ds->ops->port_bridge_tx_fwd_offload(ds, dp->index, bridge_dev,
						  bridge_num);
	if (err) {
		dsa_port_bridge_tx_fwd_unoffload(dp, bridge_dev);
		return false;

	return err ? false : true;
}

	return true;
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;
	}

	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,
@@ -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
	 * 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);

@@ -344,7 +371,8 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
	if (err)
		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,
					    &dsa_slave_switchdev_notifier,
@@ -366,7 +394,7 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br,
out_rollback_unbridge:
	dsa_broadcast(DSA_NOTIFIER_BRIDGE_LEAVE, &info);
out_rollback:
	dp->bridge_dev = NULL;
	dsa_port_bridge_destroy(dp, br);
	return err;
}

@@ -393,14 +421,15 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
		.port = dp->index,
		.br = br,
	};
	int bridge_num = dp->bridge_num;
	int err;

	/* Here the port is already unbridged. Reflect the current configuration
	 * 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);
	if (err)