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;
1025 objagg_obj_put(aregion->erp_table->objagg, objagg_obj);
1028 int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp,
1029 struct mlxsw_sp_acl_atcam_region *aregion,
1030 struct mlxsw_sp_acl_erp_mask *erp_mask,
1031 struct mlxsw_sp_acl_atcam_entry *aentry)
1033 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1034 const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1035 unsigned int erp_bank;
1038 if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1041 erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
1042 return mlxsw_sp_acl_bf_entry_add(mlxsw_sp,
1043 erp->erp_table->erp_core->bf,
1044 aregion, erp_bank, aentry);
1047 void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp,
1048 struct mlxsw_sp_acl_atcam_region *aregion,
1049 struct mlxsw_sp_acl_erp_mask *erp_mask,
1050 struct mlxsw_sp_acl_atcam_entry *aentry)
1052 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1053 const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1054 unsigned int erp_bank;
1056 if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1059 erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
1060 mlxsw_sp_acl_bf_entry_del(mlxsw_sp,
1061 erp->erp_table->erp_core->bf,
1062 aregion, erp_bank, aentry);
1066 mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1068 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1069 const struct mlxsw_sp_acl_erp_key *key = objagg_obj_raw(objagg_obj);
1074 u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1076 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1077 const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1082 struct mlxsw_sp_acl_erp_delta {
1083 struct mlxsw_sp_acl_erp_key key;
1088 u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta)
1090 return delta->start;
1093 u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta)
1098 u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta,
1099 const char *enc_key)
1101 u16 start = delta->start;
1102 u8 mask = delta->mask;
1108 tmp = (unsigned char) enc_key[__MASK_IDX(start / 8)];
1109 if (start / 8 + 1 < __MASK_LEN)
1110 tmp |= (unsigned char) enc_key[__MASK_IDX(start / 8 + 1)] << 8;
1116 void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta,
1117 const char *enc_key)
1119 u16 start = delta->start;
1120 u8 mask = delta->mask;
1121 unsigned char *byte;
1128 byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8)];
1129 *byte &= tmp & 0xff;
1130 if (start / 8 + 1 < __MASK_LEN) {
1131 byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8 + 1)];
1132 *byte &= (tmp >> 8) & 0xff;
1136 static const struct mlxsw_sp_acl_erp_delta
1137 mlxsw_sp_acl_erp_delta_default = {};
1139 const struct mlxsw_sp_acl_erp_delta *
1140 mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1142 struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1143 const struct mlxsw_sp_acl_erp_delta *delta;
1145 delta = objagg_obj_delta_priv(objagg_obj);
1147 delta = &mlxsw_sp_acl_erp_delta_default;
1152 mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key,
1153 const struct mlxsw_sp_acl_erp_key *key,
1154 u16 *delta_start, u8 *delta_mask)
1162 /* The difference between 2 masks can be up to 8 consecutive bits. */
1163 for (i = 0; i < __MASK_LEN; i++) {
1164 if (parent_key->mask[__MASK_IDX(i)] == key->mask[__MASK_IDX(i)])
1168 else if (si != i - 1)
1172 /* The masks are the same, this cannot happen.
1173 * That means the caller is broken.
1180 pmask = (unsigned char) parent_key->mask[__MASK_IDX(si)];
1181 mask = (unsigned char) key->mask[__MASK_IDX(si)];
1182 if (si + 1 < __MASK_LEN) {
1183 pmask |= (unsigned char) parent_key->mask[__MASK_IDX(si + 1)] << 8;
1184 mask |= (unsigned char) key->mask[__MASK_IDX(si + 1)] << 8;
1187 if ((pmask ^ mask) & pmask)
1190 while (!(mask & (1 << offset)))
1197 *delta_start = si * 8 + offset;
1203 static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
1206 struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
1207 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1208 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1209 struct mlxsw_sp_acl_erp_key *key = obj;
1210 struct mlxsw_sp_acl_erp_delta *delta;
1215 if (parent_key->ctcam || key->ctcam)
1216 return ERR_PTR(-EINVAL);
1217 err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
1218 &delta_start, &delta_mask);
1220 return ERR_PTR(-EINVAL);
1222 delta = kzalloc(sizeof(*delta), GFP_KERNEL);
1224 return ERR_PTR(-ENOMEM);
1225 delta->start = delta_start;
1226 delta->mask = delta_mask;
1228 err = mlxsw_sp_acl_erp_delta_inc(erp_table);
1230 goto err_erp_delta_inc;
1232 memcpy(&delta->key, key, sizeof(*key));
1233 err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key);
1235 goto err_master_mask_set;
1239 err_master_mask_set:
1240 mlxsw_sp_acl_erp_delta_dec(erp_table);
1243 return ERR_PTR(err);
1246 static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
1248 struct mlxsw_sp_acl_erp_delta *delta = delta_priv;
1249 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1250 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1252 mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key);
1253 mlxsw_sp_acl_erp_delta_dec(erp_table);
1257 static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj)
1259 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1260 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1261 struct mlxsw_sp_acl_erp_key *key = obj;
1263 return erp_table->ops->erp_create(erp_table, key);
1266 static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
1268 struct mlxsw_sp_acl_atcam_region *aregion = priv;
1269 struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1271 erp_table->ops->erp_destroy(erp_table, root_priv);
1274 static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
1275 .obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
1276 .delta_create = mlxsw_sp_acl_erp_delta_create,
1277 .delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
1278 .root_create = mlxsw_sp_acl_erp_root_create,
1279 .root_destroy = mlxsw_sp_acl_erp_root_destroy,
1282 static struct mlxsw_sp_acl_erp_table *
1283 mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion)
1285 struct mlxsw_sp_acl_erp_table *erp_table;
1288 erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL);
1290 return ERR_PTR(-ENOMEM);
1292 erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
1294 if (IS_ERR(erp_table->objagg)) {
1295 err = PTR_ERR(erp_table->objagg);
1296 goto err_objagg_create;
1299 erp_table->erp_core = aregion->atcam->erp_core;
1300 erp_table->ops = &erp_no_mask_ops;
1301 INIT_LIST_HEAD(&erp_table->atcam_erps_list);
1302 erp_table->aregion = aregion;
1308 return ERR_PTR(err);
1312 mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
1314 WARN_ON(!list_empty(&erp_table->atcam_erps_list));
1315 objagg_destroy(erp_table->objagg);
1320 mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion)
1322 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1323 char percr_pl[MLXSW_REG_PERCR_LEN];
1325 mlxsw_reg_percr_pack(percr_pl, aregion->region->id);
1326 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
1330 mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
1332 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1333 char pererp_pl[MLXSW_REG_PERERP_LEN];
1335 mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0,
1337 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
1340 int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion)
1342 struct mlxsw_sp_acl_erp_table *erp_table;
1345 erp_table = mlxsw_sp_acl_erp_table_create(aregion);
1346 if (IS_ERR(erp_table))
1347 return PTR_ERR(erp_table);
1348 aregion->erp_table = erp_table;
1350 /* Initialize the region's master mask to all zeroes */
1351 err = mlxsw_sp_acl_erp_master_mask_init(aregion);
1353 goto err_erp_master_mask_init;
1355 /* Initialize the region to not use the eRP table */
1356 err = mlxsw_sp_acl_erp_region_param_init(aregion);
1358 goto err_erp_region_param_init;
1362 err_erp_region_param_init:
1363 err_erp_master_mask_init:
1364 mlxsw_sp_acl_erp_table_destroy(erp_table);
1368 void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
1370 mlxsw_sp_acl_erp_table_destroy(aregion->erp_table);
1374 mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp,
1375 struct mlxsw_sp_acl_erp_core *erp_core)
1379 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) ||
1380 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) ||
1381 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) ||
1382 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB))
1385 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB);
1386 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size;
1388 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB);
1389 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size;
1391 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB);
1392 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size;
1394 size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB);
1395 erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size;
1400 static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp,
1401 struct mlxsw_sp_acl_erp_core *erp_core)
1403 unsigned int erpt_bank_size;
1406 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) ||
1407 !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS))
1409 erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1410 ACL_MAX_ERPT_BANK_SIZE);
1411 erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1412 ACL_MAX_ERPT_BANKS);
1414 erp_core->erp_tables = gen_pool_create(0, -1);
1415 if (!erp_core->erp_tables)
1417 gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL);
1419 err = gen_pool_add(erp_core->erp_tables,
1420 MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size,
1423 goto err_gen_pool_add;
1425 erp_core->bf = mlxsw_sp_acl_bf_init(mlxsw_sp, erp_core->num_erp_banks);
1426 if (IS_ERR(erp_core->bf)) {
1427 err = PTR_ERR(erp_core->bf);
1431 /* Different regions require masks of different sizes */
1432 err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core);
1434 goto err_erp_tables_sizes_query;
1438 err_erp_tables_sizes_query:
1439 mlxsw_sp_acl_bf_fini(erp_core->bf);
1442 gen_pool_destroy(erp_core->erp_tables);
1446 static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp,
1447 struct mlxsw_sp_acl_erp_core *erp_core)
1449 mlxsw_sp_acl_bf_fini(erp_core->bf);
1450 gen_pool_destroy(erp_core->erp_tables);
1453 int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
1454 struct mlxsw_sp_acl_atcam *atcam)
1456 struct mlxsw_sp_acl_erp_core *erp_core;
1459 erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL);
1462 erp_core->mlxsw_sp = mlxsw_sp;
1463 atcam->erp_core = erp_core;
1465 err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core);
1467 goto err_erp_tables_init;
1471 err_erp_tables_init:
1476 void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
1477 struct mlxsw_sp_acl_atcam *atcam)
1479 mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core);
1480 kfree(atcam->erp_core);