]> git.ipfire.org Git - thirdparty/kernel/stable.git/blobdiff - drivers/net/ethernet/mellanox/mlx5/core/fs_counters.c
net/mlx5: Change flow counters addlist type to single linked list
[thirdparty/kernel/stable.git] / drivers / net / ethernet / mellanox / mlx5 / core / fs_counters.c
index 58af6be13dfa88a2e08d5d85dd54b3fdaeb4e4f6..d996d6cf9e198a59e49c4e2f7b40f118a51af8ac 100644 (file)
@@ -52,7 +52,9 @@
  * access to counter list:
  * - create (user context)
  *   - mlx5_fc_create() only adds to an addlist to be used by
- *     mlx5_fc_stats_query_work(). addlist is protected by a spinlock.
+ *     mlx5_fc_stats_query_work(). addlist is a lockless single linked list
+ *     that doesn't require any additional synchronization when adding single
+ *     node.
  *   - spawn thread to do the actual destroy
  *
  * - destroy (user context)
@@ -156,28 +158,29 @@ out:
        return node;
 }
 
+static void mlx5_free_fc(struct mlx5_core_dev *dev,
+                        struct mlx5_fc *counter)
+{
+       mlx5_cmd_fc_free(dev, counter->id);
+       kfree(counter);
+}
+
 static void mlx5_fc_stats_work(struct work_struct *work)
 {
        struct mlx5_core_dev *dev = container_of(work, struct mlx5_core_dev,
                                                 priv.fc_stats.work.work);
        struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
+       struct llist_node *tmplist = llist_del_all(&fc_stats->addlist);
        unsigned long now = jiffies;
        struct mlx5_fc *counter = NULL;
        struct mlx5_fc *last = NULL;
        struct rb_node *node;
-       LIST_HEAD(tmplist);
-
-       spin_lock(&fc_stats->addlist_lock);
 
-       list_splice_tail_init(&fc_stats->addlist, &tmplist);
-
-       if (!list_empty(&tmplist) || !RB_EMPTY_ROOT(&fc_stats->counters))
+       if (tmplist || !RB_EMPTY_ROOT(&fc_stats->counters))
                queue_delayed_work(fc_stats->wq, &fc_stats->work,
                                   fc_stats->sampling_interval);
 
-       spin_unlock(&fc_stats->addlist_lock);
-
-       list_for_each_entry(counter, &tmplist, list)
+       llist_for_each_entry(counter, tmplist, addlist)
                mlx5_fc_stats_insert(&fc_stats->counters, counter);
 
        node = rb_first(&fc_stats->counters);
@@ -229,9 +232,7 @@ struct mlx5_fc *mlx5_fc_create(struct mlx5_core_dev *dev, bool aging)
                counter->cache.lastuse = jiffies;
                counter->aging = true;
 
-               spin_lock(&fc_stats->addlist_lock);
-               list_add(&counter->list, &fc_stats->addlist);
-               spin_unlock(&fc_stats->addlist_lock);
+               llist_add(&counter->addlist, &fc_stats->addlist);
 
                mod_delayed_work(fc_stats->wq, &fc_stats->work, 0);
        }
@@ -268,8 +269,7 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev)
        struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
 
        fc_stats->counters = RB_ROOT;
-       INIT_LIST_HEAD(&fc_stats->addlist);
-       spin_lock_init(&fc_stats->addlist_lock);
+       init_llist_head(&fc_stats->addlist);
 
        fc_stats->wq = create_singlethread_workqueue("mlx5_fc");
        if (!fc_stats->wq)
@@ -284,6 +284,7 @@ int mlx5_init_fc_stats(struct mlx5_core_dev *dev)
 void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev)
 {
        struct mlx5_fc_stats *fc_stats = &dev->priv.fc_stats;
+       struct llist_node *tmplist;
        struct mlx5_fc *counter;
        struct mlx5_fc *tmp;
        struct rb_node *node;
@@ -292,13 +293,9 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev)
        destroy_workqueue(dev->priv.fc_stats.wq);
        dev->priv.fc_stats.wq = NULL;
 
-       list_for_each_entry_safe(counter, tmp, &fc_stats->addlist, list) {
-               list_del(&counter->list);
-
-               mlx5_cmd_fc_free(dev, counter->id);
-
-               kfree(counter);
-       }
+       tmplist = llist_del_all(&fc_stats->addlist);
+       llist_for_each_entry_safe(counter, tmp, tmplist, addlist)
+               mlx5_free_fc(dev, counter);
 
        node = rb_first(&fc_stats->counters);
        while (node) {
@@ -308,9 +305,7 @@ void mlx5_cleanup_fc_stats(struct mlx5_core_dev *dev)
 
                rb_erase(&counter->node, &fc_stats->counters);
 
-               mlx5_cmd_fc_free(dev, counter->id);
-
-               kfree(counter);
+               mlx5_free_fc(dev, counter);
        }
 }