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/cover.1713797103.git.petrm@nvidia.com Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
04816dc9b9
@ -10,6 +10,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/refcount.h>
|
||||
#include <linux/idr.h>
|
||||
#include <net/devlink.h>
|
||||
#include <trace/events/mlxsw.h>
|
||||
|
||||
@ -58,41 +59,43 @@ int mlxsw_sp_acl_tcam_priority_get(struct mlxsw_sp *mlxsw_sp,
|
||||
static int mlxsw_sp_acl_tcam_region_id_get(struct mlxsw_sp_acl_tcam *tcam,
|
||||
u16 *p_id)
|
||||
{
|
||||
u16 id;
|
||||
int id;
|
||||
|
||||
id = find_first_zero_bit(tcam->used_regions, tcam->max_regions);
|
||||
if (id < tcam->max_regions) {
|
||||
__set_bit(id, tcam->used_regions);
|
||||
*p_id = id;
|
||||
return 0;
|
||||
}
|
||||
return -ENOBUFS;
|
||||
id = ida_alloc_max(&tcam->used_regions, tcam->max_regions - 1,
|
||||
GFP_KERNEL);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
*p_id = id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_acl_tcam_region_id_put(struct mlxsw_sp_acl_tcam *tcam,
|
||||
u16 id)
|
||||
{
|
||||
__clear_bit(id, tcam->used_regions);
|
||||
ida_free(&tcam->used_regions, id);
|
||||
}
|
||||
|
||||
static int mlxsw_sp_acl_tcam_group_id_get(struct mlxsw_sp_acl_tcam *tcam,
|
||||
u16 *p_id)
|
||||
{
|
||||
u16 id;
|
||||
int id;
|
||||
|
||||
id = find_first_zero_bit(tcam->used_groups, tcam->max_groups);
|
||||
if (id < tcam->max_groups) {
|
||||
__set_bit(id, tcam->used_groups);
|
||||
*p_id = id;
|
||||
return 0;
|
||||
}
|
||||
return -ENOBUFS;
|
||||
id = ida_alloc_max(&tcam->used_groups, tcam->max_groups - 1,
|
||||
GFP_KERNEL);
|
||||
if (id < 0)
|
||||
return id;
|
||||
|
||||
*p_id = id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mlxsw_sp_acl_tcam_group_id_put(struct mlxsw_sp_acl_tcam *tcam,
|
||||
u16 id)
|
||||
{
|
||||
__clear_bit(id, tcam->used_groups);
|
||||
ida_free(&tcam->used_groups, id);
|
||||
}
|
||||
|
||||
struct mlxsw_sp_acl_tcam_pattern {
|
||||
@ -715,7 +718,9 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work)
|
||||
rehash.dw.work);
|
||||
int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS;
|
||||
|
||||
mutex_lock(&vregion->lock);
|
||||
mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion, &credits);
|
||||
mutex_unlock(&vregion->lock);
|
||||
if (credits < 0)
|
||||
/* Rehash gone out of credits so it was interrupted.
|
||||
* 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)
|
||||
mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion);
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(struct mlxsw_sp_acl_tcam_rehash_ctx *ctx)
|
||||
{
|
||||
/* The entry markers are relative to the current chunk and therefore
|
||||
* needs to be reset together with the chunk marker.
|
||||
*/
|
||||
ctx->current_vchunk = NULL;
|
||||
ctx->start_ventry = NULL;
|
||||
ctx->stop_ventry = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(struct mlxsw_sp_acl_tcam_vchunk *vchunk)
|
||||
{
|
||||
@ -747,7 +763,7 @@ mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(struct mlxsw_sp_acl_tcam_vregion *v
|
||||
* the current chunk pointer to make sure all chunks
|
||||
* are properly migrated.
|
||||
*/
|
||||
vregion->rehash.ctx.current_vchunk = NULL;
|
||||
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(&vregion->rehash.ctx);
|
||||
}
|
||||
|
||||
static struct mlxsw_sp_acl_tcam_vregion *
|
||||
@ -820,10 +836,14 @@ mlxsw_sp_acl_tcam_vregion_destroy(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam *tcam = vregion->tcam;
|
||||
|
||||
if (vgroup->vregion_rehash_enabled && ops->region_rehash_hints_get) {
|
||||
struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx;
|
||||
|
||||
mutex_lock(&tcam->lock);
|
||||
list_del(&vregion->tlist);
|
||||
mutex_unlock(&tcam->lock);
|
||||
cancel_delayed_work_sync(&vregion->rehash.dw);
|
||||
if (cancel_delayed_work_sync(&vregion->rehash.dw) &&
|
||||
ctx->hints_priv)
|
||||
ops->region_rehash_hints_put(ctx->hints_priv);
|
||||
}
|
||||
mlxsw_sp_acl_tcam_vgroup_vregion_detach(mlxsw_sp, vregion);
|
||||
if (vregion->region2)
|
||||
@ -1154,8 +1174,14 @@ mlxsw_sp_acl_tcam_ventry_activity_get(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam_ventry *ventry,
|
||||
bool *activity)
|
||||
{
|
||||
return mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp,
|
||||
ventry->entry, activity);
|
||||
struct mlxsw_sp_acl_tcam_vregion *vregion = ventry->vchunk->vregion;
|
||||
int err;
|
||||
|
||||
mutex_lock(&vregion->lock);
|
||||
err = mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp, ventry->entry,
|
||||
activity);
|
||||
mutex_unlock(&vregion->lock);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1189,6 +1215,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_start(struct mlxsw_sp *mlxsw_sp,
|
||||
{
|
||||
struct mlxsw_sp_acl_tcam_chunk *new_chunk;
|
||||
|
||||
WARN_ON(vchunk->chunk2);
|
||||
|
||||
new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
|
||||
if (IS_ERR(new_chunk))
|
||||
return PTR_ERR(new_chunk);
|
||||
@ -1207,7 +1235,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_end(struct mlxsw_sp *mlxsw_sp,
|
||||
{
|
||||
mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
|
||||
vchunk->chunk2 = NULL;
|
||||
ctx->current_vchunk = NULL;
|
||||
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
|
||||
}
|
||||
|
||||
static int
|
||||
@ -1230,6 +1258,9 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (list_empty(&vchunk->ventry_list))
|
||||
goto out;
|
||||
|
||||
/* If the migration got interrupted, we have the ventry to start from
|
||||
* stored in context.
|
||||
*/
|
||||
@ -1239,6 +1270,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
|
||||
ventry = list_first_entry(&vchunk->ventry_list,
|
||||
typeof(*ventry), list);
|
||||
|
||||
WARN_ON(ventry->vchunk != vchunk);
|
||||
|
||||
list_for_each_entry_from(ventry, &vchunk->ventry_list, list) {
|
||||
/* During rollback, once we reach the ventry that failed
|
||||
* to migrate, we are done.
|
||||
@ -1279,6 +1312,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk, ctx);
|
||||
return 0;
|
||||
}
|
||||
@ -1292,6 +1326,9 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp,
|
||||
struct mlxsw_sp_acl_tcam_vchunk *vchunk;
|
||||
int err;
|
||||
|
||||
if (list_empty(&vregion->vchunk_list))
|
||||
return 0;
|
||||
|
||||
/* If the migration got interrupted, we have the vchunk
|
||||
* we are working on stored in context.
|
||||
*/
|
||||
@ -1320,16 +1357,17 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
|
||||
int err, err2;
|
||||
|
||||
trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
|
||||
mutex_lock(&vregion->lock);
|
||||
err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
|
||||
ctx, credits);
|
||||
if (err) {
|
||||
if (ctx->this_is_rollback)
|
||||
return err;
|
||||
/* In case migration was not successful, we need to swap
|
||||
* so the original region pointer is assigned again
|
||||
* to vregion->region.
|
||||
*/
|
||||
swap(vregion->region, vregion->region2);
|
||||
ctx->current_vchunk = NULL;
|
||||
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
|
||||
ctx->this_is_rollback = true;
|
||||
err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
|
||||
ctx, credits);
|
||||
@ -1340,7 +1378,6 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp,
|
||||
/* Let the rollback to be continued later on. */
|
||||
}
|
||||
}
|
||||
mutex_unlock(&vregion->lock);
|
||||
trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
|
||||
return err;
|
||||
}
|
||||
@ -1389,6 +1426,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
|
||||
|
||||
ctx->hints_priv = hints_priv;
|
||||
ctx->this_is_rollback = false;
|
||||
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
|
||||
|
||||
return 0;
|
||||
|
||||
@ -1441,7 +1479,8 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp,
|
||||
err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion,
|
||||
ctx, credits);
|
||||
if (err) {
|
||||
dev_err(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n");
|
||||
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (*credits >= 0)
|
||||
@ -1549,19 +1588,11 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
|
||||
if (max_tcam_regions < max_regions)
|
||||
max_regions = max_tcam_regions;
|
||||
|
||||
tcam->used_regions = bitmap_zalloc(max_regions, GFP_KERNEL);
|
||||
if (!tcam->used_regions) {
|
||||
err = -ENOMEM;
|
||||
goto err_alloc_used_regions;
|
||||
}
|
||||
ida_init(&tcam->used_regions);
|
||||
tcam->max_regions = max_regions;
|
||||
|
||||
max_groups = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_GROUPS);
|
||||
tcam->used_groups = bitmap_zalloc(max_groups, GFP_KERNEL);
|
||||
if (!tcam->used_groups) {
|
||||
err = -ENOMEM;
|
||||
goto err_alloc_used_groups;
|
||||
}
|
||||
ida_init(&tcam->used_groups);
|
||||
tcam->max_groups = max_groups;
|
||||
tcam->max_group_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
|
||||
ACL_MAX_GROUP_SIZE);
|
||||
@ -1575,10 +1606,8 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
|
||||
return 0;
|
||||
|
||||
err_tcam_init:
|
||||
bitmap_free(tcam->used_groups);
|
||||
err_alloc_used_groups:
|
||||
bitmap_free(tcam->used_regions);
|
||||
err_alloc_used_regions:
|
||||
ida_destroy(&tcam->used_groups);
|
||||
ida_destroy(&tcam->used_regions);
|
||||
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
|
||||
err_rehash_params_register:
|
||||
mutex_destroy(&tcam->lock);
|
||||
@ -1591,8 +1620,8 @@ void mlxsw_sp_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp,
|
||||
const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
|
||||
|
||||
ops->fini(mlxsw_sp, tcam->priv);
|
||||
bitmap_free(tcam->used_groups);
|
||||
bitmap_free(tcam->used_regions);
|
||||
ida_destroy(&tcam->used_groups);
|
||||
ida_destroy(&tcam->used_regions);
|
||||
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
|
||||
mutex_destroy(&tcam->lock);
|
||||
}
|
||||
|
@ -6,15 +6,16 @@
|
||||
|
||||
#include <linux/list.h>
|
||||
#include <linux/parman.h>
|
||||
#include <linux/idr.h>
|
||||
|
||||
#include "reg.h"
|
||||
#include "spectrum.h"
|
||||
#include "core_acl_flex_keys.h"
|
||||
|
||||
struct mlxsw_sp_acl_tcam {
|
||||
unsigned long *used_regions; /* bit array */
|
||||
struct ida used_regions;
|
||||
unsigned int max_regions;
|
||||
unsigned long *used_groups; /* bit array */
|
||||
struct ida used_groups;
|
||||
unsigned int max_groups;
|
||||
unsigned int max_group_size;
|
||||
struct mutex lock; /* guards vregion list */
|
||||
|
Loading…
Reference in New Issue
Block a user