summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/net/dsa.h8
-rw-r--r--net/dsa/dsa2.c48
-rw-r--r--net/dsa/dsa_priv.h2
-rw-r--r--net/dsa/port.c39
4 files changed, 58 insertions, 39 deletions
diff --git a/include/net/dsa.h b/include/net/dsa.h
index 0c2cba45fa79..c7ea0f61056f 100644
--- a/include/net/dsa.h
+++ b/include/net/dsa.h
@@ -155,9 +155,6 @@ struct dsa_switch_tree {
/* Track the largest switch index within a tree */
unsigned int last_switch;
-
- /* Track the bridges with forwarding offload enabled */
- unsigned long fwd_offloading_bridges;
};
#define dsa_lags_foreach_id(_id, _dst) \
@@ -411,8 +408,9 @@ 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 that can
- * be offloaded.
+ * 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;
diff --git a/net/dsa/dsa2.c b/net/dsa/dsa2.c
index dcd67801eca4..1b2b25d7bd02 100644
--- a/net/dsa/dsa2.c
+++ b/net/dsa/dsa2.c
@@ -21,6 +21,9 @@
static DEFINE_MUTEX(dsa2_mutex);
LIST_HEAD(dsa_tree_list);
+/* Track the bridges with forwarding offload enabled */
+static unsigned long dsa_fwd_offloading_bridges;
+
/**
* dsa_tree_notify - Execute code for all switches in a DSA switch tree.
* @dst: collection of struct dsa_switch devices to notify.
@@ -126,6 +129,51 @@ void dsa_lag_unmap(struct dsa_switch_tree *dst, struct net_device *lag)
}
}
+static int dsa_bridge_num_find(const struct net_device *bridge_dev)
+{
+ struct dsa_switch_tree *dst;
+ struct dsa_port *dp;
+
+ /* When preparing the offload for a port, it will have a valid
+ * dp->bridge_dev pointer but a not yet valid dp->bridge_num.
+ * However there might be other ports having the same dp->bridge_dev
+ * and a valid dp->bridge_num, so just ignore this port.
+ */
+ list_for_each_entry(dst, &dsa_tree_list, list)
+ list_for_each_entry(dp, &dst->ports, list)
+ if (dp->bridge_dev == bridge_dev &&
+ dp->bridge_num != -1)
+ return dp->bridge_num;
+
+ return -1;
+}
+
+int dsa_bridge_num_get(const struct net_device *bridge_dev, int max)
+{
+ int bridge_num = dsa_bridge_num_find(bridge_dev);
+
+ if (bridge_num < 0) {
+ /* First port that offloads TX forwarding for this bridge */
+ bridge_num = find_first_zero_bit(&dsa_fwd_offloading_bridges,
+ DSA_MAX_NUM_OFFLOADING_BRIDGES);
+ if (bridge_num >= max)
+ return -1;
+
+ set_bit(bridge_num, &dsa_fwd_offloading_bridges);
+ }
+
+ return bridge_num;
+}
+
+void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num)
+{
+ /* Check if the bridge is still in use, otherwise it is time
+ * to clean it up so we can reuse this bridge_num later.
+ */
+ if (!dsa_bridge_num_find(bridge_dev))
+ clear_bit(bridge_num, &dsa_fwd_offloading_bridges);
+}
+
struct dsa_switch *dsa_switch_find(int tree_index, int sw_index)
{
struct dsa_switch_tree *dst;
diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h
index b7a269e0513f..88aaf43b2da4 100644
--- a/net/dsa/dsa_priv.h
+++ b/net/dsa/dsa_priv.h
@@ -543,6 +543,8 @@ int dsa_tree_change_tag_proto(struct dsa_switch_tree *dst,
struct net_device *master,
const struct dsa_device_ops *tag_ops,
const struct dsa_device_ops *old_tag_ops);
+int dsa_bridge_num_get(const struct net_device *bridge_dev, int max);
+void dsa_bridge_num_put(const struct net_device *bridge_dev, int bridge_num);
/* tag_8021q.c */
int dsa_tag_8021q_bridge_join(struct dsa_switch *ds,
diff --git a/net/dsa/port.c b/net/dsa/port.c
index 979042a64d1a..4fbe81ffb1ce 100644
--- a/net/dsa/port.c
+++ b/net/dsa/port.c
@@ -270,27 +270,9 @@ static void dsa_port_switchdev_unsync_attrs(struct dsa_port *dp)
*/
}
-static int dsa_tree_find_bridge_num(struct dsa_switch_tree *dst,
- struct net_device *bridge_dev)
-{
- struct dsa_port *dp;
-
- /* When preparing the offload for a port, it will have a valid
- * dp->bridge_dev pointer but a not yet valid dp->bridge_num.
- * However there might be other ports having the same dp->bridge_dev
- * and a valid dp->bridge_num, so just ignore this port.
- */
- list_for_each_entry(dp, &dst->ports, list)
- if (dp->bridge_dev == bridge_dev && dp->bridge_num != -1)
- return dp->bridge_num;
-
- return -1;
-}
-
static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp,
struct net_device *bridge_dev)
{
- struct dsa_switch_tree *dst = dp->ds->dst;
int bridge_num = dp->bridge_num;
struct dsa_switch *ds = dp->ds;
@@ -300,11 +282,7 @@ static void dsa_port_bridge_tx_fwd_unoffload(struct dsa_port *dp,
dp->bridge_num = -1;
- /* Check if the bridge is still in use, otherwise it is time
- * to clean it up so we can reuse this bridge_num later.
- */
- if (!dsa_tree_find_bridge_num(dst, bridge_dev))
- clear_bit(bridge_num, &dst->fwd_offloading_bridges);
+ 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.
@@ -316,23 +294,16 @@ 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 dsa_switch_tree *dst = dp->ds->dst;
struct dsa_switch *ds = dp->ds;
int bridge_num, err;
if (!ds->ops->port_bridge_tx_fwd_offload)
return false;
- bridge_num = dsa_tree_find_bridge_num(dst, bridge_dev);
- if (bridge_num < 0) {
- /* First port that offloads TX forwarding for this bridge */
- bridge_num = find_first_zero_bit(&dst->fwd_offloading_bridges,
- DSA_MAX_NUM_OFFLOADING_BRIDGES);
- if (bridge_num >= ds->num_fwd_offloading_bridges)
- return false;
-
- set_bit(bridge_num, &dst->fwd_offloading_bridges);
- }
+ bridge_num = dsa_bridge_num_get(bridge_dev,
+ ds->num_fwd_offloading_bridges);
+ if (bridge_num < 0)
+ return false;
dp->bridge_num = bridge_num;