From f9b274ce014421899b62cb0e41e5e7b72773782b Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:16 +0000 Subject: [PATCH 01/14] mlxsw: spectrum_acl: Push rehash dw struct into rehash sub-struct More rehash related fields are going to come. Push "dw" into sub-struct that will accommodate the others as well. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index c9d9cded17244..e2699373dfa75 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -192,7 +192,9 @@ struct mlxsw_sp_acl_tcam_vregion { struct mlxsw_afk_key_info *key_info; struct mlxsw_sp_acl_tcam *tcam; struct mlxsw_sp_acl_tcam_vgroup *vgroup; - struct delayed_work rehash_dw; + struct { + struct delayed_work dw; + } rehash; struct mlxsw_sp *mlxsw_sp; bool failed_rollback; /* Indicates failed rollback during migration */ unsigned int ref_count; @@ -718,7 +720,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(struct mlxsw_sp_acl_tcam_vregion if (!interval) return; - mlxsw_core_schedule_dw(&vregion->rehash_dw, + mlxsw_core_schedule_dw(&vregion->rehash.dw, msecs_to_jiffies(interval)); } @@ -730,7 +732,7 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work) { struct mlxsw_sp_acl_tcam_vregion *vregion = container_of(work, struct mlxsw_sp_acl_tcam_vregion, - rehash_dw.work); + rehash.dw.work); mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion); mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion); @@ -778,7 +780,7 @@ mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp, if (vgroup->vregion_rehash_enabled && ops->region_rehash_hints_get) { /* Create the delayed work for vregion periodic rehash */ - INIT_DELAYED_WORK(&vregion->rehash_dw, + INIT_DELAYED_WORK(&vregion->rehash.dw, mlxsw_sp_acl_tcam_vregion_rehash_work); mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion); mutex_lock(&tcam->lock); @@ -809,7 +811,7 @@ mlxsw_sp_acl_tcam_vregion_destroy(struct mlxsw_sp *mlxsw_sp, mutex_lock(&tcam->lock); list_del(&vregion->tlist); mutex_unlock(&tcam->lock); - cancel_delayed_work_sync(&vregion->rehash_dw); + cancel_delayed_work_sync(&vregion->rehash.dw); } mlxsw_sp_acl_tcam_vgroup_vregion_detach(mlxsw_sp, vregion); if (vregion->region2) @@ -847,9 +849,9 @@ int mlxsw_sp_acl_tcam_vregion_rehash_intrvl_set(struct mlxsw_sp *mlxsw_sp, mutex_lock(&tcam->lock); list_for_each_entry(vregion, &tcam->vregion_list, tlist) { if (val) - mlxsw_core_schedule_dw(&vregion->rehash_dw, 0); + mlxsw_core_schedule_dw(&vregion->rehash.dw, 0); else - cancel_delayed_work_sync(&vregion->rehash_dw); + cancel_delayed_work_sync(&vregion->rehash.dw); } mutex_unlock(&tcam->lock); return 0; From 6ca219e7de9fb54b4eac9c3f14a0cdf2b39d723d Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:17 +0000 Subject: [PATCH 02/14] mlxsw: spectrum_acl: Don't migrate already migrated entry Check if the entry is already in a chunk where we want it to be. In that case, skip migration. This is preparation for "per parts" migration where this situation may occur. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index e2699373dfa75..30131ea2e3246 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1174,6 +1174,10 @@ mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_acl_tcam_entry *entry2; + /* First check if the entry is not already where we want it to be. */ + if (ventry->entry->chunk == chunk2) + return 0; + entry2 = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk2); if (IS_ERR(entry2)) return PTR_ERR(entry2); From 559c27681058783c4c3d50ddb5ed8a64792e78ec Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:18 +0000 Subject: [PATCH 03/14] mlxsw: spectrum_acl: Introduce new rehash context struct and save hint_priv there Prepare for continued migration. Introduce a new structure to track rehash context and save hint_priv into it. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 30131ea2e3246..ae1101c17f2c7 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -180,6 +180,10 @@ struct mlxsw_sp_acl_tcam_vgroup { bool vregion_rehash_enabled; }; +struct mlxsw_sp_acl_tcam_rehash_ctx { + void *hints_priv; +}; + struct mlxsw_sp_acl_tcam_vregion { struct mutex lock; /* Protects consistency of region, region2 pointers * and vchunk_list. @@ -194,6 +198,7 @@ struct mlxsw_sp_acl_tcam_vregion { struct mlxsw_sp_acl_tcam_vgroup *vgroup; struct { struct delayed_work dw; + struct mlxsw_sp_acl_tcam_rehash_ctx ctx; } rehash; struct mlxsw_sp *mlxsw_sp; bool failed_rollback; /* Indicates failed rollback during migration */ @@ -1270,7 +1275,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, - void *hints_priv) + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion); struct mlxsw_sp_acl_tcam_region *region2, *unused_region; @@ -1279,7 +1284,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion); region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam, - vregion, hints_priv); + vregion, ctx->hints_priv); if (IS_ERR(region2)) { err = PTR_ERR(region2); goto out; @@ -1333,6 +1338,7 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion) { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx; void *hints_priv; int err; @@ -1347,8 +1353,9 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n"); return err; } + ctx->hints_priv = hints_priv; - err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, hints_priv); + err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, ctx); if (err) { dev_err(mlxsw_sp->bus_info->dev, "Failed to migrate vregion\n"); if (vregion->failed_rollback) { @@ -1358,7 +1365,8 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, } } - ops->region_rehash_hints_put(hints_priv); + ops->region_rehash_hints_put(ctx->hints_priv); + ctx->hints_priv = NULL; return err; } From 1667f7667d85e184bc731884bf9588bed89cca80 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:19 +0000 Subject: [PATCH 04/14] mlxsw: spectrum_acl: Push rehash start/end code into separate functions In preparations for interrupt/continue of rehash work, put the code at the beginning/end of the rehash function into separate functions. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 41 +++++++++++++++---- 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index ae1101c17f2c7..fa204003bc848 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1334,26 +1334,50 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, } static int -mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_vregion *vregion) +mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vregion *vregion, + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; - struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx; void *hints_priv; - int err; trace_mlxsw_sp_acl_tcam_vregion_rehash(mlxsw_sp, vregion); if (vregion->failed_rollback) return -EBUSY; hints_priv = ops->region_rehash_hints_get(vregion->region->priv); - if (IS_ERR(hints_priv)) { - err = PTR_ERR(hints_priv); + if (IS_ERR(hints_priv)) + return PTR_ERR(hints_priv); + + ctx->hints_priv = hints_priv; + + return 0; +} + +static void +mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vregion *vregion, + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) +{ + const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; + + ops->region_rehash_hints_put(ctx->hints_priv); + ctx->hints_priv = NULL; +} + +static int +mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vregion *vregion) +{ + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx; + int err; + + err = mlxsw_sp_acl_tcam_vregion_rehash_start(mlxsw_sp, vregion, ctx); + if (err) { if (err != -EAGAIN) dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n"); return err; } - ctx->hints_priv = hints_priv; err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, ctx); if (err) { @@ -1365,8 +1389,7 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, } } - ops->region_rehash_hints_put(ctx->hints_priv); - ctx->hints_priv = NULL; + mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx); return err; } From a9550d0f075a0c59dc199c817d31354bacde9906 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:19 +0000 Subject: [PATCH 05/14] mlxsw: spectrum_acl: Push code start/end from mlxsw_sp_acl_tcam_vregion_migrate() Push code from the beginning and end of function mlxsw_sp_acl_tcam_vregion_migrate() into rehash_start()/end() functions. Then all the things needed to be done before and after the actual migration process will be grouped together. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 74 +++++++++---------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index fa204003bc848..cf901a1504c4e 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1277,59 +1277,24 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { - unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion); - struct mlxsw_sp_acl_tcam_region *region2, *unused_region; int err; trace_mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion); - - region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam, - vregion, ctx->hints_priv); - if (IS_ERR(region2)) { - err = PTR_ERR(region2); - goto out; - } - - vregion->region2 = region2; - err = mlxsw_sp_acl_tcam_group_region_attach(mlxsw_sp, - vregion->region->group, - region2, priority, - vregion->region); - if (err) - goto err_group_region_attach; - mutex_lock(&vregion->lock); err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion); if (!vregion->failed_rollback) { if (!err) { /* In case of successful migration, region2 is used and - * the original is unused. - */ - unused_region = vregion->region; - vregion->region = vregion->region2; - } else { - /* In case of failure during migration, the original - * region is still used. + * the original is unused. So swap them. */ - unused_region = vregion->region2; + swap(vregion->region, vregion->region2); } - mutex_unlock(&vregion->lock); - vregion->region2 = NULL; - mlxsw_sp_acl_tcam_group_region_detach(mlxsw_sp, unused_region); - mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, unused_region); - } else { - mutex_unlock(&vregion->lock); + /* vregion->region2 contains pointer to unused region now. */ } - goto out; - -err_group_region_attach: - vregion->region2 = NULL; - mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, region2); -out: + mutex_unlock(&vregion->lock); trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion); - return err; } @@ -1339,7 +1304,10 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; + unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion); + struct mlxsw_sp_acl_tcam_region *region2; void *hints_priv; + int err; trace_mlxsw_sp_acl_tcam_vregion_rehash(mlxsw_sp, vregion); if (vregion->failed_rollback) @@ -1349,9 +1317,31 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, if (IS_ERR(hints_priv)) return PTR_ERR(hints_priv); + region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam, + vregion, hints_priv); + if (IS_ERR(region2)) { + err = PTR_ERR(region2); + goto err_region_create; + } + + vregion->region2 = region2; + err = mlxsw_sp_acl_tcam_group_region_attach(mlxsw_sp, + vregion->region->group, + region2, priority, + vregion->region); + if (err) + goto err_group_region_attach; + ctx->hints_priv = hints_priv; return 0; + +err_group_region_attach: + vregion->region2 = NULL; + mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, region2); +err_region_create: + ops->region_rehash_hints_put(hints_priv); + return err; } static void @@ -1359,8 +1349,14 @@ mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { + struct mlxsw_sp_acl_tcam_region *unused_region = vregion->region2; const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; + if (!vregion->failed_rollback) { + vregion->region2 = NULL; + mlxsw_sp_acl_tcam_group_region_detach(mlxsw_sp, unused_region); + mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, unused_region); + } ops->region_rehash_hints_put(ctx->hints_priv); ctx->hints_priv = NULL; } From a86838e46b1dc1f7ecc2eb769ea1966380409025 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:20 +0000 Subject: [PATCH 06/14] mlxsw: spectrum_acl: assign vregion->region by the newly created region Make the vregion->region contain pointer of a new region we migrate to. In case of a rollback, it contains the original region. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index cf901a1504c4e..72734ee60a1ed 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1256,7 +1256,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, list_for_each_entry(vchunk, &vregion->vchunk_list, list) { err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, - vregion->region2, + vregion->region, false); if (err) goto rollback; @@ -1264,6 +1264,10 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, return 0; rollback: + /* 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); list_for_each_entry_continue_reverse(vchunk, &vregion->vchunk_list, list) { mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, @@ -1281,18 +1285,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, 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); - if (!vregion->failed_rollback) { - if (!err) { - /* In case of successful migration, region2 is used and - * the original is unused. So swap them. - */ - swap(vregion->region, vregion->region2); - } - /* vregion->region2 contains pointer to unused region now. */ - } - mutex_unlock(&vregion->lock); trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion); return err; @@ -1305,7 +1298,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, { const struct mlxsw_sp_acl_tcam_ops *ops = mlxsw_sp->acl_tcam_ops; unsigned int priority = mlxsw_sp_acl_tcam_vregion_prio(vregion); - struct mlxsw_sp_acl_tcam_region *region2; + struct mlxsw_sp_acl_tcam_region *new_region; void *hints_priv; int err; @@ -1317,18 +1310,22 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, if (IS_ERR(hints_priv)) return PTR_ERR(hints_priv); - region2 = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam, - vregion, hints_priv); - if (IS_ERR(region2)) { - err = PTR_ERR(region2); + new_region = mlxsw_sp_acl_tcam_region_create(mlxsw_sp, vregion->tcam, + vregion, hints_priv); + if (IS_ERR(new_region)) { + err = PTR_ERR(new_region); goto err_region_create; } - vregion->region2 = region2; + /* vregion->region contains the pointer to the new region + * we are going to migrate to. + */ + vregion->region2 = vregion->region; + vregion->region = new_region; err = mlxsw_sp_acl_tcam_group_region_attach(mlxsw_sp, - vregion->region->group, - region2, priority, - vregion->region); + vregion->region2->group, + new_region, priority, + vregion->region2); if (err) goto err_group_region_attach; @@ -1337,8 +1334,9 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, return 0; err_group_region_attach: + vregion->region = vregion->region2; vregion->region2 = NULL; - mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, region2); + mlxsw_sp_acl_tcam_region_destroy(mlxsw_sp, new_region); err_region_create: ops->region_rehash_hints_put(hints_priv); return err; From e1d2f7a97261dc0e5bec44edb64fe5bcfb994971 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:21 +0000 Subject: [PATCH 07/14] mlxsw: spectrum_acl: assign vchunk->chunk by the newly created chunk Make the vchunk->chunk contain pointer of a new chunk we migrate to. In case of a rollback, it contains the original chunk. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 72734ee60a1ed..6a50266b6809f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1197,21 +1197,23 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_region *region, bool this_is_rollback) { + struct mlxsw_sp_acl_tcam_chunk *new_chunk; struct mlxsw_sp_acl_tcam_ventry *ventry; - struct mlxsw_sp_acl_tcam_chunk *chunk2; int err; int err2; - chunk2 = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region); - if (IS_ERR(chunk2)) { + new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region); + if (IS_ERR(new_chunk)) { if (this_is_rollback) vchunk->vregion->failed_rollback = true; - return PTR_ERR(chunk2); + return PTR_ERR(new_chunk); } - vchunk->chunk2 = chunk2; + vchunk->chunk2 = vchunk->chunk; + vchunk->chunk = new_chunk; + list_for_each_entry(ventry, &vchunk->ventry_list, list) { err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, - vchunk->chunk2); + vchunk->chunk); if (err) { if (this_is_rollback) { vchunk->vregion->failed_rollback = true; @@ -1220,8 +1222,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, goto rollback; } } - mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk); - vchunk->chunk = chunk2; + mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); vchunk->chunk2 = NULL; return 0; @@ -1230,6 +1231,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, * migration fails, there's no good way how to proceed. Set the * vregion with "failed_rollback" flag. */ + swap(vchunk->chunk, vchunk->chunk2); list_for_each_entry_continue_reverse(ventry, &vchunk->ventry_list, list) { err2 = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, From 2c331593c99e0c9bf9bb27b8afa92d96d4decac8 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:22 +0000 Subject: [PATCH 08/14] mlxsw: spectrum_acl: Rename variables in mlxsw_sp_acl_tcam_ventry_migrate() Remove some of variables in function mlxsw_sp_acl_tcam_ventry_migrate() so the names are aligned with the rest of the code. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 6a50266b6809f..0bc04016c6d05 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1175,19 +1175,19 @@ mlxsw_sp_acl_tcam_ventry_activity_get(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_ventry *ventry, - struct mlxsw_sp_acl_tcam_chunk *chunk2) + struct mlxsw_sp_acl_tcam_chunk *chunk) { - struct mlxsw_sp_acl_tcam_entry *entry2; + struct mlxsw_sp_acl_tcam_entry *new_entry; /* First check if the entry is not already where we want it to be. */ - if (ventry->entry->chunk == chunk2) + if (ventry->entry->chunk == chunk) return 0; - entry2 = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk2); - if (IS_ERR(entry2)) - return PTR_ERR(entry2); + new_entry = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk); + if (IS_ERR(new_entry)) + return PTR_ERR(new_entry); mlxsw_sp_acl_tcam_entry_destroy(mlxsw_sp, ventry->entry); - ventry->entry = entry2; + ventry->entry = new_entry; return 0; } From 220f4fba3d64b484840d451cd1367de03dbb836e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:23 +0000 Subject: [PATCH 09/14] mlxsw: spectrum_acl: Put this_is_rollback to rehash context struct Put the this_is_rollback flag into rehash context struct in preparations for interrupt/continue of rehash work. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 0bc04016c6d05..db80b20e4a137 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -182,6 +182,7 @@ struct mlxsw_sp_acl_tcam_vgroup { struct mlxsw_sp_acl_tcam_rehash_ctx { void *hints_priv; + bool this_is_rollback; }; struct mlxsw_sp_acl_tcam_vregion { @@ -1195,7 +1196,7 @@ static int mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vchunk *vchunk, struct mlxsw_sp_acl_tcam_region *region, - bool this_is_rollback) + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { struct mlxsw_sp_acl_tcam_chunk *new_chunk; struct mlxsw_sp_acl_tcam_ventry *ventry; @@ -1204,7 +1205,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region); if (IS_ERR(new_chunk)) { - if (this_is_rollback) + if (ctx->this_is_rollback) vchunk->vregion->failed_rollback = true; return PTR_ERR(new_chunk); } @@ -1215,7 +1216,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, vchunk->chunk); if (err) { - if (this_is_rollback) { + if (ctx->this_is_rollback) { vchunk->vregion->failed_rollback = true; return err; } @@ -1251,7 +1252,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_vregion *vregion) + struct mlxsw_sp_acl_tcam_vregion *vregion, + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { struct mlxsw_sp_acl_tcam_vchunk *vchunk; int err; @@ -1259,7 +1261,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, list_for_each_entry(vchunk, &vregion->vchunk_list, list) { err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, vregion->region, - false); + ctx); if (err) goto rollback; } @@ -1270,10 +1272,12 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, * so the original region pointer is assigned again to vregion->region. */ swap(vregion->region, vregion->region2); + ctx->this_is_rollback = true; list_for_each_entry_continue_reverse(vchunk, &vregion->vchunk_list, list) { mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, - vregion->region, true); + vregion->region, + ctx); } return err; } @@ -1287,7 +1291,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, 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); mutex_unlock(&vregion->lock); trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion); return err; @@ -1332,6 +1336,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, goto err_group_region_attach; ctx->hints_priv = hints_priv; + ctx->this_is_rollback = false; return 0; From 844f01da9301a71fbed1e768837f4a1a6aa60529 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:24 +0000 Subject: [PATCH 10/14] mlxsw: spectrum_acl: Put vchunk migrate start/end code into separate functions In preparations of interrupt/continue of rehash work, put the code that is done at the beginning/end of vchunk migrate function into separate functions. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index db80b20e4a137..1f308ad4b635f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1193,15 +1193,12 @@ mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp, } static int -mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_vchunk *vchunk, - struct mlxsw_sp_acl_tcam_region *region, - struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) +mlxsw_sp_acl_tcam_vchunk_migrate_start(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vchunk *vchunk, + struct mlxsw_sp_acl_tcam_region *region, + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { struct mlxsw_sp_acl_tcam_chunk *new_chunk; - struct mlxsw_sp_acl_tcam_ventry *ventry; - int err; - int err2; new_chunk = mlxsw_sp_acl_tcam_chunk_create(mlxsw_sp, vchunk, region); if (IS_ERR(new_chunk)) { @@ -1211,6 +1208,31 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, } vchunk->chunk2 = vchunk->chunk; vchunk->chunk = new_chunk; + return 0; +} + +static void +mlxsw_sp_acl_tcam_vchunk_migrate_end(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vchunk *vchunk) +{ + mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); + vchunk->chunk2 = NULL; +} + +static int +mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, + struct mlxsw_sp_acl_tcam_vchunk *vchunk, + struct mlxsw_sp_acl_tcam_region *region, + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) +{ + struct mlxsw_sp_acl_tcam_ventry *ventry; + int err; + int err2; + + err = mlxsw_sp_acl_tcam_vchunk_migrate_start(mlxsw_sp, vchunk, + region, ctx); + if (err) + return err; list_for_each_entry(ventry, &vchunk->ventry_list, list) { err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, @@ -1223,8 +1245,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, goto rollback; } } - mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); - vchunk->chunk2 = NULL; + + mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk); return 0; rollback: @@ -1243,8 +1265,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, } } - mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); - vchunk->chunk2 = NULL; + mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk); err_rollback: return err; From 843500518509128a935edab96bd8efef7c54669e Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:24 +0000 Subject: [PATCH 11/14] mlxsw: spectrum_acl: Do rollback as another call to mlxsw_sp_acl_tcam_vchunk_migrate_all() In order to simplify the code and to prepare it for interrupted/continued migration process, do the rollback in case of migration error as another call to mlxsw_sp_acl_tcam_vchunk_migrate_all(). It can be understood as "migrate all back". Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 75 +++++++------------ 1 file changed, 29 insertions(+), 46 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 1f308ad4b635f..9dc83815644e9 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -1227,48 +1227,34 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, { struct mlxsw_sp_acl_tcam_ventry *ventry; int err; - int err2; - err = mlxsw_sp_acl_tcam_vchunk_migrate_start(mlxsw_sp, vchunk, - region, ctx); - if (err) - return err; + if (vchunk->chunk->region != region) { + err = mlxsw_sp_acl_tcam_vchunk_migrate_start(mlxsw_sp, vchunk, + region, ctx); + if (err) + return err; + } else if (!vchunk->chunk2) { + /* The chunk is already as it should be, nothing to do. */ + return 0; + } list_for_each_entry(ventry, &vchunk->ventry_list, list) { err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, vchunk->chunk); if (err) { - if (ctx->this_is_rollback) { - vchunk->vregion->failed_rollback = true; + if (ctx->this_is_rollback) return err; - } - goto rollback; + /* Swap the chunk and chunk2 pointers so the follow-up + * rollback call will see the original chunk pointer + * in vchunk->chunk. + */ + swap(vchunk->chunk, vchunk->chunk2); + return err; } } mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk); return 0; - -rollback: - /* Migrate the entries back to the original chunk. If some entry - * migration fails, there's no good way how to proceed. Set the - * vregion with "failed_rollback" flag. - */ - swap(vchunk->chunk, vchunk->chunk2); - list_for_each_entry_continue_reverse(ventry, &vchunk->ventry_list, - list) { - err2 = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, - vchunk->chunk); - if (err2) { - vchunk->vregion->failed_rollback = true; - goto err_rollback; - } - } - - mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk); - -err_rollback: - return err; } static int @@ -1284,23 +1270,9 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, vregion->region, ctx); if (err) - goto rollback; + return err; } return 0; - -rollback: - /* 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->this_is_rollback = true; - list_for_each_entry_continue_reverse(vchunk, &vregion->vchunk_list, - list) { - mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, - vregion->region, - ctx); - } - return err; } static int @@ -1308,11 +1280,22 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { - int err; + 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); + if (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->this_is_rollback = true; + err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx); + if (err2) + vregion->failed_rollback = true; + } mutex_unlock(&vregion->lock); trace_mlxsw_sp_acl_tcam_vregion_migrate_end(mlxsw_sp, vregion); return err; From c9c9af91f1d9a636aecc55302c792538e549a430 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:25 +0000 Subject: [PATCH 12/14] mlxsw: spectrum_acl: Allow to interrupt/continue rehash work Currently, migration of vregions with many entries may take long time during which insertions and removals of the rules are blocked due to wait to acquire vregion->lock. To overcome this, allow to interrupt and continue rehash work according to the set credits - number of rules to migrate. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 82 ++++++++++++++----- 1 file changed, 62 insertions(+), 20 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index 9dc83815644e9..cfd05af3f0f6c 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -27,6 +27,7 @@ size_t mlxsw_sp_acl_tcam_priv_size(struct mlxsw_sp *mlxsw_sp) #define MLXSW_SP_ACL_TCAM_VREGION_REHASH_INTRVL_DFLT 5000 /* ms */ #define MLXSW_SP_ACL_TCAM_VREGION_REHASH_INTRVL_MIN 3000 /* ms */ +#define MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS 100 /* number of entries */ int mlxsw_sp_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam *tcam) @@ -732,16 +733,26 @@ mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(struct mlxsw_sp_acl_tcam_vregion static int mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_vregion *vregion); + struct mlxsw_sp_acl_tcam_vregion *vregion, + int *credits); static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work) { struct mlxsw_sp_acl_tcam_vregion *vregion = container_of(work, struct mlxsw_sp_acl_tcam_vregion, rehash.dw.work); + int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS; + int err; - mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion); - mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion); + err = mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, + vregion, &credits); + if (credits < 0) + /* Rehash gone out of credits so it was interrupted. + * Schedule the work as soon as possible to continue. + */ + mlxsw_core_schedule_dw(&vregion->rehash.dw, 0); + else + mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(vregion); } static struct mlxsw_sp_acl_tcam_vregion * @@ -1176,7 +1187,8 @@ mlxsw_sp_acl_tcam_ventry_activity_get(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_ventry *ventry, - struct mlxsw_sp_acl_tcam_chunk *chunk) + struct mlxsw_sp_acl_tcam_chunk *chunk, + int *credits) { struct mlxsw_sp_acl_tcam_entry *new_entry; @@ -1184,6 +1196,9 @@ mlxsw_sp_acl_tcam_ventry_migrate(struct mlxsw_sp *mlxsw_sp, if (ventry->entry->chunk == chunk) return 0; + if (--(*credits) < 0) + return 0; + new_entry = mlxsw_sp_acl_tcam_entry_create(mlxsw_sp, ventry, chunk); if (IS_ERR(new_entry)) return PTR_ERR(new_entry); @@ -1223,7 +1238,8 @@ static int mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vchunk *vchunk, struct mlxsw_sp_acl_tcam_region *region, - struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx, + int *credits) { struct mlxsw_sp_acl_tcam_ventry *ventry; int err; @@ -1240,7 +1256,7 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, list_for_each_entry(ventry, &vchunk->ventry_list, list) { err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, - vchunk->chunk); + vchunk->chunk, credits); if (err) { if (ctx->this_is_rollback) return err; @@ -1250,6 +1266,11 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, */ swap(vchunk->chunk, vchunk->chunk2); return err; + } else if (*credits < 0) { + /* We are out of credits, the rest of the ventries + * will be migrated later. + */ + return 0; } } @@ -1260,7 +1281,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, - struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx, + int *credits) { struct mlxsw_sp_acl_tcam_vchunk *vchunk; int err; @@ -1268,8 +1290,8 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, list_for_each_entry(vchunk, &vregion->vchunk_list, list) { err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, vregion->region, - ctx); - if (err) + ctx, credits); + if (err || *credits < 0) return err; } return 0; @@ -1278,13 +1300,15 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, - struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx, + int *credits) { 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); + err = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, + ctx, credits); if (err) { /* In case migration was not successful, we need to swap * so the original region pointer is assigned again @@ -1292,7 +1316,8 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, */ swap(vregion->region, vregion->region2); ctx->this_is_rollback = true; - err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx); + err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, + ctx, credits); if (err2) vregion->failed_rollback = true; } @@ -1301,6 +1326,12 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, return err; } +static bool +mlxsw_sp_acl_tcam_vregion_rehash_in_progress(const struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) +{ + return ctx->hints_priv; +} + static int mlxsw_sp_acl_tcam_vregion_rehash_start(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, @@ -1372,19 +1403,28 @@ mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp, static int mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_vregion *vregion) + struct mlxsw_sp_acl_tcam_vregion *vregion, + int *credits) { struct mlxsw_sp_acl_tcam_rehash_ctx *ctx = &vregion->rehash.ctx; int err; - err = mlxsw_sp_acl_tcam_vregion_rehash_start(mlxsw_sp, vregion, ctx); - if (err) { - if (err != -EAGAIN) - dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n"); - return err; + /* Check if the previous rehash work was interrupted + * which means we have to continue it now. + * If not, start a new rehash. + */ + if (!mlxsw_sp_acl_tcam_vregion_rehash_in_progress(ctx)) { + err = mlxsw_sp_acl_tcam_vregion_rehash_start(mlxsw_sp, + vregion, ctx); + if (err) { + if (err != -EAGAIN) + dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n"); + return err; + } } - err = mlxsw_sp_acl_tcam_vregion_migrate(mlxsw_sp, vregion, ctx); + 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"); if (vregion->failed_rollback) { @@ -1394,7 +1434,9 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, } } - mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx); + if (*credits >= 0) + mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx); + return err; } From 6f9579d4e3021b17b0a4cde6b04a6c94c9575cdf Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:26 +0000 Subject: [PATCH 13/14] mlxsw: spectrum_acl: Remember where to continue rehash migration Store pointer to vchunk where the migration was interrupted, as well as ventry pointer to start from and to stop at (during rollback). This saved pointers need to be forgotten in case of ventries list or vchunk list changes, which is done by couple of "changed" helpers. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../mellanox/mlxsw/spectrum_acl_tcam.c | 91 ++++++++++++++++++- 1 file changed, 86 insertions(+), 5 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index cfd05af3f0f6c..dc118ed714b2a 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -184,6 +184,19 @@ struct mlxsw_sp_acl_tcam_vgroup { struct mlxsw_sp_acl_tcam_rehash_ctx { void *hints_priv; bool this_is_rollback; + struct mlxsw_sp_acl_tcam_vchunk *current_vchunk; /* vchunk being + * currently migrated. + */ + struct mlxsw_sp_acl_tcam_ventry *start_ventry; /* ventry to start + * migration from in + * a vchunk being + * currently migrated. + */ + struct mlxsw_sp_acl_tcam_ventry *stop_ventry; /* ventry to stop + * migration at + * a vchunk being + * currently migrated. + */ }; struct mlxsw_sp_acl_tcam_vregion { @@ -755,6 +768,31 @@ 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_changed(struct mlxsw_sp_acl_tcam_vchunk *vchunk) +{ + struct mlxsw_sp_acl_tcam_vregion *vregion = vchunk->vregion; + + /* If a rule was added or deleted from vchunk which is currently + * under rehash migration, we have to reset the ventry pointers + * to make sure all rules are properly migrated. + */ + if (vregion->rehash.ctx.current_vchunk == vchunk) { + vregion->rehash.ctx.start_ventry = NULL; + vregion->rehash.ctx.stop_ventry = NULL; + } +} + +static void +mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(struct mlxsw_sp_acl_tcam_vregion *vregion) +{ + /* If a chunk was added or deleted from vregion we have to reset + * the current chunk pointer to make sure all chunks + * are properly migrated. + */ + vregion->rehash.ctx.current_vchunk = NULL; +} + static struct mlxsw_sp_acl_tcam_vregion * mlxsw_sp_acl_tcam_vregion_create(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vgroup *vgroup, @@ -989,6 +1027,7 @@ mlxsw_sp_acl_tcam_vchunk_create(struct mlxsw_sp *mlxsw_sp, goto err_chunk_create; } + mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(vregion); list_add_tail(&vchunk->list, &vregion->vchunk_list); mutex_unlock(&vregion->lock); @@ -1012,6 +1051,7 @@ mlxsw_sp_acl_tcam_vchunk_destroy(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vgroup *vgroup = vchunk->vgroup; mutex_lock(&vregion->lock); + mlxsw_sp_acl_tcam_rehash_ctx_vregion_changed(vregion); list_del(&vchunk->list); if (vchunk->chunk2) mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); @@ -1141,6 +1181,7 @@ static int mlxsw_sp_acl_tcam_ventry_add(struct mlxsw_sp *mlxsw_sp, } list_add_tail(&ventry->list, &vchunk->ventry_list); + mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(vchunk); mutex_unlock(&vregion->lock); return 0; @@ -1157,6 +1198,7 @@ static void mlxsw_sp_acl_tcam_ventry_del(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion = vchunk->vregion; mutex_lock(&vregion->lock); + mlxsw_sp_acl_tcam_rehash_ctx_vchunk_changed(vchunk); list_del(&ventry->list); mlxsw_sp_acl_tcam_entry_destroy(mlxsw_sp, ventry->entry); mutex_unlock(&vregion->lock); @@ -1223,15 +1265,20 @@ mlxsw_sp_acl_tcam_vchunk_migrate_start(struct mlxsw_sp *mlxsw_sp, } vchunk->chunk2 = vchunk->chunk; vchunk->chunk = new_chunk; + ctx->current_vchunk = vchunk; + ctx->start_ventry = NULL; + ctx->stop_ventry = NULL; return 0; } static void mlxsw_sp_acl_tcam_vchunk_migrate_end(struct mlxsw_sp *mlxsw_sp, - struct mlxsw_sp_acl_tcam_vchunk *vchunk) + struct mlxsw_sp_acl_tcam_vchunk *vchunk, + struct mlxsw_sp_acl_tcam_rehash_ctx *ctx) { mlxsw_sp_acl_tcam_chunk_destroy(mlxsw_sp, vchunk->chunk2); vchunk->chunk2 = NULL; + ctx->current_vchunk = NULL; } static int @@ -1254,7 +1301,22 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, return 0; } - list_for_each_entry(ventry, &vchunk->ventry_list, list) { + /* If the migration got interrupted, we have the ventry to start from + * stored in context. + */ + if (ctx->start_ventry) + ventry = ctx->start_ventry; + else + ventry = list_first_entry(&vchunk->ventry_list, + typeof(*ventry), list); + + list_for_each_entry_from(ventry, &vchunk->ventry_list, list) { + /* During rollback, once we reach the ventry that failed + * to migrate, we are done. + */ + if (ventry == ctx->stop_ventry) + break; + err = mlxsw_sp_acl_tcam_ventry_migrate(mlxsw_sp, ventry, vchunk->chunk, credits); if (err) { @@ -1265,16 +1327,25 @@ mlxsw_sp_acl_tcam_vchunk_migrate_one(struct mlxsw_sp *mlxsw_sp, * in vchunk->chunk. */ swap(vchunk->chunk, vchunk->chunk2); + /* The rollback has to be done from beginning of the + * chunk, that is why we have to null the start_ventry. + * However, we know where to stop the rollback, + * at the current ventry. + */ + ctx->start_ventry = NULL; + ctx->stop_ventry = ventry; return err; } else if (*credits < 0) { /* We are out of credits, the rest of the ventries - * will be migrated later. + * will be migrated later. Save the ventry + * which we ended with. */ + ctx->start_ventry = ventry; return 0; } } - mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk); + mlxsw_sp_acl_tcam_vchunk_migrate_end(mlxsw_sp, vchunk, ctx); return 0; } @@ -1287,7 +1358,16 @@ mlxsw_sp_acl_tcam_vchunk_migrate_all(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vchunk *vchunk; int err; - list_for_each_entry(vchunk, &vregion->vchunk_list, list) { + /* If the migration got interrupted, we have the vchunk + * we are working on stored in context. + */ + if (ctx->current_vchunk) + vchunk = ctx->current_vchunk; + else + vchunk = list_first_entry(&vregion->vchunk_list, + typeof(*vchunk), list); + + list_for_each_entry_from(vchunk, &vregion->vchunk_list, list) { err = mlxsw_sp_acl_tcam_vchunk_migrate_one(mlxsw_sp, vchunk, vregion->region, ctx, credits); @@ -1315,6 +1395,7 @@ mlxsw_sp_acl_tcam_vregion_migrate(struct mlxsw_sp *mlxsw_sp, * to vregion->region. */ swap(vregion->region, vregion->region2); + ctx->current_vchunk = NULL; ctx->this_is_rollback = true; err2 = mlxsw_sp_acl_tcam_vchunk_migrate_all(mlxsw_sp, vregion, ctx, credits); From b2c091ce46a7e08d776160d2f1b8ccabc85410b3 Mon Sep 17 00:00:00 2001 From: Jiri Pirko Date: Thu, 28 Feb 2019 06:59:27 +0000 Subject: [PATCH 14/14] mlxsw: spectrum_acl: Make mlxsw_sp_acl_tcam_vregion_rehash() return void The return value is ignored anyway, so just return void. Signed-off-by: Jiri Pirko Signed-off-by: Ido Schimmel Signed-off-by: David S. Miller --- .../net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c index dc118ed714b2a..8811f6513e36f 100644 --- a/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c +++ b/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_tcam.c @@ -744,7 +744,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_work_schedule(struct mlxsw_sp_acl_tcam_vregion msecs_to_jiffies(interval)); } -static int +static void mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, int *credits); @@ -755,10 +755,8 @@ static void mlxsw_sp_acl_tcam_vregion_rehash_work(struct work_struct *work) container_of(work, struct mlxsw_sp_acl_tcam_vregion, rehash.dw.work); int credits = MLXSW_SP_ACL_TCAM_VREGION_REHASH_CREDITS; - int err; - err = mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, - vregion, &credits); + mlxsw_sp_acl_tcam_vregion_rehash(vregion->mlxsw_sp, vregion, &credits); if (credits < 0) /* Rehash gone out of credits so it was interrupted. * Schedule the work as soon as possible to continue. @@ -1482,7 +1480,7 @@ mlxsw_sp_acl_tcam_vregion_rehash_end(struct mlxsw_sp *mlxsw_sp, ctx->hints_priv = NULL; } -static int +static void mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, struct mlxsw_sp_acl_tcam_vregion *vregion, int *credits) @@ -1500,7 +1498,7 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, if (err) { if (err != -EAGAIN) dev_err(mlxsw_sp->bus_info->dev, "Failed get rehash hints\n"); - return err; + return; } } @@ -1517,8 +1515,6 @@ mlxsw_sp_acl_tcam_vregion_rehash(struct mlxsw_sp *mlxsw_sp, if (*credits >= 0) mlxsw_sp_acl_tcam_vregion_rehash_end(mlxsw_sp, vregion, ctx); - - return err; } static const enum mlxsw_afk_element mlxsw_sp_acl_tcam_pattern_ipv4[] = {