Skip to content

Commit 04816dc

Browse files
committed
Merge branch 'mlxsw-various-acl-fixes'
Petr Machata says: ==================== mlxsw: Various ACL fixes Ido Schimmel writes: Fix various problems in the ACL (i.e., flower offload) code. See the commit messages for more details. ==================== Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Jakub Kicinski <[email protected]>
2 parents 5ea7b72 + fb4e2b7 commit 04816dc

File tree

2 files changed

+75
-45
lines changed

2 files changed

+75
-45
lines changed

drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <linux/netdevice.h>
1111
#include <linux/mutex.h>
1212
#include <linux/refcount.h>
13+
#include <linux/idr.h>
1314
#include <net/devlink.h>
1415
#include <trace/events/mlxsw.h>
1516

@@ -58,41 +59,43 @@ int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp,
5859
static int mlxsw_sp_acl_tcam_region_id_get(struct mlxsw_sp_acl_tcam *tcam,
5960
u16 *p_id)
6061
{
61-
u16 id;
62+
int id;
6263

63-
id = find_first_zero_bit(tcam->used_regions, tcam->max_regions);
64-
if (id < tcam->max_regions) {
65-
__set_bit(id, tcam->used_regions);
66-
*p_id = id;
67-
return 0;
68-
}
69-
return -ENOBUFS;
64+
id = ida_alloc_max(&tcam->used_regions, tcam->max_regions - 1,
65+
GFP_KERNEL);
66+
if (id < 0)
67+
return id;
68+
69+
*p_id = id;
70+
71+
return 0;
7072
}
7173

7274
static void mlxsw_sp_acl_tcam_region_id_put(struct mlxsw_sp_acl_tcam *tcam,
7375
u16 id)
7476
{
75-
__clear_bit(id, tcam->used_regions);
77+
ida_free(&tcam->used_regions, id);
7678
}
7779

7880
static int mlxsw_sp_acl_tcam_group_id_get(struct mlxsw_sp_acl_tcam *tcam,
7981
u16 *p_id)
8082
{
81-
u16 id;
83+
int id;
8284

83-
id = find_first_zero_bit(tcam->used_groups, tcam->max_groups);
84-
if (id < tcam->max_groups) {
85-
__set_bit(id, tcam->used_groups);
86-
*p_id = id;
87-
return 0;
88-
}
89-
return -ENOBUFS;
85+
id = ida_alloc_max(&tcam->used_groups, tcam->max_groups - 1,
86+
GFP_KERNEL);
87+
if (id < 0)
88+
return id;
89+
90+
*p_id = id;
91+
92+
return 0;
9093
}
9194

9295
static void mlxsw_sp_acl_tcam_group_id_put(struct mlxsw_sp_acl_tcam *tcam,
9396
u16 id)
9497
{
95-
__clear_bit(id, tcam->used_groups);
98+
ida_free(&tcam->used_groups, id);
9699
}
97100

98101
struct mlxsw_sp_acl_tcam_pattern {
@@ -715,7 +718,9 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
715718
rehash.dw.work);
716719
int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS;
717720

721+
mutex_lock(&vregion->lock);
718722
mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion, &credits);
723+
mutex_unlock(&vregion->lock);
719724
if (credits < 0)
720725
/* Rehash gone out of credits so it was interrupted.
721726
* Schedule the work as soon as possible to continue.
@@ -725,6 +730,17 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
725730
mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion);
726731
}
727732

733+
static void
734+
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
735+
{
736+
/* The entry markers are relative to the current chunk and therefore
737+
* needs to be reset together with the chunk marker.
738+
*/
739+
ctx->current_vchunk = NULL;
740+
ctx->start_ventry = NULL;
741+
ctx->stop_ventry = NULL;
742+
}
743+
728744
static void
729745
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(struct mlxsw_sp_acl_tcam_vchunk *vchunk)
730746
{
@@ -747,7 +763,7 @@ mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(struct mlxsw_sp_acl_tcam_vregion *v
747763
* the current chunk pointer to make sure all chunks
748764
* are properly migrated.
749765
*/
750-
vregion->rehash.ctx.current_vchunk = NULL;
766+
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(&vregion->rehash.ctx);
751767
}
752768

753769
static struct mlxsw_sp_acl_tcam_vregion *
@@ -820,10 +836,14 @@ mlxsw_sp_acl_tcam_vregion_destroy(struct mlxsw_sp *mlxsw_sp,
820836
struct mlxsw_sp_acl_tcam *tcam = vregion->tcam;
821837

822838
if (vgroup->vregion_rehash_enabled && ops->region_rehash_hints_get) {
839+
struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx;
840+
823841
mutex_lock(&tcam->lock);
824842
list_del(&vregion->tlist);
825843
mutex_unlock(&tcam->lock);
826-
cancel_delayed_work_sync(&vregion->rehash.dw);
844+
if (cancel_delayed_work_sync(&vregion->rehash.dw) &&
845+
ctx->hints_priv)
846+
ops->region_rehash_hints_put(ctx->hints_priv);
827847
}
828848
mlxsw_sp_acl_tcam_vgroup_vregion_detach(mlxsw_sp, vregion);
829849
if (vregion->region2)
@@ -1154,8 +1174,14 @@ mlxsw_sp_acl_tcam_ventry_activity_get(struct mlxsw_sp *mlxsw_sp,
11541174
struct mlxsw_sp_acl_tcam_ventry *ventry,
11551175
bool *activity)
11561176
{
1157-
return mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp,
1158-
ventry->entry, activity);
1177+
struct mlxsw_sp_acl_tcam_vregion *vregion = ventry->vchunk->vregion;
1178+
int err;
1179+
1180+
mutex_lock(&vregion->lock);
1181+
err = mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp, ventry->entry,
1182+
activity);
1183+
mutex_unlock(&vregion->lock);
1184+
return err;
11591185
}
11601186

11611187
static int
@@ -1189,6 +1215,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_start(struct mlxsw_sp *mlxsw_sp,
11891215
{
11901216
struct mlxsw_sp_acl_tcam_chunk *new_chunk;
11911217

1218+
WARN_ON(vchunk->chunk2);
1219+
11921220
new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
11931221
if (IS_ERR(new_chunk))
11941222
return PTR_ERR(new_chunk);
@@ -1207,7 +1235,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_end(struct mlxsw_sp *mlxsw_sp,
12071235
{
12081236
mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
12091237
vchunk->chunk2 = NULL;
1210-
ctx->current_vchunk = NULL;
1238+
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
12111239
}
12121240

12131241
static int
@@ -1230,6 +1258,9 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
12301258
return 0;
12311259
}
12321260

1261+
if (list_empty(&vchunk->ventry_list))
1262+
goto out;
1263+
12331264
/* If the migration got interrupted, we have the ventry to start from
12341265
* stored in context.
12351266
*/
@@ -1239,6 +1270,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
12391270
ventry = list_first_entry(&vchunk->ventry_list,
12401271
typeof(*ventry), list);
12411272

1273+
WARN_ON(ventry->vchunk != vchunk);
1274+
12421275
list_for_each_entry_from(ventry, &vchunk->ventry_list, list) {
12431276
/* During rollback, once we reach the ventry that failed
12441277
* to migrate, we are done.
@@ -1279,6 +1312,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
12791312
}
12801313
}
12811314

1315+
out:
12821316
mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk, ctx);
12831317
return 0;
12841318
}
@@ -1292,6 +1326,9 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
12921326
struct mlxsw_sp_acl_tcam_vchunk *vchunk;
12931327
int err;
12941328

1329+
if (list_empty(&vregion->vchunk_list))
1330+
return 0;
1331+
12951332
/* If the migration got interrupted, we have the vchunk
12961333
* we are working on stored in context.
12971334
*/
@@ -1320,16 +1357,17 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
13201357
int err, err2;
13211358

13221359
trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
1323-
mutex_lock(&vregion->lock);
13241360
err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
13251361
ctx, credits);
13261362
if (err) {
1363+
if (ctx->this_is_rollback)
1364+
return err;
13271365
/* In case migration was not successful, we need to swap
13281366
* so the original region pointer is assigned again
13291367
* to vregion->region.
13301368
*/
13311369
swap(vregion->region, vregion->region2);
1332-
ctx->current_vchunk = NULL;
1370+
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
13331371
ctx->this_is_rollback = true;
13341372
err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
13351373
ctx, credits);
@@ -1340,7 +1378,6 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
13401378
/* Let the rollback to be continued later on. */
13411379
}
13421380
}
1343-
mutex_unlock(&vregion->lock);
13441381
trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
13451382
return err;
13461383
}
@@ -1389,6 +1426,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
13891426

13901427
ctx->hints_priv = hints_priv;
13911428
ctx->this_is_rollback = false;
1429+
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
13921430

13931431
return 0;
13941432

@@ -1441,7 +1479,8 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
14411479
err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion,
14421480
ctx, credits);
14431481
if (err) {
1444-
dev_err(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n");
1482+
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n");
1483+
return;
14451484
}
14461485

14471486
if (*credits >= 0)
@@ -1549,19 +1588,11 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
15491588
if (max_tcam_regions < max_regions)
15501589
max_regions = max_tcam_regions;
15511590

1552-
tcam->used_regions = bitmap_zalloc(max_regions, GFP_KERNEL);
1553-
if (!tcam->used_regions) {
1554-
err = -ENOMEM;
1555-
goto err_alloc_used_regions;
1556-
}
1591+
ida_init(&tcam->used_regions);
15571592
tcam->max_regions = max_regions;
15581593

15591594
max_groups = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_GROUPS);
1560-
tcam->used_groups = bitmap_zalloc(max_groups, GFP_KERNEL);
1561-
if (!tcam->used_groups) {
1562-
err = -ENOMEM;
1563-
goto err_alloc_used_groups;
1564-
}
1595+
ida_init(&tcam->used_groups);
15651596
tcam->max_groups = max_groups;
15661597
tcam->max_group_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
15671598
ACL_MAX_GROUP_SIZE);
@@ -1575,10 +1606,8 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
15751606
return 0;
15761607

15771608
err_tcam_init:
1578-
bitmap_free(tcam->used_groups);
1579-
err_alloc_used_groups:
1580-
bitmap_free(tcam->used_regions);
1581-
err_alloc_used_regions:
1609+
ida_destroy(&tcam->used_groups);
1610+
ida_destroy(&tcam->used_regions);
15821611
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
15831612
err_rehash_params_register:
15841613
mutex_destroy(&tcam->lock);
@@ -1591,8 +1620,8 @@ void mlxsw_sp_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp,
15911620
const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
15921621

15931622
ops->fini(mlxsw_sp, tcam->priv);
1594-
bitmap_free(tcam->used_groups);
1595-
bitmap_free(tcam->used_regions);
1623+
ida_destroy(&tcam->used_groups);
1624+
ida_destroy(&tcam->used_regions);
15961625
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
15971626
mutex_destroy(&tcam->lock);
15981627
}

drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@
66

77
#include <linux/list.h>
88
#include <linux/parman.h>
9+
#include <linux/idr.h>
910

1011
#include "reg.h"
1112
#include "spectrum.h"
1213
#include "core_acl_flex_keys.h"
1314

1415
struct mlxsw_sp_acl_tcam {
15-
unsigned long *used_regions; /* bit array */
16+
struct ida used_regions;
1617
unsigned int max_regions;
17-
unsigned long *used_groups; /* bit array */
18+
struct ida used_groups;
1819
unsigned int max_groups;
1920
unsigned int max_group_size;
2021
struct mutex lock; /* guards vregion list */

0 commit comments

Comments
 (0)