GNU Linux-libre 4.19.286-gnu1
[releases.git] / drivers / net / ethernet / mellanox / mlxsw / spectrum_acl_erp.c
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/rhashtable.h>
11 #include <linux/rtnetlink.h>
12 #include <linux/slab.h>
13
14 #include "core.h"
15 #include "reg.h"
16 #include "spectrum.h"
17 #include "spectrum_acl_tcam.h"
18
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
22
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         unsigned int num_erp_banks;
28 };
29
30 struct mlxsw_sp_acl_erp_key {
31         char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN];
32         bool ctcam;
33 };
34
35 struct mlxsw_sp_acl_erp {
36         struct mlxsw_sp_acl_erp_key key;
37         u8 id;
38         u8 index;
39         refcount_t refcnt;
40         DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
41         struct list_head list;
42         struct rhash_head ht_node;
43         struct mlxsw_sp_acl_erp_table *erp_table;
44 };
45
46 struct mlxsw_sp_acl_erp_master_mask {
47         DECLARE_BITMAP(bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
48         unsigned int count[MLXSW_SP_ACL_TCAM_MASK_LEN];
49 };
50
51 struct mlxsw_sp_acl_erp_table {
52         struct mlxsw_sp_acl_erp_master_mask master_mask;
53         DECLARE_BITMAP(erp_id_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
54         DECLARE_BITMAP(erp_index_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
55         struct list_head atcam_erps_list;
56         struct rhashtable erp_ht;
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 };
65
66 static const struct rhashtable_params mlxsw_sp_acl_erp_ht_params = {
67         .key_len = sizeof(struct mlxsw_sp_acl_erp_key),
68         .key_offset = offsetof(struct mlxsw_sp_acl_erp, key),
69         .head_offset = offsetof(struct mlxsw_sp_acl_erp, ht_node),
70 };
71
72 struct mlxsw_sp_acl_erp_table_ops {
73         struct mlxsw_sp_acl_erp *
74                 (*erp_create)(struct mlxsw_sp_acl_erp_table *erp_table,
75                               struct mlxsw_sp_acl_erp_key *key);
76         void (*erp_destroy)(struct mlxsw_sp_acl_erp_table *erp_table,
77                             struct mlxsw_sp_acl_erp *erp);
78 };
79
80 static struct mlxsw_sp_acl_erp *
81 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
82                              struct mlxsw_sp_acl_erp_key *key);
83 static void
84 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
85                               struct mlxsw_sp_acl_erp *erp);
86 static struct mlxsw_sp_acl_erp *
87 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
88                                     struct mlxsw_sp_acl_erp_key *key);
89 static void
90 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
91                                      struct mlxsw_sp_acl_erp *erp);
92 static struct mlxsw_sp_acl_erp *
93 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
94                                    struct mlxsw_sp_acl_erp_key *key);
95 static void
96 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
97                                     struct mlxsw_sp_acl_erp *erp);
98 static void
99 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
100                                  struct mlxsw_sp_acl_erp *erp);
101
102 static const struct mlxsw_sp_acl_erp_table_ops erp_multiple_masks_ops = {
103         .erp_create = mlxsw_sp_acl_erp_mask_create,
104         .erp_destroy = mlxsw_sp_acl_erp_mask_destroy,
105 };
106
107 static const struct mlxsw_sp_acl_erp_table_ops erp_two_masks_ops = {
108         .erp_create = mlxsw_sp_acl_erp_mask_create,
109         .erp_destroy = mlxsw_sp_acl_erp_second_mask_destroy,
110 };
111
112 static const struct mlxsw_sp_acl_erp_table_ops erp_single_mask_ops = {
113         .erp_create = mlxsw_sp_acl_erp_second_mask_create,
114         .erp_destroy = mlxsw_sp_acl_erp_first_mask_destroy,
115 };
116
117 static const struct mlxsw_sp_acl_erp_table_ops erp_no_mask_ops = {
118         .erp_create = mlxsw_sp_acl_erp_first_mask_create,
119         .erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy,
120 };
121
122 bool mlxsw_sp_acl_erp_is_ctcam_erp(const struct mlxsw_sp_acl_erp *erp)
123 {
124         return erp->key.ctcam;
125 }
126
127 u8 mlxsw_sp_acl_erp_id(const struct mlxsw_sp_acl_erp *erp)
128 {
129         return erp->id;
130 }
131
132 static unsigned int
133 mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table)
134 {
135         struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
136         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
137
138         return erp_core->erpt_entries_size[aregion->type];
139 }
140
141 static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table,
142                                    u8 *p_id)
143 {
144         u8 id;
145
146         id = find_first_zero_bit(erp_table->erp_id_bitmap,
147                                  MLXSW_SP_ACL_ERP_MAX_PER_REGION);
148         if (id < MLXSW_SP_ACL_ERP_MAX_PER_REGION) {
149                 __set_bit(id, erp_table->erp_id_bitmap);
150                 *p_id = id;
151                 return 0;
152         }
153
154         return -ENOBUFS;
155 }
156
157 static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table,
158                                     u8 id)
159 {
160         __clear_bit(id, erp_table->erp_id_bitmap);
161 }
162
163 static void
164 mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit,
165                                      struct mlxsw_sp_acl_erp_master_mask *mask)
166 {
167         if (mask->count[bit]++ == 0)
168                 __set_bit(bit, mask->bitmap);
169 }
170
171 static void
172 mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit,
173                                        struct mlxsw_sp_acl_erp_master_mask *mask)
174 {
175         if (--mask->count[bit] == 0)
176                 __clear_bit(bit, mask->bitmap);
177 }
178
179 static int
180 mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table)
181 {
182         struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
183         struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
184         char percr_pl[MLXSW_REG_PERCR_LEN];
185         char *master_mask;
186
187         mlxsw_reg_percr_pack(percr_pl, region->id);
188         master_mask = mlxsw_reg_percr_master_mask_data(percr_pl);
189         bitmap_to_arr32((u32 *) master_mask, erp_table->master_mask.bitmap,
190                         MLXSW_SP_ACL_TCAM_MASK_LEN);
191
192         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
193 }
194
195 static int
196 mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table,
197                                  const struct mlxsw_sp_acl_erp *erp)
198 {
199         unsigned long bit;
200         int err;
201
202         for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
203                 mlxsw_sp_acl_erp_master_mask_bit_set(bit,
204                                                      &erp_table->master_mask);
205
206         err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
207         if (err)
208                 goto err_master_mask_update;
209
210         return 0;
211
212 err_master_mask_update:
213         for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
214                 mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
215                                                        &erp_table->master_mask);
216         return err;
217 }
218
219 static int
220 mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table,
221                                    const struct mlxsw_sp_acl_erp *erp)
222 {
223         unsigned long bit;
224         int err;
225
226         for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
227                 mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
228                                                        &erp_table->master_mask);
229
230         err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
231         if (err)
232                 goto err_master_mask_update;
233
234         return 0;
235
236 err_master_mask_update:
237         for_each_set_bit(bit, erp->mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
238                 mlxsw_sp_acl_erp_master_mask_bit_set(bit,
239                                                      &erp_table->master_mask);
240         return err;
241 }
242
243 static struct mlxsw_sp_acl_erp *
244 mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
245                                 struct mlxsw_sp_acl_erp_key *key)
246 {
247         struct mlxsw_sp_acl_erp *erp;
248         int err;
249
250         erp = kzalloc(sizeof(*erp), GFP_KERNEL);
251         if (!erp)
252                 return ERR_PTR(-ENOMEM);
253
254         err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id);
255         if (err)
256                 goto err_erp_id_get;
257
258         memcpy(&erp->key, key, sizeof(*key));
259         bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask,
260                           MLXSW_SP_ACL_TCAM_MASK_LEN);
261         list_add(&erp->list, &erp_table->atcam_erps_list);
262         refcount_set(&erp->refcnt, 1);
263         erp_table->num_atcam_erps++;
264         erp->erp_table = erp_table;
265
266         err = mlxsw_sp_acl_erp_master_mask_set(erp_table, erp);
267         if (err)
268                 goto err_master_mask_set;
269
270         err = rhashtable_insert_fast(&erp_table->erp_ht, &erp->ht_node,
271                                      mlxsw_sp_acl_erp_ht_params);
272         if (err)
273                 goto err_rhashtable_insert;
274
275         return erp;
276
277 err_rhashtable_insert:
278         mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp);
279 err_master_mask_set:
280         erp_table->num_atcam_erps--;
281         list_del(&erp->list);
282         mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
283 err_erp_id_get:
284         kfree(erp);
285         return ERR_PTR(err);
286 }
287
288 static void
289 mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp)
290 {
291         struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
292
293         rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node,
294                                mlxsw_sp_acl_erp_ht_params);
295         mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp);
296         erp_table->num_atcam_erps--;
297         list_del(&erp->list);
298         mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
299         kfree(erp);
300 }
301
302 static int
303 mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
304                              unsigned int num_erps,
305                              enum mlxsw_sp_acl_atcam_region_type region_type,
306                              unsigned long *p_index)
307 {
308         unsigned int num_rows, entry_size;
309
310         /* We only allow allocations of entire rows */
311         if (num_erps % erp_core->num_erp_banks != 0)
312                 return -EINVAL;
313
314         entry_size = erp_core->erpt_entries_size[region_type];
315         num_rows = num_erps / erp_core->num_erp_banks;
316
317         *p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
318         if (*p_index == 0)
319                 return -ENOBUFS;
320         *p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
321
322         return 0;
323 }
324
325 static void
326 mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core *erp_core,
327                             unsigned int num_erps,
328                             enum mlxsw_sp_acl_atcam_region_type region_type,
329                             unsigned long index)
330 {
331         unsigned long base_index;
332         unsigned int entry_size;
333         size_t size;
334
335         entry_size = erp_core->erpt_entries_size[region_type];
336         base_index = index + MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
337         size = num_erps / erp_core->num_erp_banks * entry_size;
338         gen_pool_free(erp_core->erp_tables, base_index, size);
339 }
340
341 static struct mlxsw_sp_acl_erp *
342 mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table)
343 {
344         if (!list_is_singular(&erp_table->atcam_erps_list))
345                 return NULL;
346
347         return list_first_entry(&erp_table->atcam_erps_list,
348                                 struct mlxsw_sp_acl_erp, list);
349 }
350
351 static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table,
352                                       u8 *p_index)
353 {
354         u8 index;
355
356         index = find_first_zero_bit(erp_table->erp_index_bitmap,
357                                     erp_table->num_max_atcam_erps);
358         if (index < erp_table->num_max_atcam_erps) {
359                 __set_bit(index, erp_table->erp_index_bitmap);
360                 *p_index = index;
361                 return 0;
362         }
363
364         return -ENOBUFS;
365 }
366
367 static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table,
368                                        u8 index)
369 {
370         __clear_bit(index, erp_table->erp_index_bitmap);
371 }
372
373 static void
374 mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table *erp_table,
375                               const struct mlxsw_sp_acl_erp *erp,
376                               u8 *p_erpt_bank, u8 *p_erpt_index)
377 {
378         unsigned int entry_size = mlxsw_sp_acl_erp_table_entry_size(erp_table);
379         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
380         unsigned int row;
381
382         *p_erpt_bank = erp->index % erp_core->num_erp_banks;
383         row = erp->index / erp_core->num_erp_banks;
384         *p_erpt_index = erp_table->base_index + row * entry_size;
385 }
386
387 static int
388 mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
389                                struct mlxsw_sp_acl_erp *erp)
390 {
391         struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
392         enum mlxsw_reg_perpt_key_size key_size;
393         char perpt_pl[MLXSW_REG_PERPT_LEN];
394         u8 erpt_bank, erpt_index;
395
396         mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
397         key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
398         mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
399                              0, erp_table->base_index, erp->index,
400                              erp->key.mask);
401         mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
402                                         MLXSW_SP_ACL_ERP_MAX_PER_REGION);
403         mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, true);
404         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
405 }
406
407 static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp)
408 {
409         char empty_mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
410         struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
411         struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
412         enum mlxsw_reg_perpt_key_size key_size;
413         char perpt_pl[MLXSW_REG_PERPT_LEN];
414         u8 erpt_bank, erpt_index;
415
416         mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
417         key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
418         mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
419                              0, erp_table->base_index, erp->index, empty_mask);
420         mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
421                                         MLXSW_SP_ACL_ERP_MAX_PER_REGION);
422         mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, false);
423         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
424 }
425
426 static int
427 mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table,
428                               bool ctcam_le)
429 {
430         struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
431         struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
432         char pererp_pl[MLXSW_REG_PERERP_LEN];
433
434         mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
435                               erp_table->base_index, 0);
436         mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
437                                          MLXSW_SP_ACL_ERP_MAX_PER_REGION);
438
439         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
440 }
441
442 static void
443 mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table)
444 {
445         struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
446         struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
447         char pererp_pl[MLXSW_REG_PERERP_LEN];
448         struct mlxsw_sp_acl_erp *master_rp;
449
450         master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
451         /* It is possible we do not have a master RP when we disable the
452          * table when there are no rules in the A-TCAM and the last C-TCAM
453          * rule is deleted
454          */
455         mlxsw_reg_pererp_pack(pererp_pl, region->id, false, false, 0, 0,
456                               master_rp ? master_rp->id : 0);
457         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
458 }
459
460 static int
461 mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table)
462 {
463         struct mlxsw_sp_acl_erp *erp;
464         int err;
465
466         list_for_each_entry(erp, &erp_table->atcam_erps_list, list) {
467                 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
468                 if (err)
469                         goto err_table_erp_add;
470         }
471
472         return 0;
473
474 err_table_erp_add:
475         list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list,
476                                              list)
477                 mlxsw_sp_acl_erp_table_erp_del(erp);
478         return err;
479 }
480
481 static int
482 mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table)
483 {
484         unsigned int num_erps, old_num_erps = erp_table->num_max_atcam_erps;
485         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
486         unsigned long old_base_index = erp_table->base_index;
487         bool ctcam_le = erp_table->num_ctcam_erps > 0;
488         int err;
489
490         if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps)
491                 return 0;
492
493         if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION)
494                 return -ENOBUFS;
495
496         num_erps = old_num_erps + erp_core->num_erp_banks;
497         err = mlxsw_sp_acl_erp_table_alloc(erp_core, num_erps,
498                                            erp_table->aregion->type,
499                                            &erp_table->base_index);
500         if (err)
501                 return err;
502         erp_table->num_max_atcam_erps = num_erps;
503
504         err = mlxsw_sp_acl_erp_table_relocate(erp_table);
505         if (err)
506                 goto err_table_relocate;
507
508         err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le);
509         if (err)
510                 goto err_table_enable;
511
512         mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps,
513                                     erp_table->aregion->type, old_base_index);
514
515         return 0;
516
517 err_table_enable:
518 err_table_relocate:
519         erp_table->num_max_atcam_erps = old_num_erps;
520         mlxsw_sp_acl_erp_table_free(erp_core, num_erps,
521                                     erp_table->aregion->type,
522                                     erp_table->base_index);
523         erp_table->base_index = old_base_index;
524         return err;
525 }
526
527 static int
528 mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table)
529 {
530         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
531         struct mlxsw_sp_acl_erp *master_rp;
532         int err;
533
534         /* Initially, allocate a single eRP row. Expand later as needed */
535         err = mlxsw_sp_acl_erp_table_alloc(erp_core, erp_core->num_erp_banks,
536                                            erp_table->aregion->type,
537                                            &erp_table->base_index);
538         if (err)
539                 return err;
540         erp_table->num_max_atcam_erps = erp_core->num_erp_banks;
541
542         /* Transition the sole RP currently configured (the master RP)
543          * to the eRP table
544          */
545         master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
546         if (!master_rp) {
547                 err = -EINVAL;
548                 goto err_table_master_rp;
549         }
550
551         /* Maintain the same eRP bank for the master RP, so that we
552          * wouldn't need to update the bloom filter
553          */
554         master_rp->index = master_rp->index % erp_core->num_erp_banks;
555         __set_bit(master_rp->index, erp_table->erp_index_bitmap);
556
557         err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp);
558         if (err)
559                 goto err_table_master_rp_add;
560
561         err = mlxsw_sp_acl_erp_table_enable(erp_table, false);
562         if (err)
563                 goto err_table_enable;
564
565         return 0;
566
567 err_table_enable:
568         mlxsw_sp_acl_erp_table_erp_del(master_rp);
569 err_table_master_rp_add:
570         __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
571 err_table_master_rp:
572         mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
573                                     erp_table->aregion->type,
574                                     erp_table->base_index);
575         return err;
576 }
577
578 static void
579 mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table)
580 {
581         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
582         struct mlxsw_sp_acl_erp *master_rp;
583
584         mlxsw_sp_acl_erp_table_disable(erp_table);
585         master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
586         if (!master_rp)
587                 return;
588         mlxsw_sp_acl_erp_table_erp_del(master_rp);
589         __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
590         mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
591                                     erp_table->aregion->type,
592                                     erp_table->base_index);
593 }
594
595 static int
596 mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
597                                 struct mlxsw_sp_acl_erp *erp)
598 {
599         struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
600         struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
601         bool ctcam_le = erp_table->num_ctcam_erps > 0;
602         char pererp_pl[MLXSW_REG_PERERP_LEN];
603
604         mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
605                               erp_table->base_index, 0);
606         mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
607                                          MLXSW_SP_ACL_ERP_MAX_PER_REGION);
608         mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, true);
609
610         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
611 }
612
613 static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp)
614 {
615         struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
616         struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
617         struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
618         bool ctcam_le = erp_table->num_ctcam_erps > 0;
619         char pererp_pl[MLXSW_REG_PERERP_LEN];
620
621         mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
622                               erp_table->base_index, 0);
623         mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
624                                          MLXSW_SP_ACL_ERP_MAX_PER_REGION);
625         mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, false);
626
627         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
628 }
629
630 static int
631 mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table)
632 {
633         /* No need to re-enable lookup in the C-TCAM */
634         if (erp_table->num_ctcam_erps > 1)
635                 return 0;
636
637         return mlxsw_sp_acl_erp_table_enable(erp_table, true);
638 }
639
640 static void
641 mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table)
642 {
643         /* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */
644         if (erp_table->num_ctcam_erps > 1)
645                 return;
646
647         mlxsw_sp_acl_erp_table_enable(erp_table, false);
648 }
649
650 static void
651 mlxsw_sp_acl_erp_ctcam_table_ops_set(struct mlxsw_sp_acl_erp_table *erp_table)
652 {
653         switch (erp_table->num_atcam_erps) {
654         case 2:
655                 /* Keep using the eRP table, but correctly set the
656                  * operations pointer so that when an A-TCAM eRP is
657                  * deleted we will transition to use the master mask
658                  */
659                 erp_table->ops = &erp_two_masks_ops;
660                 break;
661         case 1:
662                 /* We only kept the eRP table because we had C-TCAM
663                  * eRPs in use. Now that the last C-TCAM eRP is gone we
664                  * can stop using the table and transition to use the
665                  * master mask
666                  */
667                 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
668                 erp_table->ops = &erp_single_mask_ops;
669                 break;
670         case 0:
671                 /* There are no more eRPs of any kind used by the region
672                  * so free its eRP table and transition to initial state
673                  */
674                 mlxsw_sp_acl_erp_table_disable(erp_table);
675                 mlxsw_sp_acl_erp_table_free(erp_table->erp_core,
676                                             erp_table->num_max_atcam_erps,
677                                             erp_table->aregion->type,
678                                             erp_table->base_index);
679                 erp_table->ops = &erp_no_mask_ops;
680                 break;
681         default:
682                 break;
683         }
684 }
685
686 static struct mlxsw_sp_acl_erp *
687 __mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
688                                      struct mlxsw_sp_acl_erp_key *key)
689 {
690         struct mlxsw_sp_acl_erp *erp;
691         int err;
692
693         erp = kzalloc(sizeof(*erp), GFP_KERNEL);
694         if (!erp)
695                 return ERR_PTR(-ENOMEM);
696
697         memcpy(&erp->key, key, sizeof(*key));
698         bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask,
699                           MLXSW_SP_ACL_TCAM_MASK_LEN);
700         refcount_set(&erp->refcnt, 1);
701         erp_table->num_ctcam_erps++;
702         erp->erp_table = erp_table;
703
704         err = mlxsw_sp_acl_erp_master_mask_set(erp_table, erp);
705         if (err)
706                 goto err_master_mask_set;
707
708         err = rhashtable_insert_fast(&erp_table->erp_ht, &erp->ht_node,
709                                      mlxsw_sp_acl_erp_ht_params);
710         if (err)
711                 goto err_rhashtable_insert;
712
713         err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table);
714         if (err)
715                 goto err_erp_region_ctcam_enable;
716
717         /* When C-TCAM is used, the eRP table must be used */
718         erp_table->ops = &erp_multiple_masks_ops;
719
720         return erp;
721
722 err_erp_region_ctcam_enable:
723         rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node,
724                                mlxsw_sp_acl_erp_ht_params);
725 err_rhashtable_insert:
726         mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp);
727 err_master_mask_set:
728         erp_table->num_ctcam_erps--;
729         kfree(erp);
730         return ERR_PTR(err);
731 }
732
733 static struct mlxsw_sp_acl_erp *
734 mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
735                                    struct mlxsw_sp_acl_erp_key *key)
736 {
737         struct mlxsw_sp_acl_erp *erp;
738         int err;
739
740         /* There is a special situation where we need to spill rules
741          * into the C-TCAM, yet the region is still using a master
742          * mask and thus not performing a lookup in the C-TCAM. This
743          * can happen when two rules that only differ in priority - and
744          * thus sharing the same key - are programmed. In this case
745          * we transition the region to use an eRP table
746          */
747         err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
748         if (err)
749                 return ERR_PTR(err);
750
751         erp = __mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
752         if (IS_ERR(erp)) {
753                 err = PTR_ERR(erp);
754                 goto err_erp_create;
755         }
756
757         return erp;
758
759 err_erp_create:
760         mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
761         return ERR_PTR(err);
762 }
763
764 static void
765 mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp)
766 {
767         struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
768
769         mlxsw_sp_acl_erp_region_ctcam_disable(erp_table);
770         rhashtable_remove_fast(&erp_table->erp_ht, &erp->ht_node,
771                                mlxsw_sp_acl_erp_ht_params);
772         mlxsw_sp_acl_erp_master_mask_clear(erp_table, erp);
773         erp_table->num_ctcam_erps--;
774         kfree(erp);
775
776         /* Once the last C-TCAM eRP was destroyed, the state we
777          * transition to depends on the number of A-TCAM eRPs currently
778          * in use
779          */
780         if (erp_table->num_ctcam_erps > 0)
781                 return;
782         mlxsw_sp_acl_erp_ctcam_table_ops_set(erp_table);
783 }
784
785 static struct mlxsw_sp_acl_erp *
786 mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
787                              struct mlxsw_sp_acl_erp_key *key)
788 {
789         struct mlxsw_sp_acl_erp *erp;
790         int err;
791
792         if (key->ctcam)
793                 return __mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
794
795         /* Expand the eRP table for the new eRP, if needed */
796         err = mlxsw_sp_acl_erp_table_expand(erp_table);
797         if (err)
798                 return ERR_PTR(err);
799
800         erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
801         if (IS_ERR(erp))
802                 return erp;
803
804         err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
805         if (err)
806                 goto err_erp_index_get;
807
808         err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
809         if (err)
810                 goto err_table_erp_add;
811
812         err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
813         if (err)
814                 goto err_region_erp_add;
815
816         erp_table->ops = &erp_multiple_masks_ops;
817
818         return erp;
819
820 err_region_erp_add:
821         mlxsw_sp_acl_erp_table_erp_del(erp);
822 err_table_erp_add:
823         mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
824 err_erp_index_get:
825         mlxsw_sp_acl_erp_generic_destroy(erp);
826         return ERR_PTR(err);
827 }
828
829 static void
830 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
831                               struct mlxsw_sp_acl_erp *erp)
832 {
833         if (erp->key.ctcam)
834                 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
835
836         mlxsw_sp_acl_erp_region_erp_del(erp);
837         mlxsw_sp_acl_erp_table_erp_del(erp);
838         mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
839         mlxsw_sp_acl_erp_generic_destroy(erp);
840
841         if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0)
842                 erp_table->ops = &erp_two_masks_ops;
843 }
844
845 static struct mlxsw_sp_acl_erp *
846 mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
847                                     struct mlxsw_sp_acl_erp_key *key)
848 {
849         struct mlxsw_sp_acl_erp *erp;
850         int err;
851
852         if (key->ctcam)
853                 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
854
855         /* Transition to use eRP table instead of master mask */
856         err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
857         if (err)
858                 return ERR_PTR(err);
859
860         erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
861         if (IS_ERR(erp)) {
862                 err = PTR_ERR(erp);
863                 goto err_erp_create;
864         }
865
866         err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
867         if (err)
868                 goto err_erp_index_get;
869
870         err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
871         if (err)
872                 goto err_table_erp_add;
873
874         err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
875         if (err)
876                 goto err_region_erp_add;
877
878         erp_table->ops = &erp_two_masks_ops;
879
880         return erp;
881
882 err_region_erp_add:
883         mlxsw_sp_acl_erp_table_erp_del(erp);
884 err_table_erp_add:
885         mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
886 err_erp_index_get:
887         mlxsw_sp_acl_erp_generic_destroy(erp);
888 err_erp_create:
889         mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
890         return ERR_PTR(err);
891 }
892
893 static void
894 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
895                                      struct mlxsw_sp_acl_erp *erp)
896 {
897         if (erp->key.ctcam)
898                 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
899
900         mlxsw_sp_acl_erp_region_erp_del(erp);
901         mlxsw_sp_acl_erp_table_erp_del(erp);
902         mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
903         mlxsw_sp_acl_erp_generic_destroy(erp);
904         /* Transition to use master mask instead of eRP table */
905         mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
906
907         erp_table->ops = &erp_single_mask_ops;
908 }
909
910 static struct mlxsw_sp_acl_erp *
911 mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
912                                    struct mlxsw_sp_acl_erp_key *key)
913 {
914         struct mlxsw_sp_acl_erp *erp;
915
916         if (key->ctcam)
917                 return ERR_PTR(-EINVAL);
918
919         erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
920         if (IS_ERR(erp))
921                 return erp;
922
923         erp_table->ops = &erp_single_mask_ops;
924
925         return erp;
926 }
927
928 static void
929 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
930                                     struct mlxsw_sp_acl_erp *erp)
931 {
932         mlxsw_sp_acl_erp_generic_destroy(erp);
933         erp_table->ops = &erp_no_mask_ops;
934 }
935
936 static void
937 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
938                                  struct mlxsw_sp_acl_erp *erp)
939 {
940         WARN_ON(1);
941 }
942
943 struct mlxsw_sp_acl_erp *
944 mlxsw_sp_acl_erp_get(struct mlxsw_sp_acl_atcam_region *aregion,
945                      const char *mask, bool ctcam)
946 {
947         struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
948         struct mlxsw_sp_acl_erp_key key;
949         struct mlxsw_sp_acl_erp *erp;
950
951         /* eRPs are allocated from a shared resource, but currently all
952          * allocations are done under RTNL.
953          */
954         ASSERT_RTNL();
955
956         memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN);
957         key.ctcam = ctcam;
958         erp = rhashtable_lookup_fast(&erp_table->erp_ht, &key,
959                                      mlxsw_sp_acl_erp_ht_params);
960         if (erp) {
961                 refcount_inc(&erp->refcnt);
962                 return erp;
963         }
964
965         return erp_table->ops->erp_create(erp_table, &key);
966 }
967
968 void mlxsw_sp_acl_erp_put(struct mlxsw_sp_acl_atcam_region *aregion,
969                           struct mlxsw_sp_acl_erp *erp)
970 {
971         struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
972
973         ASSERT_RTNL();
974
975         if (!refcount_dec_and_test(&erp->refcnt))
976                 return;
977
978         erp_table->ops->erp_destroy(erp_table, erp);
979 }
980
981 static struct mlxsw_sp_acl_erp_table *
982 mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion)
983 {
984         struct mlxsw_sp_acl_erp_table *erp_table;
985         int err;
986
987         erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL);
988         if (!erp_table)
989                 return ERR_PTR(-ENOMEM);
990
991         err = rhashtable_init(&erp_table->erp_ht, &mlxsw_sp_acl_erp_ht_params);
992         if (err)
993                 goto err_rhashtable_init;
994
995         erp_table->erp_core = aregion->atcam->erp_core;
996         erp_table->ops = &erp_no_mask_ops;
997         INIT_LIST_HEAD(&erp_table->atcam_erps_list);
998         erp_table->aregion = aregion;
999
1000         return erp_table;
1001
1002 err_rhashtable_init:
1003         kfree(erp_table);
1004         return ERR_PTR(err);
1005 }
1006
1007 static void
1008 mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
1009 {
1010         WARN_ON(!list_empty(&erp_table->atcam_erps_list));
1011         rhashtable_destroy(&erp_table->erp_ht);
1012         kfree(erp_table);
1013 }
1014
1015 static int
1016 mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion)
1017 {
1018         struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1019         char percr_pl[MLXSW_REG_PERCR_LEN];
1020
1021         mlxsw_reg_percr_pack(percr_pl, aregion->region->id);
1022         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
1023 }
1024
1025 static int
1026 mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
1027 {
1028         struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1029         char pererp_pl[MLXSW_REG_PERERP_LEN];
1030
1031         mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0,
1032                               0, 0);
1033         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
1034 }
1035
1036 int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion)
1037 {
1038         struct mlxsw_sp_acl_erp_table *erp_table;
1039         int err;
1040
1041         erp_table = mlxsw_sp_acl_erp_table_create(aregion);
1042         if (IS_ERR(erp_table))
1043                 return PTR_ERR(erp_table);
1044         aregion->erp_table = erp_table;
1045
1046         /* Initialize the region's master mask to all zeroes */
1047         err = mlxsw_sp_acl_erp_master_mask_init(aregion);
1048         if (err)
1049                 goto err_erp_master_mask_init;
1050
1051         /* Initialize the region to not use the eRP table */
1052         err = mlxsw_sp_acl_erp_region_param_init(aregion);
1053         if (err)
1054                 goto err_erp_region_param_init;
1055
1056         return 0;
1057
1058 err_erp_region_param_init:
1059 err_erp_master_mask_init:
1060         mlxsw_sp_acl_erp_table_destroy(erp_table);
1061         return err;
1062 }
1063
1064 void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
1065 {
1066         mlxsw_sp_acl_erp_table_destroy(aregion->erp_table);
1067 }
1068
1069 static int
1070 mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp,
1071                                     struct mlxsw_sp_acl_erp_core *erp_core)
1072 {
1073         unsigned int size;
1074
1075         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) ||
1076             !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) ||
1077             !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) ||
1078             !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB))
1079                 return -EIO;
1080
1081         size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB);
1082         erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size;
1083
1084         size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB);
1085         erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size;
1086
1087         size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB);
1088         erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size;
1089
1090         size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB);
1091         erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size;
1092
1093         return 0;
1094 }
1095
1096 static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp,
1097                                         struct mlxsw_sp_acl_erp_core *erp_core)
1098 {
1099         unsigned int erpt_bank_size;
1100         int err;
1101
1102         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) ||
1103             !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS))
1104                 return -EIO;
1105         erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1106                                             ACL_MAX_ERPT_BANK_SIZE);
1107         erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1108                                                      ACL_MAX_ERPT_BANKS);
1109
1110         erp_core->erp_tables = gen_pool_create(0, -1);
1111         if (!erp_core->erp_tables)
1112                 return -ENOMEM;
1113         gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL);
1114
1115         err = gen_pool_add(erp_core->erp_tables,
1116                            MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size,
1117                            -1);
1118         if (err)
1119                 goto err_gen_pool_add;
1120
1121         /* Different regions require masks of different sizes */
1122         err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core);
1123         if (err)
1124                 goto err_erp_tables_sizes_query;
1125
1126         return 0;
1127
1128 err_erp_tables_sizes_query:
1129 err_gen_pool_add:
1130         gen_pool_destroy(erp_core->erp_tables);
1131         return err;
1132 }
1133
1134 static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp,
1135                                          struct mlxsw_sp_acl_erp_core *erp_core)
1136 {
1137         gen_pool_destroy(erp_core->erp_tables);
1138 }
1139
1140 int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
1141                            struct mlxsw_sp_acl_atcam *atcam)
1142 {
1143         struct mlxsw_sp_acl_erp_core *erp_core;
1144         int err;
1145
1146         erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL);
1147         if (!erp_core)
1148                 return -ENOMEM;
1149         erp_core->mlxsw_sp = mlxsw_sp;
1150         atcam->erp_core = erp_core;
1151
1152         err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core);
1153         if (err)
1154                 goto err_erp_tables_init;
1155
1156         return 0;
1157
1158 err_erp_tables_init:
1159         kfree(erp_core);
1160         return err;
1161 }
1162
1163 void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
1164                             struct mlxsw_sp_acl_atcam *atcam)
1165 {
1166         mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core);
1167         kfree(atcam->erp_core);
1168 }