Skip to content

Commit

Permalink
Merge branch 'mlxsw-spectrum_acl-Don-t-take-rtnl-mutex-for-region-reh…
Browse files Browse the repository at this point in the history
…ash'

Ido Schimmel says:

====================
mlxsw: spectrum_acl: Don't take rtnl mutex for region rehash

Jiri says:

During region rehash, a new region is created with a more optimized set
of masks (ERPs). When transitioning to the new region, all the rules
from the old region are copied one-by-one to the new region. This
transition can be time consuming and currently done under RTNL lock.

In order to remove RTNL lock dependency during region rehash, introduce
multiple smaller locks guarding dedicated structures or parts of them.
That is the vast majority of this patchset. Only patch #1 is simple
cleanup and patches 12-15 are improving or introducing new selftests.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Feb 25, 2019
2 parents 731e7cc + 81d56d8 commit 834f9b0
Show file tree
Hide file tree
Showing 6 changed files with 592 additions and 187 deletions.
34 changes: 27 additions & 7 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_bloom_filter.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/refcount.h>
#include <linux/mutex.h>

#include "spectrum.h"
#include "spectrum_acl_tcam.h"

struct mlxsw_sp_acl_bf {
struct mutex lock; /* Protects Bloom Filter updates. */
unsigned int bank_size;
refcount_t refcnt[0];
};
Expand Down Expand Up @@ -172,26 +174,36 @@ mlxsw_sp_acl_bf_entry_add(struct mlxsw_sp *mlxsw_sp,
u16 bf_index;
int err;

mutex_lock(&bf->lock);

bf_index = mlxsw_sp_acl_bf_index_get(bf, aregion, aentry);
rule_index = mlxsw_sp_acl_bf_rule_count_index_get(bf, erp_bank,
bf_index);

if (refcount_inc_not_zero(&bf->refcnt[rule_index]))
return 0;
if (refcount_inc_not_zero(&bf->refcnt[rule_index])) {
err = 0;
goto unlock;
}

peabfe_pl = kmalloc(MLXSW_REG_PEABFE_LEN, GFP_KERNEL);
if (!peabfe_pl)
return -ENOMEM;
if (!peabfe_pl) {
err = -ENOMEM;
goto unlock;
}

mlxsw_reg_peabfe_pack(peabfe_pl);
mlxsw_reg_peabfe_rec_pack(peabfe_pl, 0, 1, erp_bank, bf_index);
err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(peabfe), peabfe_pl);
kfree(peabfe_pl);
if (err)
return err;
goto unlock;

refcount_set(&bf->refcnt[rule_index], 1);
return 0;
err = 0;

unlock:
mutex_unlock(&bf->lock);
return err;
}

void
Expand All @@ -205,20 +217,25 @@ mlxsw_sp_acl_bf_entry_del(struct mlxsw_sp *mlxsw_sp,
char *peabfe_pl;
u16 bf_index;

mutex_lock(&bf->lock);

bf_index = mlxsw_sp_acl_bf_index_get(bf, aregion, aentry);
rule_index = mlxsw_sp_acl_bf_rule_count_index_get(bf, erp_bank,
bf_index);

if (refcount_dec_and_test(&bf->refcnt[rule_index])) {
peabfe_pl = kmalloc(MLXSW_REG_PEABFE_LEN, GFP_KERNEL);
if (!peabfe_pl)
return;
goto unlock;

mlxsw_reg_peabfe_pack(peabfe_pl);
mlxsw_reg_peabfe_rec_pack(peabfe_pl, 0, 0, erp_bank, bf_index);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(peabfe), peabfe_pl);
kfree(peabfe_pl);
}

unlock:
mutex_unlock(&bf->lock);
}

struct mlxsw_sp_acl_bf *
Expand All @@ -240,10 +257,13 @@ mlxsw_sp_acl_bf_init(struct mlxsw_sp *mlxsw_sp, unsigned int num_erp_banks)
return ERR_PTR(-ENOMEM);

bf->bank_size = bf_bank_size;
mutex_init(&bf->lock);

return bf;
}

void mlxsw_sp_acl_bf_fini(struct mlxsw_sp_acl_bf *bf)
{
mutex_destroy(&bf->lock);
kfree(bf);
}
31 changes: 20 additions & 11 deletions drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include <linux/gfp.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/objagg.h>
#include <linux/rtnetlink.h>
#include <linux/slab.h>
Expand Down Expand Up @@ -63,6 +64,7 @@ struct mlxsw_sp_acl_erp_table {
unsigned int num_ctcam_erps;
unsigned int num_deltas;
struct objagg *objagg;
struct mutex objagg_lock; /* guards objagg manipulation */
};

struct mlxsw_sp_acl_erp_table_ops {
Expand Down Expand Up @@ -1001,17 +1003,15 @@ struct mlxsw_sp_acl_erp_mask *
mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion,
const char *mask, bool ctcam)
{
struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
struct mlxsw_sp_acl_erp_key key;
struct objagg_obj *objagg_obj;

/* eRPs are allocated from a shared resource, but currently all
* allocations are done under RTNL.
*/
ASSERT_RTNL();

memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN);
key.ctcam = ctcam;
objagg_obj = objagg_obj_get(aregion->erp_table->objagg, &key);
mutex_lock(&erp_table->objagg_lock);
objagg_obj = objagg_obj_get(erp_table->objagg, &key);
mutex_unlock(&erp_table->objagg_lock);
if (IS_ERR(objagg_obj))
return ERR_CAST(objagg_obj);
return (struct mlxsw_sp_acl_erp_mask *) objagg_obj;
Expand All @@ -1021,8 +1021,11 @@ void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion,
struct mlxsw_sp_acl_erp_mask *erp_mask)
{
struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;

objagg_obj_put(aregion->erp_table->objagg, objagg_obj);
mutex_lock(&erp_table->objagg_lock);
objagg_obj_put(erp_table->objagg, objagg_obj);
mutex_unlock(&erp_table->objagg_lock);
}

int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp,
Expand All @@ -1034,7 +1037,6 @@ int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp,
const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
unsigned int erp_bank;

ASSERT_RTNL();
if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
return 0;

Expand Down Expand Up @@ -1334,6 +1336,7 @@ mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion,
erp_table->ops = &erp_no_mask_ops;
INIT_LIST_HEAD(&erp_table->atcam_erps_list);
erp_table->aregion = aregion;
mutex_init(&erp_table->objagg_lock);

return erp_table;

Expand All @@ -1346,6 +1349,7 @@ static void
mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
{
WARN_ON(!list_empty(&erp_table->atcam_erps_list));
mutex_destroy(&erp_table->objagg_lock);
objagg_destroy(erp_table->objagg);
kfree(erp_table);
}
Expand Down Expand Up @@ -1376,14 +1380,16 @@ mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_acl_atcam_region *aregion,
struct objagg_hints *hints, bool *p_rehash_needed)
{
struct objagg *objagg = aregion->erp_table->objagg;
struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
const struct objagg_stats *ostats;
const struct objagg_stats *hstats;
int err;

*p_rehash_needed = false;

ostats = objagg_stats_get(objagg);
mutex_lock(&erp_table->objagg_lock);
ostats = objagg_stats_get(erp_table->objagg);
mutex_unlock(&erp_table->objagg_lock);
if (IS_ERR(ostats)) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP stats\n");
return PTR_ERR(ostats);
Expand Down Expand Up @@ -1411,13 +1417,16 @@ mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp *mlxsw_sp,
void *
mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
{
struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
struct objagg_hints *hints;
bool rehash_needed;
int err;

hints = objagg_hints_get(aregion->erp_table->objagg,
mutex_lock(&erp_table->objagg_lock);
hints = objagg_hints_get(erp_table->objagg,
OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
mutex_unlock(&erp_table->objagg_lock);
if (IS_ERR(hints)) {
dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to create ERP hints\n");
return ERR_CAST(hints);
Expand Down
Loading

0 comments on commit 834f9b0

Please sign in to comment.