cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

spectrum_acl_erp.c (45538B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
      3
      4#include <linux/bitmap.h>
      5#include <linux/errno.h>
      6#include <linux/genalloc.h>
      7#include <linux/gfp.h>
      8#include <linux/kernel.h>
      9#include <linux/list.h>
     10#include <linux/mutex.h>
     11#include <linux/objagg.h>
     12#include <linux/rtnetlink.h>
     13#include <linux/slab.h>
     14
     15#include "core.h"
     16#include "reg.h"
     17#include "spectrum.h"
     18#include "spectrum_acl_tcam.h"
     19
     20/* gen_pool_alloc() returns 0 when allocation fails, so use an offset */
     21#define MLXSW_SP_ACL_ERP_GENALLOC_OFFSET 0x100
     22#define MLXSW_SP_ACL_ERP_MAX_PER_REGION 16
     23
     24struct mlxsw_sp_acl_erp_core {
     25	unsigned int erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX + 1];
     26	struct gen_pool *erp_tables;
     27	struct mlxsw_sp *mlxsw_sp;
     28	struct mlxsw_sp_acl_bf *bf;
     29	unsigned int num_erp_banks;
     30};
     31
     32struct mlxsw_sp_acl_erp_key {
     33	char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN];
     34#define __MASK_LEN 0x38
     35#define __MASK_IDX(i) (__MASK_LEN - (i) - 1)
     36	bool ctcam;
     37};
     38
     39struct mlxsw_sp_acl_erp {
     40	struct mlxsw_sp_acl_erp_key key;
     41	u8 id;
     42	u8 index;
     43	DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
     44	struct list_head list;
     45	struct mlxsw_sp_acl_erp_table *erp_table;
     46};
     47
     48struct mlxsw_sp_acl_erp_master_mask {
     49	DECLARE_BITMAP(bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
     50	unsigned int count[MLXSW_SP_ACL_TCAM_MASK_LEN];
     51};
     52
     53struct mlxsw_sp_acl_erp_table {
     54	struct mlxsw_sp_acl_erp_master_mask master_mask;
     55	DECLARE_BITMAP(erp_id_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
     56	DECLARE_BITMAP(erp_index_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
     57	struct list_head atcam_erps_list;
     58	struct mlxsw_sp_acl_erp_core *erp_core;
     59	struct mlxsw_sp_acl_atcam_region *aregion;
     60	const struct mlxsw_sp_acl_erp_table_ops *ops;
     61	unsigned long base_index;
     62	unsigned int num_atcam_erps;
     63	unsigned int num_max_atcam_erps;
     64	unsigned int num_ctcam_erps;
     65	unsigned int num_deltas;
     66	struct objagg *objagg;
     67	struct mutex objagg_lock; /* guards objagg manipulation */
     68};
     69
     70struct mlxsw_sp_acl_erp_table_ops {
     71	struct mlxsw_sp_acl_erp *
     72		(*erp_create)(struct mlxsw_sp_acl_erp_table *erp_table,
     73			      struct mlxsw_sp_acl_erp_key *key);
     74	void (*erp_destroy)(struct mlxsw_sp_acl_erp_table *erp_table,
     75			    struct mlxsw_sp_acl_erp *erp);
     76};
     77
     78static struct mlxsw_sp_acl_erp *
     79mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
     80			     struct mlxsw_sp_acl_erp_key *key);
     81static void
     82mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
     83			      struct mlxsw_sp_acl_erp *erp);
     84static struct mlxsw_sp_acl_erp *
     85mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
     86				    struct mlxsw_sp_acl_erp_key *key);
     87static void
     88mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
     89				     struct mlxsw_sp_acl_erp *erp);
     90static struct mlxsw_sp_acl_erp *
     91mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
     92				   struct mlxsw_sp_acl_erp_key *key);
     93static void
     94mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
     95				    struct mlxsw_sp_acl_erp *erp);
     96static void
     97mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
     98				 struct mlxsw_sp_acl_erp *erp);
     99
    100static const struct mlxsw_sp_acl_erp_table_ops erp_multiple_masks_ops = {
    101	.erp_create = mlxsw_sp_acl_erp_mask_create,
    102	.erp_destroy = mlxsw_sp_acl_erp_mask_destroy,
    103};
    104
    105static const struct mlxsw_sp_acl_erp_table_ops erp_two_masks_ops = {
    106	.erp_create = mlxsw_sp_acl_erp_mask_create,
    107	.erp_destroy = mlxsw_sp_acl_erp_second_mask_destroy,
    108};
    109
    110static const struct mlxsw_sp_acl_erp_table_ops erp_single_mask_ops = {
    111	.erp_create = mlxsw_sp_acl_erp_second_mask_create,
    112	.erp_destroy = mlxsw_sp_acl_erp_first_mask_destroy,
    113};
    114
    115static const struct mlxsw_sp_acl_erp_table_ops erp_no_mask_ops = {
    116	.erp_create = mlxsw_sp_acl_erp_first_mask_create,
    117	.erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy,
    118};
    119
    120static bool
    121mlxsw_sp_acl_erp_table_is_used(const struct mlxsw_sp_acl_erp_table *erp_table)
    122{
    123	return erp_table->ops != &erp_single_mask_ops &&
    124	       erp_table->ops != &erp_no_mask_ops;
    125}
    126
    127static unsigned int
    128mlxsw_sp_acl_erp_bank_get(const struct mlxsw_sp_acl_erp *erp)
    129{
    130	return erp->index % erp->erp_table->erp_core->num_erp_banks;
    131}
    132
    133static unsigned int
    134mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table)
    135{
    136	struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
    137	struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
    138
    139	return erp_core->erpt_entries_size[aregion->type];
    140}
    141
    142static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table,
    143				   u8 *p_id)
    144{
    145	u8 id;
    146
    147	id = find_first_zero_bit(erp_table->erp_id_bitmap,
    148				 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
    149	if (id < MLXSW_SP_ACL_ERP_MAX_PER_REGION) {
    150		__set_bit(id, erp_table->erp_id_bitmap);
    151		*p_id = id;
    152		return 0;
    153	}
    154
    155	return -ENOBUFS;
    156}
    157
    158static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table,
    159				    u8 id)
    160{
    161	__clear_bit(id, erp_table->erp_id_bitmap);
    162}
    163
    164static void
    165mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit,
    166				     struct mlxsw_sp_acl_erp_master_mask *mask)
    167{
    168	if (mask->count[bit]++ == 0)
    169		__set_bit(bit, mask->bitmap);
    170}
    171
    172static void
    173mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit,
    174				       struct mlxsw_sp_acl_erp_master_mask *mask)
    175{
    176	if (--mask->count[bit] == 0)
    177		__clear_bit(bit, mask->bitmap);
    178}
    179
    180static int
    181mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table)
    182{
    183	struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
    184	struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
    185	char percr_pl[MLXSW_REG_PERCR_LEN];
    186	char *master_mask;
    187
    188	mlxsw_reg_percr_pack(percr_pl, region->id);
    189	master_mask = mlxsw_reg_percr_master_mask_data(percr_pl);
    190	bitmap_to_arr32((u32 *) master_mask, erp_table->master_mask.bitmap,
    191			MLXSW_SP_ACL_TCAM_MASK_LEN);
    192
    193	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
    194}
    195
    196static int
    197mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table,
    198				 struct mlxsw_sp_acl_erp_key *key)
    199{
    200	DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
    201	unsigned long bit;
    202	int err;
    203
    204	bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
    205			  MLXSW_SP_ACL_TCAM_MASK_LEN);
    206	for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
    207		mlxsw_sp_acl_erp_master_mask_bit_set(bit,
    208						     &erp_table->master_mask);
    209
    210	err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
    211	if (err)
    212		goto err_master_mask_update;
    213
    214	return 0;
    215
    216err_master_mask_update:
    217	for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
    218		mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
    219						       &erp_table->master_mask);
    220	return err;
    221}
    222
    223static int
    224mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table,
    225				   struct mlxsw_sp_acl_erp_key *key)
    226{
    227	DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
    228	unsigned long bit;
    229	int err;
    230
    231	bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
    232			  MLXSW_SP_ACL_TCAM_MASK_LEN);
    233	for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
    234		mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
    235						       &erp_table->master_mask);
    236
    237	err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
    238	if (err)
    239		goto err_master_mask_update;
    240
    241	return 0;
    242
    243err_master_mask_update:
    244	for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
    245		mlxsw_sp_acl_erp_master_mask_bit_set(bit,
    246						     &erp_table->master_mask);
    247	return err;
    248}
    249
    250static struct mlxsw_sp_acl_erp *
    251mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
    252				struct mlxsw_sp_acl_erp_key *key)
    253{
    254	struct mlxsw_sp_acl_erp *erp;
    255	int err;
    256
    257	erp = kzalloc(sizeof(*erp), GFP_KERNEL);
    258	if (!erp)
    259		return ERR_PTR(-ENOMEM);
    260
    261	err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id);
    262	if (err)
    263		goto err_erp_id_get;
    264
    265	memcpy(&erp->key, key, sizeof(*key));
    266	list_add(&erp->list, &erp_table->atcam_erps_list);
    267	erp_table->num_atcam_erps++;
    268	erp->erp_table = erp_table;
    269
    270	err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
    271	if (err)
    272		goto err_master_mask_set;
    273
    274	return erp;
    275
    276err_master_mask_set:
    277	erp_table->num_atcam_erps--;
    278	list_del(&erp->list);
    279	mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
    280err_erp_id_get:
    281	kfree(erp);
    282	return ERR_PTR(err);
    283}
    284
    285static void
    286mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp)
    287{
    288	struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
    289
    290	mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
    291	erp_table->num_atcam_erps--;
    292	list_del(&erp->list);
    293	mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
    294	kfree(erp);
    295}
    296
    297static int
    298mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
    299			     unsigned int num_erps,
    300			     enum mlxsw_sp_acl_atcam_region_type region_type,
    301			     unsigned long *p_index)
    302{
    303	unsigned int num_rows, entry_size;
    304
    305	/* We only allow allocations of entire rows */
    306	if (num_erps % erp_core->num_erp_banks != 0)
    307		return -EINVAL;
    308
    309	entry_size = erp_core->erpt_entries_size[region_type];
    310	num_rows = num_erps / erp_core->num_erp_banks;
    311
    312	*p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
    313	if (*p_index == 0)
    314		return -ENOBUFS;
    315	*p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
    316
    317	return 0;
    318}
    319
    320static void
    321mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core *erp_core,
    322			    unsigned int num_erps,
    323			    enum mlxsw_sp_acl_atcam_region_type region_type,
    324			    unsigned long index)
    325{
    326	unsigned long base_index;
    327	unsigned int entry_size;
    328	size_t size;
    329
    330	entry_size = erp_core->erpt_entries_size[region_type];
    331	base_index = index + MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
    332	size = num_erps / erp_core->num_erp_banks * entry_size;
    333	gen_pool_free(erp_core->erp_tables, base_index, size);
    334}
    335
    336static struct mlxsw_sp_acl_erp *
    337mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table)
    338{
    339	if (!list_is_singular(&erp_table->atcam_erps_list))
    340		return NULL;
    341
    342	return list_first_entry(&erp_table->atcam_erps_list,
    343				struct mlxsw_sp_acl_erp, list);
    344}
    345
    346static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table,
    347				      u8 *p_index)
    348{
    349	u8 index;
    350
    351	index = find_first_zero_bit(erp_table->erp_index_bitmap,
    352				    erp_table->num_max_atcam_erps);
    353	if (index < erp_table->num_max_atcam_erps) {
    354		__set_bit(index, erp_table->erp_index_bitmap);
    355		*p_index = index;
    356		return 0;
    357	}
    358
    359	return -ENOBUFS;
    360}
    361
    362static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table,
    363				       u8 index)
    364{
    365	__clear_bit(index, erp_table->erp_index_bitmap);
    366}
    367
    368static void
    369mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table *erp_table,
    370			      const struct mlxsw_sp_acl_erp *erp,
    371			      u8 *p_erpt_bank, u8 *p_erpt_index)
    372{
    373	unsigned int entry_size = mlxsw_sp_acl_erp_table_entry_size(erp_table);
    374	struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
    375	unsigned int row;
    376
    377	*p_erpt_bank = erp->index % erp_core->num_erp_banks;
    378	row = erp->index / erp_core->num_erp_banks;
    379	*p_erpt_index = erp_table->base_index + row * entry_size;
    380}
    381
    382static int
    383mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
    384			       struct mlxsw_sp_acl_erp *erp)
    385{
    386	struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
    387	enum mlxsw_reg_perpt_key_size key_size;
    388	char perpt_pl[MLXSW_REG_PERPT_LEN];
    389	u8 erpt_bank, erpt_index;
    390
    391	mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
    392	key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
    393	mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
    394			     0, erp_table->base_index, erp->index,
    395			     erp->key.mask);
    396	mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
    397					MLXSW_SP_ACL_ERP_MAX_PER_REGION);
    398	mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, true);
    399	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
    400}
    401
    402static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp)
    403{
    404	char empty_mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
    405	struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
    406	struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
    407	enum mlxsw_reg_perpt_key_size key_size;
    408	char perpt_pl[MLXSW_REG_PERPT_LEN];
    409	u8 erpt_bank, erpt_index;
    410
    411	mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
    412	key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
    413	mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
    414			     0, erp_table->base_index, erp->index, empty_mask);
    415	mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
    416					MLXSW_SP_ACL_ERP_MAX_PER_REGION);
    417	mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, false);
    418	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
    419}
    420
    421static int
    422mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table,
    423			      bool ctcam_le)
    424{
    425	struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
    426	struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
    427	char pererp_pl[MLXSW_REG_PERERP_LEN];
    428
    429	mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
    430			      erp_table->base_index, 0);
    431	mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
    432					 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
    433
    434	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
    435}
    436
    437static void
    438mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table)
    439{
    440	struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
    441	struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
    442	char pererp_pl[MLXSW_REG_PERERP_LEN];
    443	struct mlxsw_sp_acl_erp *master_rp;
    444
    445	master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
    446	/* It is possible we do not have a master RP when we disable the
    447	 * table when there are no rules in the A-TCAM and the last C-TCAM
    448	 * rule is deleted
    449	 */
    450	mlxsw_reg_pererp_pack(pererp_pl, region->id, false, false, 0, 0,
    451			      master_rp ? master_rp->id : 0);
    452	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
    453}
    454
    455static int
    456mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table)
    457{
    458	struct mlxsw_sp_acl_erp *erp;
    459	int err;
    460
    461	list_for_each_entry(erp, &erp_table->atcam_erps_list, list) {
    462		err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
    463		if (err)
    464			goto err_table_erp_add;
    465	}
    466
    467	return 0;
    468
    469err_table_erp_add:
    470	list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list,
    471					     list)
    472		mlxsw_sp_acl_erp_table_erp_del(erp);
    473	return err;
    474}
    475
    476static int
    477mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table)
    478{
    479	unsigned int num_erps, old_num_erps = erp_table->num_max_atcam_erps;
    480	struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
    481	unsigned long old_base_index = erp_table->base_index;
    482	bool ctcam_le = erp_table->num_ctcam_erps > 0;
    483	int err;
    484
    485	if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps)
    486		return 0;
    487
    488	if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION)
    489		return -ENOBUFS;
    490
    491	num_erps = old_num_erps + erp_core->num_erp_banks;
    492	err = mlxsw_sp_acl_erp_table_alloc(erp_core, num_erps,
    493					   erp_table->aregion->type,
    494					   &erp_table->base_index);
    495	if (err)
    496		return err;
    497	erp_table->num_max_atcam_erps = num_erps;
    498
    499	err = mlxsw_sp_acl_erp_table_relocate(erp_table);
    500	if (err)
    501		goto err_table_relocate;
    502
    503	err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le);
    504	if (err)
    505		goto err_table_enable;
    506
    507	mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps,
    508				    erp_table->aregion->type, old_base_index);
    509
    510	return 0;
    511
    512err_table_enable:
    513err_table_relocate:
    514	erp_table->num_max_atcam_erps = old_num_erps;
    515	mlxsw_sp_acl_erp_table_free(erp_core, num_erps,
    516				    erp_table->aregion->type,
    517				    erp_table->base_index);
    518	erp_table->base_index = old_base_index;
    519	return err;
    520}
    521
    522static int
    523mlxsw_acl_erp_table_bf_add(struct mlxsw_sp_acl_erp_table *erp_table,
    524			   struct mlxsw_sp_acl_erp *erp)
    525{
    526	struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
    527	unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
    528	struct mlxsw_sp_acl_atcam_entry *aentry;
    529	int err;
    530
    531	list_for_each_entry(aentry, &aregion->entries_list, list) {
    532		err = mlxsw_sp_acl_bf_entry_add(aregion->region->mlxsw_sp,
    533						erp_table->erp_core->bf,
    534						aregion, erp_bank, aentry);
    535		if (err)
    536			goto bf_entry_add_err;
    537	}
    538
    539	return 0;
    540
    541bf_entry_add_err:
    542	list_for_each_entry_continue_reverse(aentry, &aregion->entries_list,
    543					     list)
    544		mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
    545					  erp_table->erp_core->bf,
    546					  aregion, erp_bank, aentry);
    547	return err;
    548}
    549
    550static void
    551mlxsw_acl_erp_table_bf_del(struct mlxsw_sp_acl_erp_table *erp_table,
    552			   struct mlxsw_sp_acl_erp *erp)
    553{
    554	struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
    555	unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
    556	struct mlxsw_sp_acl_atcam_entry *aentry;
    557
    558	list_for_each_entry_reverse(aentry, &aregion->entries_list, list)
    559		mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
    560					  erp_table->erp_core->bf,
    561					  aregion, erp_bank, aentry);
    562}
    563
    564static int
    565mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table)
    566{
    567	struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
    568	struct mlxsw_sp_acl_erp *master_rp;
    569	int err;
    570
    571	/* Initially, allocate a single eRP row. Expand later as needed */
    572	err = mlxsw_sp_acl_erp_table_alloc(erp_core, erp_core->num_erp_banks,
    573					   erp_table->aregion->type,
    574					   &erp_table->base_index);
    575	if (err)
    576		return err;
    577	erp_table->num_max_atcam_erps = erp_core->num_erp_banks;
    578
    579	/* Transition the sole RP currently configured (the master RP)
    580	 * to the eRP table
    581	 */
    582	master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
    583	if (!master_rp) {
    584		err = -EINVAL;
    585		goto err_table_master_rp;
    586	}
    587
    588	/* Make sure the master RP is using a valid index, as
    589	 * only a single eRP row is currently allocated.
    590	 */
    591	master_rp->index = 0;
    592	__set_bit(master_rp->index, erp_table->erp_index_bitmap);
    593
    594	err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp);
    595	if (err)
    596		goto err_table_master_rp_add;
    597
    598	/* Update Bloom filter before enabling eRP table, as rules
    599	 * on the master RP were not set to Bloom filter up to this
    600	 * point.
    601	 */
    602	err = mlxsw_acl_erp_table_bf_add(erp_table, master_rp);
    603	if (err)
    604		goto err_table_bf_add;
    605
    606	err = mlxsw_sp_acl_erp_table_enable(erp_table, false);
    607	if (err)
    608		goto err_table_enable;
    609
    610	return 0;
    611
    612err_table_enable:
    613	mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
    614err_table_bf_add:
    615	mlxsw_sp_acl_erp_table_erp_del(master_rp);
    616err_table_master_rp_add:
    617	__clear_bit(master_rp->index, erp_table->erp_index_bitmap);
    618err_table_master_rp:
    619	mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
    620				    erp_table->aregion->type,
    621				    erp_table->base_index);
    622	return err;
    623}
    624
    625static void
    626mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table)
    627{
    628	struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
    629	struct mlxsw_sp_acl_erp *master_rp;
    630
    631	mlxsw_sp_acl_erp_table_disable(erp_table);
    632	master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
    633	if (!master_rp)
    634		return;
    635	mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
    636	mlxsw_sp_acl_erp_table_erp_del(master_rp);
    637	__clear_bit(master_rp->index, erp_table->erp_index_bitmap);
    638	mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
    639				    erp_table->aregion->type,
    640				    erp_table->base_index);
    641}
    642
    643static int
    644mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
    645				struct mlxsw_sp_acl_erp *erp)
    646{
    647	struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
    648	struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
    649	bool ctcam_le = erp_table->num_ctcam_erps > 0;
    650	char pererp_pl[MLXSW_REG_PERERP_LEN];
    651
    652	mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
    653			      erp_table->base_index, 0);
    654	mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
    655					 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
    656	mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, true);
    657
    658	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
    659}
    660
    661static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp)
    662{
    663	struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
    664	struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
    665	struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
    666	bool ctcam_le = erp_table->num_ctcam_erps > 0;
    667	char pererp_pl[MLXSW_REG_PERERP_LEN];
    668
    669	mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
    670			      erp_table->base_index, 0);
    671	mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
    672					 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
    673	mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, false);
    674
    675	mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
    676}
    677
    678static int
    679mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table)
    680{
    681	/* No need to re-enable lookup in the C-TCAM */
    682	if (erp_table->num_ctcam_erps > 1)
    683		return 0;
    684
    685	return mlxsw_sp_acl_erp_table_enable(erp_table, true);
    686}
    687
    688static void
    689mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table)
    690{
    691	/* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */
    692	if (erp_table->num_ctcam_erps > 1)
    693		return;
    694
    695	mlxsw_sp_acl_erp_table_enable(erp_table, false);
    696}
    697
    698static int
    699__mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
    700				   unsigned int *inc_num)
    701{
    702	int err;
    703
    704	/* If there are C-TCAM eRP or deltas in use we need to transition
    705	 * the region to use eRP table, if it is not already done
    706	 */
    707	if (!mlxsw_sp_acl_erp_table_is_used(erp_table)) {
    708		err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
    709		if (err)
    710			return err;
    711	}
    712
    713	/* When C-TCAM or deltas are used, the eRP table must be used */
    714	if (erp_table->ops != &erp_multiple_masks_ops)
    715		erp_table->ops = &erp_multiple_masks_ops;
    716
    717	(*inc_num)++;
    718
    719	return 0;
    720}
    721
    722static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table)
    723{
    724	return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
    725						  &erp_table->num_ctcam_erps);
    726}
    727
    728static int mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table *erp_table)
    729{
    730	return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
    731						  &erp_table->num_deltas);
    732}
    733
    734static void
    735__mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table *erp_table,
    736				   unsigned int *dec_num)
    737{
    738	(*dec_num)--;
    739
    740	/* If there are no C-TCAM eRP or deltas in use, the state we
    741	 * transition to depends on the number of A-TCAM eRPs currently
    742	 * in use.
    743	 */
    744	if (erp_table->num_ctcam_erps > 0 || erp_table->num_deltas > 0)
    745		return;
    746
    747	switch (erp_table->num_atcam_erps) {
    748	case 2:
    749		/* Keep using the eRP table, but correctly set the
    750		 * operations pointer so that when an A-TCAM eRP is
    751		 * deleted we will transition to use the master mask
    752		 */
    753		erp_table->ops = &erp_two_masks_ops;
    754		break;
    755	case 1:
    756		/* We only kept the eRP table because we had C-TCAM
    757		 * eRPs in use. Now that the last C-TCAM eRP is gone we
    758		 * can stop using the table and transition to use the
    759		 * master mask
    760		 */
    761		mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
    762		erp_table->ops = &erp_single_mask_ops;
    763		break;
    764	case 0:
    765		/* There are no more eRPs of any kind used by the region
    766		 * so free its eRP table and transition to initial state
    767		 */
    768		mlxsw_sp_acl_erp_table_disable(erp_table);
    769		mlxsw_sp_acl_erp_table_free(erp_table->erp_core,
    770					    erp_table->num_max_atcam_erps,
    771					    erp_table->aregion->type,
    772					    erp_table->base_index);
    773		erp_table->ops = &erp_no_mask_ops;
    774		break;
    775	default:
    776		break;
    777	}
    778}
    779
    780static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table)
    781{
    782	__mlxsw_sp_acl_erp_table_other_dec(erp_table,
    783					   &erp_table->num_ctcam_erps);
    784}
    785
    786static void mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table *erp_table)
    787{
    788	__mlxsw_sp_acl_erp_table_other_dec(erp_table,
    789					   &erp_table->num_deltas);
    790}
    791
    792static struct mlxsw_sp_acl_erp *
    793mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
    794				   struct mlxsw_sp_acl_erp_key *key)
    795{
    796	struct mlxsw_sp_acl_erp *erp;
    797	int err;
    798
    799	erp = kzalloc(sizeof(*erp), GFP_KERNEL);
    800	if (!erp)
    801		return ERR_PTR(-ENOMEM);
    802
    803	memcpy(&erp->key, key, sizeof(*key));
    804	bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask,
    805			  MLXSW_SP_ACL_TCAM_MASK_LEN);
    806
    807	err = mlxsw_sp_acl_erp_ctcam_inc(erp_table);
    808	if (err)
    809		goto err_erp_ctcam_inc;
    810
    811	erp->erp_table = erp_table;
    812
    813	err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
    814	if (err)
    815		goto err_master_mask_set;
    816
    817	err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table);
    818	if (err)
    819		goto err_erp_region_ctcam_enable;
    820
    821	return erp;
    822
    823err_erp_region_ctcam_enable:
    824	mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
    825err_master_mask_set:
    826	mlxsw_sp_acl_erp_ctcam_dec(erp_table);
    827err_erp_ctcam_inc:
    828	kfree(erp);
    829	return ERR_PTR(err);
    830}
    831
    832static void
    833mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp)
    834{
    835	struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
    836
    837	mlxsw_sp_acl_erp_region_ctcam_disable(erp_table);
    838	mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
    839	mlxsw_sp_acl_erp_ctcam_dec(erp_table);
    840	kfree(erp);
    841}
    842
    843static struct mlxsw_sp_acl_erp *
    844mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
    845			     struct mlxsw_sp_acl_erp_key *key)
    846{
    847	struct mlxsw_sp_acl_erp *erp;
    848	int err;
    849
    850	if (key->ctcam)
    851		return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
    852
    853	/* Expand the eRP table for the new eRP, if needed */
    854	err = mlxsw_sp_acl_erp_table_expand(erp_table);
    855	if (err)
    856		return ERR_PTR(err);
    857
    858	erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
    859	if (IS_ERR(erp))
    860		return erp;
    861
    862	err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
    863	if (err)
    864		goto err_erp_index_get;
    865
    866	err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
    867	if (err)
    868		goto err_table_erp_add;
    869
    870	err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
    871	if (err)
    872		goto err_region_erp_add;
    873
    874	erp_table->ops = &erp_multiple_masks_ops;
    875
    876	return erp;
    877
    878err_region_erp_add:
    879	mlxsw_sp_acl_erp_table_erp_del(erp);
    880err_table_erp_add:
    881	mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
    882err_erp_index_get:
    883	mlxsw_sp_acl_erp_generic_destroy(erp);
    884	return ERR_PTR(err);
    885}
    886
    887static void
    888mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
    889			      struct mlxsw_sp_acl_erp *erp)
    890{
    891	if (erp->key.ctcam)
    892		return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
    893
    894	mlxsw_sp_acl_erp_region_erp_del(erp);
    895	mlxsw_sp_acl_erp_table_erp_del(erp);
    896	mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
    897	mlxsw_sp_acl_erp_generic_destroy(erp);
    898
    899	if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0 &&
    900	    erp_table->num_deltas == 0)
    901		erp_table->ops = &erp_two_masks_ops;
    902}
    903
    904static struct mlxsw_sp_acl_erp *
    905mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
    906				    struct mlxsw_sp_acl_erp_key *key)
    907{
    908	struct mlxsw_sp_acl_erp *erp;
    909	int err;
    910
    911	if (key->ctcam)
    912		return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
    913
    914	/* Transition to use eRP table instead of master mask */
    915	err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
    916	if (err)
    917		return ERR_PTR(err);
    918
    919	erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
    920	if (IS_ERR(erp)) {
    921		err = PTR_ERR(erp);
    922		goto err_erp_create;
    923	}
    924
    925	err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
    926	if (err)
    927		goto err_erp_index_get;
    928
    929	err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
    930	if (err)
    931		goto err_table_erp_add;
    932
    933	err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
    934	if (err)
    935		goto err_region_erp_add;
    936
    937	erp_table->ops = &erp_two_masks_ops;
    938
    939	return erp;
    940
    941err_region_erp_add:
    942	mlxsw_sp_acl_erp_table_erp_del(erp);
    943err_table_erp_add:
    944	mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
    945err_erp_index_get:
    946	mlxsw_sp_acl_erp_generic_destroy(erp);
    947err_erp_create:
    948	mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
    949	return ERR_PTR(err);
    950}
    951
    952static void
    953mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
    954				     struct mlxsw_sp_acl_erp *erp)
    955{
    956	if (erp->key.ctcam)
    957		return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
    958
    959	mlxsw_sp_acl_erp_region_erp_del(erp);
    960	mlxsw_sp_acl_erp_table_erp_del(erp);
    961	mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
    962	mlxsw_sp_acl_erp_generic_destroy(erp);
    963	/* Transition to use master mask instead of eRP table */
    964	mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
    965
    966	erp_table->ops = &erp_single_mask_ops;
    967}
    968
    969static struct mlxsw_sp_acl_erp *
    970mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
    971				   struct mlxsw_sp_acl_erp_key *key)
    972{
    973	struct mlxsw_sp_acl_erp *erp;
    974
    975	if (key->ctcam)
    976		return ERR_PTR(-EINVAL);
    977
    978	erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
    979	if (IS_ERR(erp))
    980		return erp;
    981
    982	erp_table->ops = &erp_single_mask_ops;
    983
    984	return erp;
    985}
    986
    987static void
    988mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
    989				    struct mlxsw_sp_acl_erp *erp)
    990{
    991	mlxsw_sp_acl_erp_generic_destroy(erp);
    992	erp_table->ops = &erp_no_mask_ops;
    993}
    994
    995static void
    996mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
    997				 struct mlxsw_sp_acl_erp *erp)
    998{
    999	WARN_ON(1);
   1000}
   1001
   1002struct mlxsw_sp_acl_erp_mask *
   1003mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion,
   1004			  const char *mask, bool ctcam)
   1005{
   1006	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1007	struct mlxsw_sp_acl_erp_key key;
   1008	struct objagg_obj *objagg_obj;
   1009
   1010	memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN);
   1011	key.ctcam = ctcam;
   1012	mutex_lock(&erp_table->objagg_lock);
   1013	objagg_obj = objagg_obj_get(erp_table->objagg, &key);
   1014	mutex_unlock(&erp_table->objagg_lock);
   1015	if (IS_ERR(objagg_obj))
   1016		return ERR_CAST(objagg_obj);
   1017	return (struct mlxsw_sp_acl_erp_mask *) objagg_obj;
   1018}
   1019
   1020void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion,
   1021			       struct mlxsw_sp_acl_erp_mask *erp_mask)
   1022{
   1023	struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
   1024	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1025
   1026	mutex_lock(&erp_table->objagg_lock);
   1027	objagg_obj_put(erp_table->objagg, objagg_obj);
   1028	mutex_unlock(&erp_table->objagg_lock);
   1029}
   1030
   1031int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp,
   1032			       struct mlxsw_sp_acl_atcam_region *aregion,
   1033			       struct mlxsw_sp_acl_erp_mask *erp_mask,
   1034			       struct mlxsw_sp_acl_atcam_entry *aentry)
   1035{
   1036	struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
   1037	const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
   1038	unsigned int erp_bank;
   1039
   1040	if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
   1041		return 0;
   1042
   1043	erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
   1044	return mlxsw_sp_acl_bf_entry_add(mlxsw_sp,
   1045					erp->erp_table->erp_core->bf,
   1046					aregion, erp_bank, aentry);
   1047}
   1048
   1049void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp,
   1050				struct mlxsw_sp_acl_atcam_region *aregion,
   1051				struct mlxsw_sp_acl_erp_mask *erp_mask,
   1052				struct mlxsw_sp_acl_atcam_entry *aentry)
   1053{
   1054	struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
   1055	const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
   1056	unsigned int erp_bank;
   1057
   1058	if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
   1059		return;
   1060
   1061	erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
   1062	mlxsw_sp_acl_bf_entry_del(mlxsw_sp,
   1063				  erp->erp_table->erp_core->bf,
   1064				  aregion, erp_bank, aentry);
   1065}
   1066
   1067bool
   1068mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask)
   1069{
   1070	struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
   1071	const struct mlxsw_sp_acl_erp_key *key = objagg_obj_raw(objagg_obj);
   1072
   1073	return key->ctcam;
   1074}
   1075
   1076u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
   1077{
   1078	struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
   1079	const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
   1080
   1081	return erp->id;
   1082}
   1083
   1084struct mlxsw_sp_acl_erp_delta {
   1085	struct mlxsw_sp_acl_erp_key key;
   1086	u16 start;
   1087	u8 mask;
   1088};
   1089
   1090u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta)
   1091{
   1092	return delta->start;
   1093}
   1094
   1095u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta)
   1096{
   1097	return delta->mask;
   1098}
   1099
   1100u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta,
   1101				const char *enc_key)
   1102{
   1103	u16 start = delta->start;
   1104	u8 mask = delta->mask;
   1105	u16 tmp;
   1106
   1107	if (!mask)
   1108		return 0;
   1109
   1110	tmp = (unsigned char) enc_key[__MASK_IDX(start / 8)];
   1111	if (start / 8 + 1 < __MASK_LEN)
   1112		tmp |= (unsigned char) enc_key[__MASK_IDX(start / 8 + 1)] << 8;
   1113	tmp >>= start % 8;
   1114	tmp &= mask;
   1115	return tmp;
   1116}
   1117
   1118void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta,
   1119				  const char *enc_key)
   1120{
   1121	u16 start = delta->start;
   1122	u8 mask = delta->mask;
   1123	unsigned char *byte;
   1124	u16 tmp;
   1125
   1126	tmp = mask;
   1127	tmp <<= start % 8;
   1128	tmp = ~tmp;
   1129
   1130	byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8)];
   1131	*byte &= tmp & 0xff;
   1132	if (start / 8 + 1 < __MASK_LEN) {
   1133		byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8 + 1)];
   1134		*byte &= (tmp >> 8) & 0xff;
   1135	}
   1136}
   1137
   1138static const struct mlxsw_sp_acl_erp_delta
   1139mlxsw_sp_acl_erp_delta_default = {};
   1140
   1141const struct mlxsw_sp_acl_erp_delta *
   1142mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask)
   1143{
   1144	struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
   1145	const struct mlxsw_sp_acl_erp_delta *delta;
   1146
   1147	delta = objagg_obj_delta_priv(objagg_obj);
   1148	if (!delta)
   1149		delta = &mlxsw_sp_acl_erp_delta_default;
   1150	return delta;
   1151}
   1152
   1153static int
   1154mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key,
   1155			    const struct mlxsw_sp_acl_erp_key *key,
   1156			    u16 *delta_start, u8 *delta_mask)
   1157{
   1158	int offset = 0;
   1159	int si = -1;
   1160	u16 pmask;
   1161	u16 mask;
   1162	int i;
   1163
   1164	/* The difference between 2 masks can be up to 8 consecutive bits. */
   1165	for (i = 0; i < __MASK_LEN; i++) {
   1166		if (parent_key->mask[__MASK_IDX(i)] == key->mask[__MASK_IDX(i)])
   1167			continue;
   1168		if (si == -1)
   1169			si = i;
   1170		else if (si != i - 1)
   1171			return -EINVAL;
   1172	}
   1173	if (si == -1) {
   1174		/* The masks are the same, this can happen in case eRPs with
   1175		 * the same mask were created in both A-TCAM and C-TCAM.
   1176		 * The only possible condition under which this can happen
   1177		 * is identical rule insertion. Delta is not possible here.
   1178		 */
   1179		return -EINVAL;
   1180	}
   1181	pmask = (unsigned char) parent_key->mask[__MASK_IDX(si)];
   1182	mask = (unsigned char) key->mask[__MASK_IDX(si)];
   1183	if (si + 1 < __MASK_LEN) {
   1184		pmask |= (unsigned char) parent_key->mask[__MASK_IDX(si + 1)] << 8;
   1185		mask |= (unsigned char) key->mask[__MASK_IDX(si + 1)] << 8;
   1186	}
   1187
   1188	if ((pmask ^ mask) & pmask)
   1189		return -EINVAL;
   1190	mask &= ~pmask;
   1191	while (!(mask & (1 << offset)))
   1192		offset++;
   1193	while (!(mask & 1))
   1194		mask >>= 1;
   1195	if (mask & 0xff00)
   1196		return -EINVAL;
   1197
   1198	*delta_start = si * 8 + offset;
   1199	*delta_mask = mask;
   1200
   1201	return 0;
   1202}
   1203
   1204static bool mlxsw_sp_acl_erp_delta_check(void *priv, const void *parent_obj,
   1205					 const void *obj)
   1206{
   1207	const struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
   1208	const struct mlxsw_sp_acl_erp_key *key = obj;
   1209	u16 delta_start;
   1210	u8 delta_mask;
   1211	int err;
   1212
   1213	err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
   1214					  &delta_start, &delta_mask);
   1215	return err ? false : true;
   1216}
   1217
   1218static int mlxsw_sp_acl_erp_hints_obj_cmp(const void *obj1, const void *obj2)
   1219{
   1220	const struct mlxsw_sp_acl_erp_key *key1 = obj1;
   1221	const struct mlxsw_sp_acl_erp_key *key2 = obj2;
   1222
   1223	/* For hints purposes, two objects are considered equal
   1224	 * in case the masks are the same. Does not matter what
   1225	 * the "ctcam" value is.
   1226	 */
   1227	return memcmp(key1->mask, key2->mask, sizeof(key1->mask));
   1228}
   1229
   1230static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
   1231					   void *obj)
   1232{
   1233	struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
   1234	struct mlxsw_sp_acl_atcam_region *aregion = priv;
   1235	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1236	struct mlxsw_sp_acl_erp_key *key = obj;
   1237	struct mlxsw_sp_acl_erp_delta *delta;
   1238	u16 delta_start;
   1239	u8 delta_mask;
   1240	int err;
   1241
   1242	if (parent_key->ctcam || key->ctcam)
   1243		return ERR_PTR(-EINVAL);
   1244	err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
   1245					  &delta_start, &delta_mask);
   1246	if (err)
   1247		return ERR_PTR(-EINVAL);
   1248
   1249	delta = kzalloc(sizeof(*delta), GFP_KERNEL);
   1250	if (!delta)
   1251		return ERR_PTR(-ENOMEM);
   1252	delta->start = delta_start;
   1253	delta->mask = delta_mask;
   1254
   1255	err = mlxsw_sp_acl_erp_delta_inc(erp_table);
   1256	if (err)
   1257		goto err_erp_delta_inc;
   1258
   1259	memcpy(&delta->key, key, sizeof(*key));
   1260	err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key);
   1261	if (err)
   1262		goto err_master_mask_set;
   1263
   1264	return delta;
   1265
   1266err_master_mask_set:
   1267	mlxsw_sp_acl_erp_delta_dec(erp_table);
   1268err_erp_delta_inc:
   1269	kfree(delta);
   1270	return ERR_PTR(err);
   1271}
   1272
   1273static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
   1274{
   1275	struct mlxsw_sp_acl_erp_delta *delta = delta_priv;
   1276	struct mlxsw_sp_acl_atcam_region *aregion = priv;
   1277	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1278
   1279	mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key);
   1280	mlxsw_sp_acl_erp_delta_dec(erp_table);
   1281	kfree(delta);
   1282}
   1283
   1284static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj,
   1285					  unsigned int root_id)
   1286{
   1287	struct mlxsw_sp_acl_atcam_region *aregion = priv;
   1288	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1289	struct mlxsw_sp_acl_erp_key *key = obj;
   1290
   1291	if (!key->ctcam &&
   1292	    root_id != OBJAGG_OBJ_ROOT_ID_INVALID &&
   1293	    root_id >= MLXSW_SP_ACL_ERP_MAX_PER_REGION)
   1294		return ERR_PTR(-ENOBUFS);
   1295	return erp_table->ops->erp_create(erp_table, key);
   1296}
   1297
   1298static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
   1299{
   1300	struct mlxsw_sp_acl_atcam_region *aregion = priv;
   1301	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1302
   1303	erp_table->ops->erp_destroy(erp_table, root_priv);
   1304}
   1305
   1306static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
   1307	.obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
   1308	.delta_check = mlxsw_sp_acl_erp_delta_check,
   1309	.hints_obj_cmp = mlxsw_sp_acl_erp_hints_obj_cmp,
   1310	.delta_create = mlxsw_sp_acl_erp_delta_create,
   1311	.delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
   1312	.root_create = mlxsw_sp_acl_erp_root_create,
   1313	.root_destroy = mlxsw_sp_acl_erp_root_destroy,
   1314};
   1315
   1316static struct mlxsw_sp_acl_erp_table *
   1317mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion,
   1318			      struct objagg_hints *hints)
   1319{
   1320	struct mlxsw_sp_acl_erp_table *erp_table;
   1321	int err;
   1322
   1323	erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL);
   1324	if (!erp_table)
   1325		return ERR_PTR(-ENOMEM);
   1326
   1327	erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
   1328					  hints, aregion);
   1329	if (IS_ERR(erp_table->objagg)) {
   1330		err = PTR_ERR(erp_table->objagg);
   1331		goto err_objagg_create;
   1332	}
   1333
   1334	erp_table->erp_core = aregion->atcam->erp_core;
   1335	erp_table->ops = &erp_no_mask_ops;
   1336	INIT_LIST_HEAD(&erp_table->atcam_erps_list);
   1337	erp_table->aregion = aregion;
   1338	mutex_init(&erp_table->objagg_lock);
   1339
   1340	return erp_table;
   1341
   1342err_objagg_create:
   1343	kfree(erp_table);
   1344	return ERR_PTR(err);
   1345}
   1346
   1347static void
   1348mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
   1349{
   1350	WARN_ON(!list_empty(&erp_table->atcam_erps_list));
   1351	mutex_destroy(&erp_table->objagg_lock);
   1352	objagg_destroy(erp_table->objagg);
   1353	kfree(erp_table);
   1354}
   1355
   1356static int
   1357mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion)
   1358{
   1359	struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
   1360	char percr_pl[MLXSW_REG_PERCR_LEN];
   1361
   1362	mlxsw_reg_percr_pack(percr_pl, aregion->region->id);
   1363	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
   1364}
   1365
   1366static int
   1367mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
   1368{
   1369	struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
   1370	char pererp_pl[MLXSW_REG_PERERP_LEN];
   1371
   1372	mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0,
   1373			      0, 0);
   1374	return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
   1375}
   1376
   1377static int
   1378mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp *mlxsw_sp,
   1379			     struct mlxsw_sp_acl_atcam_region *aregion,
   1380			     struct objagg_hints *hints, bool *p_rehash_needed)
   1381{
   1382	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1383	const struct objagg_stats *ostats;
   1384	const struct objagg_stats *hstats;
   1385	int err;
   1386
   1387	*p_rehash_needed = false;
   1388
   1389	mutex_lock(&erp_table->objagg_lock);
   1390	ostats = objagg_stats_get(erp_table->objagg);
   1391	mutex_unlock(&erp_table->objagg_lock);
   1392	if (IS_ERR(ostats)) {
   1393		dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP stats\n");
   1394		return PTR_ERR(ostats);
   1395	}
   1396
   1397	hstats = objagg_hints_stats_get(hints);
   1398	if (IS_ERR(hstats)) {
   1399		dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP hints stats\n");
   1400		err = PTR_ERR(hstats);
   1401		goto err_hints_stats_get;
   1402	}
   1403
   1404	/* Very basic criterion for now. */
   1405	if (hstats->root_count < ostats->root_count)
   1406		*p_rehash_needed = true;
   1407
   1408	err = 0;
   1409
   1410	objagg_stats_put(hstats);
   1411err_hints_stats_get:
   1412	objagg_stats_put(ostats);
   1413	return err;
   1414}
   1415
   1416void *
   1417mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
   1418{
   1419	struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
   1420	struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
   1421	struct objagg_hints *hints;
   1422	bool rehash_needed;
   1423	int err;
   1424
   1425	mutex_lock(&erp_table->objagg_lock);
   1426	hints = objagg_hints_get(erp_table->objagg,
   1427				 OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
   1428	mutex_unlock(&erp_table->objagg_lock);
   1429	if (IS_ERR(hints)) {
   1430		dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to create ERP hints\n");
   1431		return ERR_CAST(hints);
   1432	}
   1433	err = mlxsw_sp_acl_erp_hints_check(mlxsw_sp, aregion, hints,
   1434					   &rehash_needed);
   1435	if (err)
   1436		goto errout;
   1437
   1438	if (!rehash_needed) {
   1439		err = -EAGAIN;
   1440		goto errout;
   1441	}
   1442	return hints;
   1443
   1444errout:
   1445	objagg_hints_put(hints);
   1446	return ERR_PTR(err);
   1447}
   1448
   1449void mlxsw_sp_acl_erp_rehash_hints_put(void *hints_priv)
   1450{
   1451	struct objagg_hints *hints = hints_priv;
   1452
   1453	objagg_hints_put(hints);
   1454}
   1455
   1456int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion,
   1457				 void *hints_priv)
   1458{
   1459	struct mlxsw_sp_acl_erp_table *erp_table;
   1460	struct objagg_hints *hints = hints_priv;
   1461	int err;
   1462
   1463	erp_table = mlxsw_sp_acl_erp_table_create(aregion, hints);
   1464	if (IS_ERR(erp_table))
   1465		return PTR_ERR(erp_table);
   1466	aregion->erp_table = erp_table;
   1467
   1468	/* Initialize the region's master mask to all zeroes */
   1469	err = mlxsw_sp_acl_erp_master_mask_init(aregion);
   1470	if (err)
   1471		goto err_erp_master_mask_init;
   1472
   1473	/* Initialize the region to not use the eRP table */
   1474	err = mlxsw_sp_acl_erp_region_param_init(aregion);
   1475	if (err)
   1476		goto err_erp_region_param_init;
   1477
   1478	return 0;
   1479
   1480err_erp_region_param_init:
   1481err_erp_master_mask_init:
   1482	mlxsw_sp_acl_erp_table_destroy(erp_table);
   1483	return err;
   1484}
   1485
   1486void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
   1487{
   1488	mlxsw_sp_acl_erp_table_destroy(aregion->erp_table);
   1489}
   1490
   1491static int
   1492mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp,
   1493				    struct mlxsw_sp_acl_erp_core *erp_core)
   1494{
   1495	unsigned int size;
   1496
   1497	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) ||
   1498	    !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) ||
   1499	    !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) ||
   1500	    !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB))
   1501		return -EIO;
   1502
   1503	size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB);
   1504	erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size;
   1505
   1506	size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB);
   1507	erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size;
   1508
   1509	size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB);
   1510	erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size;
   1511
   1512	size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB);
   1513	erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size;
   1514
   1515	return 0;
   1516}
   1517
   1518static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp,
   1519					struct mlxsw_sp_acl_erp_core *erp_core)
   1520{
   1521	unsigned int erpt_bank_size;
   1522	int err;
   1523
   1524	if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) ||
   1525	    !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS))
   1526		return -EIO;
   1527	erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
   1528					    ACL_MAX_ERPT_BANK_SIZE);
   1529	erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core,
   1530						     ACL_MAX_ERPT_BANKS);
   1531
   1532	erp_core->erp_tables = gen_pool_create(0, -1);
   1533	if (!erp_core->erp_tables)
   1534		return -ENOMEM;
   1535	gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL);
   1536
   1537	err = gen_pool_add(erp_core->erp_tables,
   1538			   MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size,
   1539			   -1);
   1540	if (err)
   1541		goto err_gen_pool_add;
   1542
   1543	erp_core->bf = mlxsw_sp_acl_bf_init(mlxsw_sp, erp_core->num_erp_banks);
   1544	if (IS_ERR(erp_core->bf)) {
   1545		err = PTR_ERR(erp_core->bf);
   1546		goto err_bf_init;
   1547	}
   1548
   1549	/* Different regions require masks of different sizes */
   1550	err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core);
   1551	if (err)
   1552		goto err_erp_tables_sizes_query;
   1553
   1554	return 0;
   1555
   1556err_erp_tables_sizes_query:
   1557	mlxsw_sp_acl_bf_fini(erp_core->bf);
   1558err_bf_init:
   1559err_gen_pool_add:
   1560	gen_pool_destroy(erp_core->erp_tables);
   1561	return err;
   1562}
   1563
   1564static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp,
   1565					 struct mlxsw_sp_acl_erp_core *erp_core)
   1566{
   1567	mlxsw_sp_acl_bf_fini(erp_core->bf);
   1568	gen_pool_destroy(erp_core->erp_tables);
   1569}
   1570
   1571int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
   1572			   struct mlxsw_sp_acl_atcam *atcam)
   1573{
   1574	struct mlxsw_sp_acl_erp_core *erp_core;
   1575	int err;
   1576
   1577	erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL);
   1578	if (!erp_core)
   1579		return -ENOMEM;
   1580	erp_core->mlxsw_sp = mlxsw_sp;
   1581	atcam->erp_core = erp_core;
   1582
   1583	err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core);
   1584	if (err)
   1585		goto err_erp_tables_init;
   1586
   1587	return 0;
   1588
   1589err_erp_tables_init:
   1590	kfree(erp_core);
   1591	return err;
   1592}
   1593
   1594void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
   1595			    struct mlxsw_sp_acl_atcam *atcam)
   1596{
   1597	mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core);
   1598	kfree(atcam->erp_core);
   1599}