1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/bitmap.h>
5 #include <linux/errno.h>
6 #include <linux/genalloc.h>
8 #include <linux/kernel.h>
9 #include <linux/list.h>
10 #include <linux/objagg.h>
11 #include <linux/rtnetlink.h>
12 #include <linux/slab.h>
17 #include "spectrum_acl_tcam.h"
19 /* gen_pool_alloc() returns 0 when allocation fails, so use an offset */
20 #define MLXSW_SP_ACL_ERP_GENALLOC_OFFSET 0x100
21 #define MLXSW_SP_ACL_ERP_MAX_PER_REGION 16
23 struct mlxsw_sp_acl_erp_core {
24 unsigned int erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX + 1];
25 struct gen_pool *erp_tables;
26 struct mlxsw_sp *mlxsw_sp;
27 struct mlxsw_sp_acl_bf *bf;
28 unsigned int num_erp_banks;
31 struct mlxsw_sp_acl_erp_key {
32 char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN];
33 #define __MASK_LEN 0x38
34 #define __MASK_IDX(i) (__MASK_LEN - (i) - 1)
38 struct mlxsw_sp_acl_erp {
39 struct mlxsw_sp_acl_erp_key key;
42 DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
43 struct list_head list;
44 struct mlxsw_sp_acl_erp_table *erp_table;
47 struct mlxsw_sp_acl_erp_master_mask {
48 DECLARE_BITMAP(bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
49 unsigned int count[MLXSW_SP_ACL_TCAM_MASK_LEN];
52 struct mlxsw_sp_acl_erp_table {
53 struct mlxsw_sp_acl_erp_master_mask master_mask;
54 DECLARE_BITMAP(erp_id_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
55 DECLARE_BITMAP(erp_index_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
56 struct list_head atcam_erps_list;
57 struct mlxsw_sp_acl_erp_core *erp_core;
58 struct mlxsw_sp_acl_atcam_region *aregion;
59 const struct mlxsw_sp_acl_erp_table_ops *ops;
60 unsigned long base_index;
61 unsigned int num_atcam_erps;
62 unsigned int num_max_atcam_erps;
63 unsigned int num_ctcam_erps;
64 unsigned int num_deltas;
65 struct objagg *objagg;
68 struct mlxsw_sp_acl_erp_table_ops {
69 struct mlxsw_sp_acl_erp *
70 (*erp_create)(struct mlxsw_sp_acl_erp_table *erp_table,
71 struct mlxsw_sp_acl_erp_key *key);
72 void (*erp_destroy)(struct mlxsw_sp_acl_erp_table *erp_table,
73 struct mlxsw_sp_acl_erp *erp);
76 static struct mlxsw_sp_acl_erp *
77 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
78 struct mlxsw_sp_acl_erp_key *key);
80 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
81 struct mlxsw_sp_acl_erp *erp);
82 static struct mlxsw_sp_acl_erp *
83 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
84 struct mlxsw_sp_acl_erp_key *key);
86 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
87 struct mlxsw_sp_acl_erp *erp);
88 static struct mlxsw_sp_acl_erp *
89 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
90 struct mlxsw_sp_acl_erp_key *key);
92 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
93 struct mlxsw_sp_acl_erp *erp);
95 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
96 struct mlxsw_sp_acl_erp *erp);
98 static const struct mlxsw_sp_acl_erp_table_ops erp_multiple_masks_ops = {
99 .erp_create = mlxsw_sp_acl_erp_mask_create,
100 .erp_destroy = mlxsw_sp_acl_erp_mask_destroy,
103 static const struct mlxsw_sp_acl_erp_table_ops erp_two_masks_ops = {
104 .erp_create = mlxsw_sp_acl_erp_mask_create,
105 .erp_destroy = mlxsw_sp_acl_erp_second_mask_destroy,
108 static const struct mlxsw_sp_acl_erp_table_ops erp_single_mask_ops = {
109 .erp_create = mlxsw_sp_acl_erp_second_mask_create,
110 .erp_destroy = mlxsw_sp_acl_erp_first_mask_destroy,
113 static const struct mlxsw_sp_acl_erp_table_ops erp_no_mask_ops = {
114 .erp_create = mlxsw_sp_acl_erp_first_mask_create,
115 .erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy,
119 mlxsw_sp_acl_erp_table_is_used(const struct mlxsw_sp_acl_erp_table *erp_table)
121 return erp_table->ops != &erp_single_mask_ops &&
122 erp_table->ops != &erp_no_mask_ops;
126 mlxsw_sp_acl_erp_bank_get(const struct mlxsw_sp_acl_erp *erp)
128 return erp->index % erp->erp_table->erp_core->num_erp_banks;
132 mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table)
134 struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
135 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
137 return erp_core->erpt_entries_size[aregion->type];
140 static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table,
145 id = find_first_zero_bit(erp_table->erp_id_bitmap,
146 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
147 if (id < MLXSW_SP_ACL_ERP_MAX_PER_REGION) {
148 __set_bit(id, erp_table->erp_id_bitmap);
156 static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table,
159 __clear_bit(id, erp_table->erp_id_bitmap);
163 mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit,
164 struct mlxsw_sp_acl_erp_master_mask *mask)
166 if (mask->count[bit]++ == 0)
167 __set_bit(bit, mask->bitmap);
171 mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit,
172 struct mlxsw_sp_acl_erp_master_mask *mask)
174 if (--mask->count[bit] == 0)
175 __clear_bit(bit, mask->bitmap);
179 mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table)
181 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
182 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
183 char percr_pl[MLXSW_REG_PERCR_LEN];
186 mlxsw_reg_percr_pack(percr_pl, region->id);
187 master_mask = mlxsw_reg_percr_master_mask_data(percr_pl);
188 bitmap_to_arr32((u32 *) master_mask, erp_table->master_mask.bitmap,
189 MLXSW_SP_ACL_TCAM_MASK_LEN);
191 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
195 mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table,
196 struct mlxsw_sp_acl_erp_key *key)
198 DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
202 bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
203 MLXSW_SP_ACL_TCAM_MASK_LEN);
204 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
205 mlxsw_sp_acl_erp_master_mask_bit_set(bit,
206 &erp_table->master_mask);
208 err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
210 goto err_master_mask_update;
214 err_master_mask_update:
215 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
216 mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
217 &erp_table->master_mask);
222 mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table,
223 struct mlxsw_sp_acl_erp_key *key)
225 DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
229 bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
230 MLXSW_SP_ACL_TCAM_MASK_LEN);
231 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
232 mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
233 &erp_table->master_mask);
235 err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
237 goto err_master_mask_update;
241 err_master_mask_update:
242 for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
243 mlxsw_sp_acl_erp_master_mask_bit_set(bit,
244 &erp_table->master_mask);
248 static struct mlxsw_sp_acl_erp *
249 mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
250 struct mlxsw_sp_acl_erp_key *key)
252 struct mlxsw_sp_acl_erp *erp;
255 erp = kzalloc(sizeof(*erp), GFP_KERNEL);
257 return ERR_PTR(-ENOMEM);
259 err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id);
263 memcpy(&erp->key, key, sizeof(*key));
264 list_add(&erp->list, &erp_table->atcam_erps_list);
265 erp_table->num_atcam_erps++;
266 erp->erp_table = erp_table;
268 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
270 goto err_master_mask_set;
275 erp_table->num_atcam_erps--;
276 list_del(&erp->list);
277 mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
284 mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp)
286 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
288 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
289 erp_table->num_atcam_erps--;
290 list_del(&erp->list);
291 mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
296 mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
297 unsigned int num_erps,
298 enum mlxsw_sp_acl_atcam_region_type region_type,
299 unsigned long *p_index)
301 unsigned int num_rows, entry_size;
303 /* We only allow allocations of entire rows */
304 if (num_erps % erp_core->num_erp_banks != 0)
307 entry_size = erp_core->erpt_entries_size[region_type];
308 num_rows = num_erps / erp_core->num_erp_banks;
310 *p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
313 *p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
319 mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core *erp_core,
320 unsigned int num_erps,
321 enum mlxsw_sp_acl_atcam_region_type region_type,
324 unsigned long base_index;
325 unsigned int entry_size;
328 entry_size = erp_core->erpt_entries_size[region_type];
329 base_index = index + MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
330 size = num_erps / erp_core->num_erp_banks * entry_size;
331 gen_pool_free(erp_core->erp_tables, base_index, size);
334 static struct mlxsw_sp_acl_erp *
335 mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table)
337 if (!list_is_singular(&erp_table->atcam_erps_list))
340 return list_first_entry(&erp_table->atcam_erps_list,
341 struct mlxsw_sp_acl_erp, list);
344 static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table,
349 index = find_first_zero_bit(erp_table->erp_index_bitmap,
350 erp_table->num_max_atcam_erps);
351 if (index < erp_table->num_max_atcam_erps) {
352 __set_bit(index, erp_table->erp_index_bitmap);
360 static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table,
363 __clear_bit(index, erp_table->erp_index_bitmap);
367 mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table *erp_table,
368 const struct mlxsw_sp_acl_erp *erp,
369 u8 *p_erpt_bank, u8 *p_erpt_index)
371 unsigned int entry_size = mlxsw_sp_acl_erp_table_entry_size(erp_table);
372 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
375 *p_erpt_bank = erp->index % erp_core->num_erp_banks;
376 row = erp->index / erp_core->num_erp_banks;
377 *p_erpt_index = erp_table->base_index + row * entry_size;
381 mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
382 struct mlxsw_sp_acl_erp *erp)
384 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
385 enum mlxsw_reg_perpt_key_size key_size;
386 char perpt_pl[MLXSW_REG_PERPT_LEN];
387 u8 erpt_bank, erpt_index;
389 mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
390 key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
391 mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
392 0, erp_table->base_index, erp->index,
394 mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
395 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
396 mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, true);
397 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
400 static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp)
402 char empty_mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
403 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
404 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
405 enum mlxsw_reg_perpt_key_size key_size;
406 char perpt_pl[MLXSW_REG_PERPT_LEN];
407 u8 erpt_bank, erpt_index;
409 mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
410 key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
411 mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
412 0, erp_table->base_index, erp->index, empty_mask);
413 mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
414 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
415 mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, false);
416 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
420 mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table,
423 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
424 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
425 char pererp_pl[MLXSW_REG_PERERP_LEN];
427 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
428 erp_table->base_index, 0);
429 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
430 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
432 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
436 mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table)
438 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
439 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
440 char pererp_pl[MLXSW_REG_PERERP_LEN];
441 struct mlxsw_sp_acl_erp *master_rp;
443 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
444 /* It is possible we do not have a master RP when we disable the
445 * table when there are no rules in the A-TCAM and the last C-TCAM
448 mlxsw_reg_pererp_pack(pererp_pl, region->id, false, false, 0, 0,
449 master_rp ? master_rp->id : 0);
450 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
454 mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table)
456 struct mlxsw_sp_acl_erp *erp;
459 list_for_each_entry(erp, &erp_table->atcam_erps_list, list) {
460 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
462 goto err_table_erp_add;
468 list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list,
470 mlxsw_sp_acl_erp_table_erp_del(erp);
475 mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table)
477 unsigned int num_erps, old_num_erps = erp_table->num_max_atcam_erps;
478 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
479 unsigned long old_base_index = erp_table->base_index;
480 bool ctcam_le = erp_table->num_ctcam_erps > 0;
483 if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps)
486 if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION)
489 num_erps = old_num_erps + erp_core->num_erp_banks;
490 err = mlxsw_sp_acl_erp_table_alloc(erp_core, num_erps,
491 erp_table->aregion->type,
492 &erp_table->base_index);
495 erp_table->num_max_atcam_erps = num_erps;
497 err = mlxsw_sp_acl_erp_table_relocate(erp_table);
499 goto err_table_relocate;
501 err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le);
503 goto err_table_enable;
505 mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps,
506 erp_table->aregion->type, old_base_index);
512 erp_table->num_max_atcam_erps = old_num_erps;
513 mlxsw_sp_acl_erp_table_free(erp_core, num_erps,
514 erp_table->aregion->type,
515 erp_table->base_index);
516 erp_table->base_index = old_base_index;
521 mlxsw_acl_erp_table_bf_add(struct mlxsw_sp_acl_erp_table *erp_table,
522 struct mlxsw_sp_acl_erp *erp)
524 struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
525 unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
526 struct mlxsw_sp_acl_atcam_entry *aentry;
529 list_for_each_entry(aentry, &aregion->entries_list, list) {
530 err = mlxsw_sp_acl_bf_entry_add(aregion->region->mlxsw_sp,
531 erp_table->erp_core->bf,
532 aregion, erp_bank, aentry);
534 goto bf_entry_add_err;
540 list_for_each_entry_continue_reverse(aentry, &aregion->entries_list,
542 mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
543 erp_table->erp_core->bf,
544 aregion, erp_bank, aentry);
549 mlxsw_acl_erp_table_bf_del(struct mlxsw_sp_acl_erp_table *erp_table,
550 struct mlxsw_sp_acl_erp *erp)
552 struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
553 unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
554 struct mlxsw_sp_acl_atcam_entry *aentry;
556 list_for_each_entry_reverse(aentry, &aregion->entries_list, list)
557 mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
558 erp_table->erp_core->bf,
559 aregion, erp_bank, aentry);
563 mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table)
565 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
566 struct mlxsw_sp_acl_erp *master_rp;
569 /* Initially, allocate a single eRP row. Expand later as needed */
570 err = mlxsw_sp_acl_erp_table_alloc(erp_core, erp_core->num_erp_banks,
571 erp_table->aregion->type,
572 &erp_table->base_index);
575 erp_table->num_max_atcam_erps = erp_core->num_erp_banks;
577 /* Transition the sole RP currently configured (the master RP)
580 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
583 goto err_table_master_rp;
586 /* Make sure the master RP is using a valid index, as
587 * only a single eRP row is currently allocated.
589 master_rp->index = 0;
590 __set_bit(master_rp->index, erp_table->erp_index_bitmap);
592 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp);
594 goto err_table_master_rp_add;
596 /* Update Bloom filter before enabling eRP table, as rules
597 * on the master RP were not set to Bloom filter up to this
600 err = mlxsw_acl_erp_table_bf_add(erp_table, master_rp);
602 goto err_table_bf_add;
604 err = mlxsw_sp_acl_erp_table_enable(erp_table, false);
606 goto err_table_enable;
611 mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
613 mlxsw_sp_acl_erp_table_erp_del(master_rp);
614 err_table_master_rp_add:
615 __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
617 mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
618 erp_table->aregion->type,
619 erp_table->base_index);
624 mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table)
626 struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
627 struct mlxsw_sp_acl_erp *master_rp;
629 mlxsw_sp_acl_erp_table_disable(erp_table);
630 master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
633 mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
634 mlxsw_sp_acl_erp_table_erp_del(master_rp);
635 __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
636 mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
637 erp_table->aregion->type,
638 erp_table->base_index);
642 mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
643 struct mlxsw_sp_acl_erp *erp)
645 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
646 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
647 bool ctcam_le = erp_table->num_ctcam_erps > 0;
648 char pererp_pl[MLXSW_REG_PERERP_LEN];
650 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
651 erp_table->base_index, 0);
652 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
653 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
654 mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, true);
656 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
659 static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp)
661 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
662 struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
663 struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
664 bool ctcam_le = erp_table->num_ctcam_erps > 0;
665 char pererp_pl[MLXSW_REG_PERERP_LEN];
667 mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
668 erp_table->base_index, 0);
669 mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
670 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
671 mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, false);
673 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
677 mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table)
679 /* No need to re-enable lookup in the C-TCAM */
680 if (erp_table->num_ctcam_erps > 1)
683 return mlxsw_sp_acl_erp_table_enable(erp_table, true);
687 mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table)
689 /* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */
690 if (erp_table->num_ctcam_erps > 1)
693 mlxsw_sp_acl_erp_table_enable(erp_table, false);
697 __mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
698 unsigned int *inc_num)
702 /* If there are C-TCAM eRP or deltas in use we need to transition
703 * the region to use eRP table, if it is not already done
705 if (!mlxsw_sp_acl_erp_table_is_used(erp_table)) {
706 err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
711 /* When C-TCAM or deltas are used, the eRP table must be used */
712 if (erp_table->ops != &erp_multiple_masks_ops)
713 erp_table->ops = &erp_multiple_masks_ops;
720 static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table)
722 return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
723 &erp_table->num_ctcam_erps);
726 static int mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table *erp_table)
728 return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
729 &erp_table->num_deltas);
733 __mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table *erp_table,
734 unsigned int *dec_num)
738 /* If there are no C-TCAM eRP or deltas in use, the state we
739 * transition to depends on the number of A-TCAM eRPs currently
742 if (erp_table->num_ctcam_erps > 0 || erp_table->num_deltas > 0)
745 switch (erp_table->num_atcam_erps) {
747 /* Keep using the eRP table, but correctly set the
748 * operations pointer so that when an A-TCAM eRP is
749 * deleted we will transition to use the master mask
751 erp_table->ops = &erp_two_masks_ops;
754 /* We only kept the eRP table because we had C-TCAM
755 * eRPs in use. Now that the last C-TCAM eRP is gone we
756 * can stop using the table and transition to use the
759 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
760 erp_table->ops = &erp_single_mask_ops;
763 /* There are no more eRPs of any kind used by the region
764 * so free its eRP table and transition to initial state
766 mlxsw_sp_acl_erp_table_disable(erp_table);
767 mlxsw_sp_acl_erp_table_free(erp_table->erp_core,
768 erp_table->num_max_atcam_erps,
769 erp_table->aregion->type,
770 erp_table->base_index);
771 erp_table->ops = &erp_no_mask_ops;
778 static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table)
780 __mlxsw_sp_acl_erp_table_other_dec(erp_table,
781 &erp_table->num_ctcam_erps);
784 static void mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table *erp_table)
786 __mlxsw_sp_acl_erp_table_other_dec(erp_table,
787 &erp_table->num_deltas);
790 static struct mlxsw_sp_acl_erp *
791 mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
792 struct mlxsw_sp_acl_erp_key *key)
794 struct mlxsw_sp_acl_erp *erp;
797 erp = kzalloc(sizeof(*erp), GFP_KERNEL);
799 return ERR_PTR(-ENOMEM);
801 memcpy(&erp->key, key, sizeof(*key));
802 bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask,
803 MLXSW_SP_ACL_TCAM_MASK_LEN);
805 err = mlxsw_sp_acl_erp_ctcam_inc(erp_table);
807 goto err_erp_ctcam_inc;
809 erp->erp_table = erp_table;
811 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
813 goto err_master_mask_set;
815 err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table);
817 goto err_erp_region_ctcam_enable;
821 err_erp_region_ctcam_enable:
822 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
824 mlxsw_sp_acl_erp_ctcam_dec(erp_table);
831 mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp)
833 struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
835 mlxsw_sp_acl_erp_region_ctcam_disable(erp_table);
836 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
837 mlxsw_sp_acl_erp_ctcam_dec(erp_table);
841 static struct mlxsw_sp_acl_erp *
842 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
843 struct mlxsw_sp_acl_erp_key *key)
845 struct mlxsw_sp_acl_erp *erp;
849 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
851 /* Expand the eRP table for the new eRP, if needed */
852 err = mlxsw_sp_acl_erp_table_expand(erp_table);
856 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
860 err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
862 goto err_erp_index_get;
864 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
866 goto err_table_erp_add;
868 err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
870 goto err_region_erp_add;
872 erp_table->ops = &erp_multiple_masks_ops;
877 mlxsw_sp_acl_erp_table_erp_del(erp);
879 mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
881 mlxsw_sp_acl_erp_generic_destroy(erp);
886 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
887 struct mlxsw_sp_acl_erp *erp)
890 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
892 mlxsw_sp_acl_erp_region_erp_del(erp);
893 mlxsw_sp_acl_erp_table_erp_del(erp);
894 mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
895 mlxsw_sp_acl_erp_generic_destroy(erp);
897 if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0 &&
898 erp_table->num_deltas == 0)
899 erp_table->ops = &erp_two_masks_ops;
902 static struct mlxsw_sp_acl_erp *
903 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
904 struct mlxsw_sp_acl_erp_key *key)
906 struct mlxsw_sp_acl_erp *erp;
910 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
912 /* Transition to use eRP table instead of master mask */
913 err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
917 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
923 err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
925 goto err_erp_index_get;
927 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
929 goto err_table_erp_add;
931 err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
933 goto err_region_erp_add;
935 erp_table->ops = &erp_two_masks_ops;
940 mlxsw_sp_acl_erp_table_erp_del(erp);
942 mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
944 mlxsw_sp_acl_erp_generic_destroy(erp);
946 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
951 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
952 struct mlxsw_sp_acl_erp *erp)
955 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
957 mlxsw_sp_acl_erp_region_erp_del(erp);
958 mlxsw_sp_acl_erp_table_erp_del(erp);
959 mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
960 mlxsw_sp_acl_erp_generic_destroy(erp);
961 /* Transition to use master mask instead of eRP table */
962 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
964 erp_table->ops = &erp_single_mask_ops;
967 static struct mlxsw_sp_acl_erp *
968 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
969 struct mlxsw_sp_acl_erp_key *key)
971 struct mlxsw_sp_acl_erp *erp;
974 return ERR_PTR(-EINVAL);
976 erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
980 erp_table->ops = &erp_single_mask_ops;
986 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
987 struct mlxsw_sp_acl_erp *erp)
989 mlxsw_sp_acl_erp_generic_destroy(erp);
990 erp_table->ops = &erp_no_mask_ops;
994 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
995 struct mlxsw_sp_acl_erp *erp)
1000 struct mlxsw_sp_acl_erp_mask *
1001 mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion,
1002 const char *mask, bool ctcam)
1004 struct mlxsw_sp_acl_erp_key key;
1005 struct objagg_obj *objagg_obj;
1007 /* eRPs are allocated from a shared resource, but currently all
1008 * allocations are done under RTNL.
1012 memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN);
1014 objagg_obj = objagg_obj_get(aregion->erp_table->objagg, &key);
1015 if (IS_ERR(objagg_obj))
1016 return ERR_CAST(objagg_obj);
1017 return (struct mlxsw_sp_acl_erp_mask *) objagg_obj;
1020 void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion,
1021 struct mlxsw_sp_acl_erp_mask *erp_mask)
1023 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1026 objagg_obj_put(aregion->erp_table->objagg, objagg_obj);
1029 int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp,
1030 struct mlxsw_sp_acl_atcam_region *aregion,
1031 struct mlxsw_sp_acl_erp_mask *erp_mask,
1032 struct mlxsw_sp_acl_atcam_entry *aentry)
1034 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1035 const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1036 unsigned int erp_bank;
1039 if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1042 erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
1043 return mlxsw_sp_acl_bf_entry_add(mlxsw_sp,
1044 erp->erp_table->erp_core->bf,
1045 aregion, erp_bank, aentry);
1048 void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp,
1049 struct mlxsw_sp_acl_atcam_region *aregion,
1050 struct mlxsw_sp_acl_erp_mask *erp_mask,
1051 struct mlxsw_sp_acl_atcam_entry *aentry)
1053 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1054 const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1055 unsigned int erp_bank;
1058 if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
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);
1068 mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask)
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);
1076 u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
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);
1084 struct mlxsw_sp_acl_erp_delta {
1085 struct mlxsw_sp_acl_erp_key key;
1090 u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta)
1092 return delta->start;
1095 u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta)
1100 u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta,
1101 const char *enc_key)
1103 u16 start = delta->start;
1104 u8 mask = delta->mask;
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;
1118 void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta,
1119 const char *enc_key)
1121 u16 start = delta->start;
1122 u8 mask = delta->mask;
1123 unsigned char *byte;
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;
1138 static const struct mlxsw_sp_acl_erp_delta
1139 mlxsw_sp_acl_erp_delta_default = {};
1141 const struct mlxsw_sp_acl_erp_delta *
1142 mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1144 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1145 const struct mlxsw_sp_acl_erp_delta *delta;
1147 delta = objagg_obj_delta_priv(objagg_obj);
1149 delta = &mlxsw_sp_acl_erp_delta_default;
1154 mlxsw_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)
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)])
1170 else if (si != i - 1)
1174 /* The masks are the same, this cannot happen.
1175 * That means the caller is broken.
1182 pmask = (unsigned char) parent_key->mask[__MASK_IDX(si)];
1183 mask = (unsigned char) key->mask[__MASK_IDX(si)];
1184 if (si + 1 < __MASK_LEN) {
1185 pmask |= (unsigned char) parent_key->mask[__MASK_IDX(si + 1)] << 8;
1186 mask |= (unsigned char) key->mask[__MASK_IDX(si + 1)] << 8;
1189 if ((pmask ^ mask) & pmask)
1192 while (!(mask & (1 << offset)))
1199 *delta_start = si * 8 + offset;
1205 static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
1208 struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
1209 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1210 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1211 struct mlxsw_sp_acl_erp_key *key = obj;
1212 struct mlxsw_sp_acl_erp_delta *delta;
1217 if (parent_key->ctcam || key->ctcam)
1218 return ERR_PTR(-EINVAL);
1219 err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
1220 &delta_start, &delta_mask);
1222 return ERR_PTR(-EINVAL);
1224 delta = kzalloc(sizeof(*delta), GFP_KERNEL);
1226 return ERR_PTR(-ENOMEM);
1227 delta->start = delta_start;
1228 delta->mask = delta_mask;
1230 err = mlxsw_sp_acl_erp_delta_inc(erp_table);
1232 goto err_erp_delta_inc;
1234 memcpy(&delta->key, key, sizeof(*key));
1235 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key);
1237 goto err_master_mask_set;
1241 err_master_mask_set:
1242 mlxsw_sp_acl_erp_delta_dec(erp_table);
1245 return ERR_PTR(err);
1248 static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
1250 struct mlxsw_sp_acl_erp_delta *delta = delta_priv;
1251 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1252 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1254 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key);
1255 mlxsw_sp_acl_erp_delta_dec(erp_table);
1259 static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj)
1261 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1262 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1263 struct mlxsw_sp_acl_erp_key *key = obj;
1265 return erp_table->ops->erp_create(erp_table, key);
1268 static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
1270 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1271 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1273 erp_table->ops->erp_destroy(erp_table, root_priv);
1276 static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
1277 .obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
1278 .delta_create = mlxsw_sp_acl_erp_delta_create,
1279 .delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
1280 .root_create = mlxsw_sp_acl_erp_root_create,
1281 .root_destroy = mlxsw_sp_acl_erp_root_destroy,
1284 static struct mlxsw_sp_acl_erp_table *
1285 mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion)
1287 struct mlxsw_sp_acl_erp_table *erp_table;
1290 erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL);
1292 return ERR_PTR(-ENOMEM);
1294 erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
1296 if (IS_ERR(erp_table->objagg)) {
1297 err = PTR_ERR(erp_table->objagg);
1298 goto err_objagg_create;
1301 erp_table->erp_core = aregion->atcam->erp_core;
1302 erp_table->ops = &erp_no_mask_ops;
1303 INIT_LIST_HEAD(&erp_table->atcam_erps_list);
1304 erp_table->aregion = aregion;
1310 return ERR_PTR(err);
1314 mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
1316 WARN_ON(!list_empty(&erp_table->atcam_erps_list));
1317 objagg_destroy(erp_table->objagg);
1322 mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion)
1324 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1325 char percr_pl[MLXSW_REG_PERCR_LEN];
1327 mlxsw_reg_percr_pack(percr_pl, aregion->region->id);
1328 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
1332 mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
1334 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1335 char pererp_pl[MLXSW_REG_PERERP_LEN];
1337 mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0,
1339 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
1342 int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion)
1344 struct mlxsw_sp_acl_erp_table *erp_table;
1347 erp_table = mlxsw_sp_acl_erp_table_create(aregion);
1348 if (IS_ERR(erp_table))
1349 return PTR_ERR(erp_table);
1350 aregion->erp_table = erp_table;
1352 /* Initialize the region's master mask to all zeroes */
1353 err = mlxsw_sp_acl_erp_master_mask_init(aregion);
1355 goto err_erp_master_mask_init;
1357 /* Initialize the region to not use the eRP table */
1358 err = mlxsw_sp_acl_erp_region_param_init(aregion);
1360 goto err_erp_region_param_init;
1364 err_erp_region_param_init:
1365 err_erp_master_mask_init:
1366 mlxsw_sp_acl_erp_table_destroy(erp_table);
1370 void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
1372 mlxsw_sp_acl_erp_table_destroy(aregion->erp_table);
1376 mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp,
1377 struct mlxsw_sp_acl_erp_core *erp_core)
1381 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) ||
1382 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) ||
1383 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) ||
1384 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB))
1387 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB);
1388 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size;
1390 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB);
1391 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size;
1393 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB);
1394 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size;
1396 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB);
1397 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size;
1402 static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp,
1403 struct mlxsw_sp_acl_erp_core *erp_core)
1405 unsigned int erpt_bank_size;
1408 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) ||
1409 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS))
1411 erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1412 ACL_MAX_ERPT_BANK_SIZE);
1413 erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1414 ACL_MAX_ERPT_BANKS);
1416 erp_core->erp_tables = gen_pool_create(0, -1);
1417 if (!erp_core->erp_tables)
1419 gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL);
1421 err = gen_pool_add(erp_core->erp_tables,
1422 MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size,
1425 goto err_gen_pool_add;
1427 erp_core->bf = mlxsw_sp_acl_bf_init(mlxsw_sp, erp_core->num_erp_banks);
1428 if (IS_ERR(erp_core->bf)) {
1429 err = PTR_ERR(erp_core->bf);
1433 /* Different regions require masks of different sizes */
1434 err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core);
1436 goto err_erp_tables_sizes_query;
1440 err_erp_tables_sizes_query:
1441 mlxsw_sp_acl_bf_fini(erp_core->bf);
1444 gen_pool_destroy(erp_core->erp_tables);
1448 static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp,
1449 struct mlxsw_sp_acl_erp_core *erp_core)
1451 mlxsw_sp_acl_bf_fini(erp_core->bf);
1452 gen_pool_destroy(erp_core->erp_tables);
1455 int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
1456 struct mlxsw_sp_acl_atcam *atcam)
1458 struct mlxsw_sp_acl_erp_core *erp_core;
1461 erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL);
1464 erp_core->mlxsw_sp = mlxsw_sp;
1465 atcam->erp_core = erp_core;
1467 err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core);
1469 goto err_erp_tables_init;
1473 err_erp_tables_init:
1478 void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
1479 struct mlxsw_sp_acl_atcam *atcam)
1481 mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core);
1482 kfree(atcam->erp_core);