net: dsa: track unique bridge numbers across all DSA switch trees
[linux-2.6-microblaze.git] / net / dsa / dsa2.c
index dcd6780..1b2b25d 100644 (file)
@@ -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;