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/netdevice.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/refcount.h>
|
#include <linux/refcount.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
#include <net/devlink.h>
|
#include <net/devlink.h>
|
||||||
#include <trace/events/mlxsw.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,
|
static int mlxsw_sp_acl_tcam_region_id_get(struct mlxsw_sp_acl_tcam *tcam,
|
||||||
u16 *p_id)
|
u16 *p_id)
|
||||||
{
|
{
|
||||||
u16 id;
|
int id;
|
||||||
|
|
||||||
id = find_first_zero_bit(tcam->used_regions, tcam->max_regions);
|
id = ida_alloc_max(&tcam->used_regions, tcam->max_regions - 1,
|
||||||
if (id < tcam->max_regions) {
|
GFP_KERNEL);
|
||||||
__set_bit(id, tcam->used_regions);
|
if (id < 0)
|
||||||
*p_id = id;
|
return id;
|
||||||
return 0;
|
|
||||||
}
|
*p_id = id;
|
||||||
return -ENOBUFS;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlxsw_sp_acl_tcam_region_id_put(struct mlxsw_sp_acl_tcam *tcam,
|
static void mlxsw_sp_acl_tcam_region_id_put(struct mlxsw_sp_acl_tcam *tcam,
|
||||||
u16 id)
|
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,
|
static int mlxsw_sp_acl_tcam_group_id_get(struct mlxsw_sp_acl_tcam *tcam,
|
||||||
u16 *p_id)
|
u16 *p_id)
|
||||||
{
|
{
|
||||||
u16 id;
|
int id;
|
||||||
|
|
||||||
id = find_first_zero_bit(tcam->used_groups, tcam->max_groups);
|
id = ida_alloc_max(&tcam->used_groups, tcam->max_groups - 1,
|
||||||
if (id < tcam->max_groups) {
|
GFP_KERNEL);
|
||||||
__set_bit(id, tcam->used_groups);
|
if (id < 0)
|
||||||
*p_id = id;
|
return id;
|
||||||
return 0;
|
|
||||||
}
|
*p_id = id;
|
||||||
return -ENOBUFS;
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mlxsw_sp_acl_tcam_group_id_put(struct mlxsw_sp_acl_tcam *tcam,
|
static void mlxsw_sp_acl_tcam_group_id_put(struct mlxsw_sp_acl_tcam *tcam,
|
||||||
u16 id)
|
u16 id)
|
||||||
{
|
{
|
||||||
__clear_bit(id, tcam->used_groups);
|
ida_free(&tcam->used_groups, id);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct mlxsw_sp_acl_tcam_pattern {
|
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);
|
rehash.dw.work);
|
||||||
int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS;
|
int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS;
|
||||||
|
|
||||||
|
mutex_lock(&vregion->lock);
|
||||||
mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion, &credits);
|
mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion, &credits);
|
||||||
|
mutex_unlock(&vregion->lock);
|
||||||
if (credits < 0)
|
if (credits < 0)
|
||||||
/* Rehash gone out of credits so it was interrupted.
|
/* Rehash gone out of credits so it was interrupted.
|
||||||
* Schedule the work as soon as possible to continue.
|
* 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);
|
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
|
static void
|
||||||
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(struct mlxsw_sp_acl_tcam_vchunk *vchunk)
|
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
|
* the current chunk pointer to make sure all chunks
|
||||||
* are properly migrated.
|
* 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 *
|
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;
|
struct mlxsw_sp_acl_tcam *tcam = vregion->tcam;
|
||||||
|
|
||||||
if (vgroup->vregion_rehash_enabled && ops->region_rehash_hints_get) {
|
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);
|
mutex_lock(&tcam->lock);
|
||||||
list_del(&vregion->tlist);
|
list_del(&vregion->tlist);
|
||||||
mutex_unlock(&tcam->lock);
|
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);
|
mlxsw_sp_acl_tcam_vgroup_vregion_detach(mlxsw_sp, vregion);
|
||||||
if (vregion->region2)
|
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,
|
struct mlxsw_sp_acl_tcam_ventry *ventry,
|
||||||
bool *activity)
|
bool *activity)
|
||||||
{
|
{
|
||||||
return mlxsw_sp_acl_tcam_entry_activity_get(mlxsw_sp,
|
struct mlxsw_sp_acl_tcam_vregion *vregion = ventry->vchunk->vregion;
|
||||||
ventry->entry, activity);
|
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
|
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;
|
struct mlxsw_sp_acl_tcam_chunk *new_chunk;
|
||||||
|
|
||||||
|
WARN_ON(vchunk->chunk2);
|
||||||
|
|
||||||
new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
|
new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region);
|
||||||
if (IS_ERR(new_chunk))
|
if (IS_ERR(new_chunk))
|
||||||
return PTR_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);
|
mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2);
|
||||||
vchunk->chunk2 = NULL;
|
vchunk->chunk2 = NULL;
|
||||||
ctx->current_vchunk = NULL;
|
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1230,6 +1258,9 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (list_empty(&vchunk->ventry_list))
|
||||||
|
goto out;
|
||||||
|
|
||||||
/* If the migration got interrupted, we have the ventry to start from
|
/* If the migration got interrupted, we have the ventry to start from
|
||||||
* stored in context.
|
* 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,
|
ventry = list_first_entry(&vchunk->ventry_list,
|
||||||
typeof(*ventry), list);
|
typeof(*ventry), list);
|
||||||
|
|
||||||
|
WARN_ON(ventry->vchunk != vchunk);
|
||||||
|
|
||||||
list_for_each_entry_from(ventry, &vchunk->ventry_list, list) {
|
list_for_each_entry_from(ventry, &vchunk->ventry_list, list) {
|
||||||
/* During rollback, once we reach the ventry that failed
|
/* During rollback, once we reach the ventry that failed
|
||||||
* to migrate, we are done.
|
* 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);
|
mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk, ctx);
|
||||||
return 0;
|
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;
|
struct mlxsw_sp_acl_tcam_vchunk *vchunk;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (list_empty(&vregion->vchunk_list))
|
||||||
|
return 0;
|
||||||
|
|
||||||
/* If the migration got interrupted, we have the vchunk
|
/* If the migration got interrupted, we have the vchunk
|
||||||
* we are working on stored in context.
|
* 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;
|
int err, err2;
|
||||||
|
|
||||||
trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion);
|
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,
|
err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
|
||||||
ctx, credits);
|
ctx, credits);
|
||||||
if (err) {
|
if (err) {
|
||||||
|
if (ctx->this_is_rollback)
|
||||||
|
return err;
|
||||||
/* In case migration was not successful, we need to swap
|
/* In case migration was not successful, we need to swap
|
||||||
* so the original region pointer is assigned again
|
* so the original region pointer is assigned again
|
||||||
* to vregion->region.
|
* to vregion->region.
|
||||||
*/
|
*/
|
||||||
swap(vregion->region, vregion->region2);
|
swap(vregion->region, vregion->region2);
|
||||||
ctx->current_vchunk = NULL;
|
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
|
||||||
ctx->this_is_rollback = true;
|
ctx->this_is_rollback = true;
|
||||||
err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
|
err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion,
|
||||||
ctx, credits);
|
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. */
|
/* Let the rollback to be continued later on. */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mutex_unlock(&vregion->lock);
|
|
||||||
trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
|
trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -1389,6 +1426,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp,
|
||||||
|
|
||||||
ctx->hints_priv = hints_priv;
|
ctx->hints_priv = hints_priv;
|
||||||
ctx->this_is_rollback = false;
|
ctx->this_is_rollback = false;
|
||||||
|
mlxsw_sp_acl_tcam_rehash_ctx_vchunk_reset(ctx);
|
||||||
|
|
||||||
return 0;
|
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,
|
err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion,
|
||||||
ctx, credits);
|
ctx, credits);
|
||||||
if (err) {
|
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)
|
if (*credits >= 0)
|
||||||
|
@ -1549,19 +1588,11 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
|
||||||
if (max_tcam_regions < max_regions)
|
if (max_tcam_regions < max_regions)
|
||||||
max_regions = max_tcam_regions;
|
max_regions = max_tcam_regions;
|
||||||
|
|
||||||
tcam->used_regions = bitmap_zalloc(max_regions, GFP_KERNEL);
|
ida_init(&tcam->used_regions);
|
||||||
if (!tcam->used_regions) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto err_alloc_used_regions;
|
|
||||||
}
|
|
||||||
tcam->max_regions = max_regions;
|
tcam->max_regions = max_regions;
|
||||||
|
|
||||||
max_groups = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_GROUPS);
|
max_groups = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_GROUPS);
|
||||||
tcam->used_groups = bitmap_zalloc(max_groups, GFP_KERNEL);
|
ida_init(&tcam->used_groups);
|
||||||
if (!tcam->used_groups) {
|
|
||||||
err = -ENOMEM;
|
|
||||||
goto err_alloc_used_groups;
|
|
||||||
}
|
|
||||||
tcam->max_groups = max_groups;
|
tcam->max_groups = max_groups;
|
||||||
tcam->max_group_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
|
tcam->max_group_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
|
||||||
ACL_MAX_GROUP_SIZE);
|
ACL_MAX_GROUP_SIZE);
|
||||||
|
@ -1575,10 +1606,8 @@ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp,
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_tcam_init:
|
err_tcam_init:
|
||||||
bitmap_free(tcam->used_groups);
|
ida_destroy(&tcam->used_groups);
|
||||||
err_alloc_used_groups:
|
ida_destroy(&tcam->used_regions);
|
||||||
bitmap_free(tcam->used_regions);
|
|
||||||
err_alloc_used_regions:
|
|
||||||
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
|
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
|
||||||
err_rehash_params_register:
|
err_rehash_params_register:
|
||||||
mutex_destroy(&tcam->lock);
|
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;
|
const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops;
|
||||||
|
|
||||||
ops->fini(mlxsw_sp, tcam->priv);
|
ops->fini(mlxsw_sp, tcam->priv);
|
||||||
bitmap_free(tcam->used_groups);
|
ida_destroy(&tcam->used_groups);
|
||||||
bitmap_free(tcam->used_regions);
|
ida_destroy(&tcam->used_regions);
|
||||||
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
|
mlxsw_sp_acl_tcam_rehash_params_unregister(mlxsw_sp);
|
||||||
mutex_destroy(&tcam->lock);
|
mutex_destroy(&tcam->lock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,15 +6,16 @@
|
||||||
|
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
#include <linux/parman.h>
|
#include <linux/parman.h>
|
||||||
|
#include <linux/idr.h>
|
||||||
|
|
||||||
#include "reg.h"
|
#include "reg.h"
|
||||||
#include "spectrum.h"
|
#include "spectrum.h"
|
||||||
#include "core_acl_flex_keys.h"
|
#include "core_acl_flex_keys.h"
|
||||||
|
|
||||||
struct mlxsw_sp_acl_tcam {
|
struct mlxsw_sp_acl_tcam {
|
||||||
unsigned long *used_regions; /* bit array */
|
struct ida used_regions;
|
||||||
unsigned int max_regions;
|
unsigned int max_regions;
|
||||||
unsigned long *used_groups; /* bit array */
|
struct ida used_groups;
|
||||||
unsigned int max_groups;
|
unsigned int max_groups;
|
||||||
unsigned int max_group_size;
|
unsigned int max_group_size;
|
||||||
struct mutex lock; /* guards vregion list */
|
struct mutex lock; /* guards vregion list */
|
||||||
|
|
Loading…
Reference in New Issue