Merge tag 'nfs-for-5.0-3' of git://git.linux-nfs.org/projects/anna/linux-nfs
[sfrench/cifs-2.6.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/objagg.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         struct mlxsw_sp_acl_bf *bf;
28         unsigned int num_erp_banks;
29 };
30
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)
35         bool ctcam;
36 };
37
38 struct mlxsw_sp_acl_erp {
39         struct mlxsw_sp_acl_erp_key key;
40         u8 id;
41         u8 index;
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;
45 };
46
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];
50 };
51
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;
66 };
67
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);
74 };
75
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);
79 static void
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);
85 static void
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);
91 static void
92 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
93                                     struct mlxsw_sp_acl_erp *erp);
94 static void
95 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
96                                  struct mlxsw_sp_acl_erp *erp);
97
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,
101 };
102
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,
106 };
107
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,
111 };
112
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,
116 };
117
118 static bool
119 mlxsw_sp_acl_erp_table_is_used(const struct mlxsw_sp_acl_erp_table *erp_table)
120 {
121         return erp_table->ops != &erp_single_mask_ops &&
122                erp_table->ops != &erp_no_mask_ops;
123 }
124
125 static unsigned int
126 mlxsw_sp_acl_erp_bank_get(const struct mlxsw_sp_acl_erp *erp)
127 {
128         return erp->index % erp->erp_table->erp_core->num_erp_banks;
129 }
130
131 static unsigned int
132 mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table)
133 {
134         struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
135         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
136
137         return erp_core->erpt_entries_size[aregion->type];
138 }
139
140 static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table,
141                                    u8 *p_id)
142 {
143         u8 id;
144
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);
149                 *p_id = id;
150                 return 0;
151         }
152
153         return -ENOBUFS;
154 }
155
156 static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table,
157                                     u8 id)
158 {
159         __clear_bit(id, erp_table->erp_id_bitmap);
160 }
161
162 static void
163 mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit,
164                                      struct mlxsw_sp_acl_erp_master_mask *mask)
165 {
166         if (mask->count[bit]++ == 0)
167                 __set_bit(bit, mask->bitmap);
168 }
169
170 static void
171 mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit,
172                                        struct mlxsw_sp_acl_erp_master_mask *mask)
173 {
174         if (--mask->count[bit] == 0)
175                 __clear_bit(bit, mask->bitmap);
176 }
177
178 static int
179 mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table)
180 {
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];
184         char *master_mask;
185
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);
190
191         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
192 }
193
194 static int
195 mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table,
196                                  struct mlxsw_sp_acl_erp_key *key)
197 {
198         DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
199         unsigned long bit;
200         int err;
201
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);
207
208         err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
209         if (err)
210                 goto err_master_mask_update;
211
212         return 0;
213
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);
218         return err;
219 }
220
221 static int
222 mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table,
223                                    struct mlxsw_sp_acl_erp_key *key)
224 {
225         DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
226         unsigned long bit;
227         int err;
228
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);
234
235         err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
236         if (err)
237                 goto err_master_mask_update;
238
239         return 0;
240
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);
245         return err;
246 }
247
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)
251 {
252         struct mlxsw_sp_acl_erp *erp;
253         int err;
254
255         erp = kzalloc(sizeof(*erp), GFP_KERNEL);
256         if (!erp)
257                 return ERR_PTR(-ENOMEM);
258
259         err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id);
260         if (err)
261                 goto err_erp_id_get;
262
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;
267
268         err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
269         if (err)
270                 goto err_master_mask_set;
271
272         return erp;
273
274 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);
278 err_erp_id_get:
279         kfree(erp);
280         return ERR_PTR(err);
281 }
282
283 static void
284 mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp)
285 {
286         struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
287
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);
292         kfree(erp);
293 }
294
295 static int
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)
300 {
301         unsigned int num_rows, entry_size;
302
303         /* We only allow allocations of entire rows */
304         if (num_erps % erp_core->num_erp_banks != 0)
305                 return -EINVAL;
306
307         entry_size = erp_core->erpt_entries_size[region_type];
308         num_rows = num_erps / erp_core->num_erp_banks;
309
310         *p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
311         if (*p_index == 0)
312                 return -ENOBUFS;
313         *p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
314
315         return 0;
316 }
317
318 static void
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,
322                             unsigned long index)
323 {
324         unsigned long base_index;
325         unsigned int entry_size;
326         size_t size;
327
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);
332 }
333
334 static struct mlxsw_sp_acl_erp *
335 mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table)
336 {
337         if (!list_is_singular(&erp_table->atcam_erps_list))
338                 return NULL;
339
340         return list_first_entry(&erp_table->atcam_erps_list,
341                                 struct mlxsw_sp_acl_erp, list);
342 }
343
344 static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table,
345                                       u8 *p_index)
346 {
347         u8 index;
348
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);
353                 *p_index = index;
354                 return 0;
355         }
356
357         return -ENOBUFS;
358 }
359
360 static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table,
361                                        u8 index)
362 {
363         __clear_bit(index, erp_table->erp_index_bitmap);
364 }
365
366 static void
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)
370 {
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;
373         unsigned int row;
374
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;
378 }
379
380 static int
381 mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
382                                struct mlxsw_sp_acl_erp *erp)
383 {
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;
388
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,
393                              erp->key.mask);
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);
398 }
399
400 static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp)
401 {
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;
408
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);
417 }
418
419 static int
420 mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table,
421                               bool ctcam_le)
422 {
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];
426
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);
431
432         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
433 }
434
435 static void
436 mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table)
437 {
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;
442
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
446          * rule is deleted
447          */
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);
451 }
452
453 static int
454 mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table)
455 {
456         struct mlxsw_sp_acl_erp *erp;
457         int err;
458
459         list_for_each_entry(erp, &erp_table->atcam_erps_list, list) {
460                 err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
461                 if (err)
462                         goto err_table_erp_add;
463         }
464
465         return 0;
466
467 err_table_erp_add:
468         list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list,
469                                              list)
470                 mlxsw_sp_acl_erp_table_erp_del(erp);
471         return err;
472 }
473
474 static int
475 mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table)
476 {
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;
481         int err;
482
483         if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps)
484                 return 0;
485
486         if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION)
487                 return -ENOBUFS;
488
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);
493         if (err)
494                 return err;
495         erp_table->num_max_atcam_erps = num_erps;
496
497         err = mlxsw_sp_acl_erp_table_relocate(erp_table);
498         if (err)
499                 goto err_table_relocate;
500
501         err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le);
502         if (err)
503                 goto err_table_enable;
504
505         mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps,
506                                     erp_table->aregion->type, old_base_index);
507
508         return 0;
509
510 err_table_enable:
511 err_table_relocate:
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;
517         return err;
518 }
519
520 static int
521 mlxsw_acl_erp_table_bf_add(struct mlxsw_sp_acl_erp_table *erp_table,
522                            struct mlxsw_sp_acl_erp *erp)
523 {
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;
527         int err;
528
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);
533                 if (err)
534                         goto bf_entry_add_err;
535         }
536
537         return 0;
538
539 bf_entry_add_err:
540         list_for_each_entry_continue_reverse(aentry, &aregion->entries_list,
541                                              list)
542                 mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
543                                           erp_table->erp_core->bf,
544                                           aregion, erp_bank, aentry);
545         return err;
546 }
547
548 static void
549 mlxsw_acl_erp_table_bf_del(struct mlxsw_sp_acl_erp_table *erp_table,
550                            struct mlxsw_sp_acl_erp *erp)
551 {
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;
555
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);
560 }
561
562 static int
563 mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table)
564 {
565         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
566         struct mlxsw_sp_acl_erp *master_rp;
567         int err;
568
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);
573         if (err)
574                 return err;
575         erp_table->num_max_atcam_erps = erp_core->num_erp_banks;
576
577         /* Transition the sole RP currently configured (the master RP)
578          * to the eRP table
579          */
580         master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
581         if (!master_rp) {
582                 err = -EINVAL;
583                 goto err_table_master_rp;
584         }
585
586         /* Make sure the master RP is using a valid index, as
587          * only a single eRP row is currently allocated.
588          */
589         master_rp->index = 0;
590         __set_bit(master_rp->index, erp_table->erp_index_bitmap);
591
592         err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp);
593         if (err)
594                 goto err_table_master_rp_add;
595
596         /* Update Bloom filter before enabling eRP table, as rules
597          * on the master RP were not set to Bloom filter up to this
598          * point.
599          */
600         err = mlxsw_acl_erp_table_bf_add(erp_table, master_rp);
601         if (err)
602                 goto err_table_bf_add;
603
604         err = mlxsw_sp_acl_erp_table_enable(erp_table, false);
605         if (err)
606                 goto err_table_enable;
607
608         return 0;
609
610 err_table_enable:
611         mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
612 err_table_bf_add:
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);
616 err_table_master_rp:
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);
620         return err;
621 }
622
623 static void
624 mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table)
625 {
626         struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
627         struct mlxsw_sp_acl_erp *master_rp;
628
629         mlxsw_sp_acl_erp_table_disable(erp_table);
630         master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
631         if (!master_rp)
632                 return;
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);
639 }
640
641 static int
642 mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
643                                 struct mlxsw_sp_acl_erp *erp)
644 {
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];
649
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);
655
656         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
657 }
658
659 static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp)
660 {
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];
666
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);
672
673         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
674 }
675
676 static int
677 mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table)
678 {
679         /* No need to re-enable lookup in the C-TCAM */
680         if (erp_table->num_ctcam_erps > 1)
681                 return 0;
682
683         return mlxsw_sp_acl_erp_table_enable(erp_table, true);
684 }
685
686 static void
687 mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table)
688 {
689         /* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */
690         if (erp_table->num_ctcam_erps > 1)
691                 return;
692
693         mlxsw_sp_acl_erp_table_enable(erp_table, false);
694 }
695
696 static int
697 __mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
698                                    unsigned int *inc_num)
699 {
700         int err;
701
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
704          */
705         if (!mlxsw_sp_acl_erp_table_is_used(erp_table)) {
706                 err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
707                 if (err)
708                         return err;
709         }
710
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;
714
715         (*inc_num)++;
716
717         return 0;
718 }
719
720 static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table)
721 {
722         return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
723                                                   &erp_table->num_ctcam_erps);
724 }
725
726 static int mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table *erp_table)
727 {
728         return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
729                                                   &erp_table->num_deltas);
730 }
731
732 static void
733 __mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table *erp_table,
734                                    unsigned int *dec_num)
735 {
736         (*dec_num)--;
737
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
740          * in use.
741          */
742         if (erp_table->num_ctcam_erps > 0 || erp_table->num_deltas > 0)
743                 return;
744
745         switch (erp_table->num_atcam_erps) {
746         case 2:
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
750                  */
751                 erp_table->ops = &erp_two_masks_ops;
752                 break;
753         case 1:
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
757                  * master mask
758                  */
759                 mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
760                 erp_table->ops = &erp_single_mask_ops;
761                 break;
762         case 0:
763                 /* There are no more eRPs of any kind used by the region
764                  * so free its eRP table and transition to initial state
765                  */
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;
772                 break;
773         default:
774                 break;
775         }
776 }
777
778 static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table)
779 {
780         __mlxsw_sp_acl_erp_table_other_dec(erp_table,
781                                            &erp_table->num_ctcam_erps);
782 }
783
784 static void mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table *erp_table)
785 {
786         __mlxsw_sp_acl_erp_table_other_dec(erp_table,
787                                            &erp_table->num_deltas);
788 }
789
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)
793 {
794         struct mlxsw_sp_acl_erp *erp;
795         int err;
796
797         erp = kzalloc(sizeof(*erp), GFP_KERNEL);
798         if (!erp)
799                 return ERR_PTR(-ENOMEM);
800
801         memcpy(&erp->key, key, sizeof(*key));
802         bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask,
803                           MLXSW_SP_ACL_TCAM_MASK_LEN);
804
805         err = mlxsw_sp_acl_erp_ctcam_inc(erp_table);
806         if (err)
807                 goto err_erp_ctcam_inc;
808
809         erp->erp_table = erp_table;
810
811         err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
812         if (err)
813                 goto err_master_mask_set;
814
815         err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table);
816         if (err)
817                 goto err_erp_region_ctcam_enable;
818
819         return erp;
820
821 err_erp_region_ctcam_enable:
822         mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
823 err_master_mask_set:
824         mlxsw_sp_acl_erp_ctcam_dec(erp_table);
825 err_erp_ctcam_inc:
826         kfree(erp);
827         return ERR_PTR(err);
828 }
829
830 static void
831 mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp)
832 {
833         struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
834
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);
838         kfree(erp);
839 }
840
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)
844 {
845         struct mlxsw_sp_acl_erp *erp;
846         int err;
847
848         if (key->ctcam)
849                 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
850
851         /* Expand the eRP table for the new eRP, if needed */
852         err = mlxsw_sp_acl_erp_table_expand(erp_table);
853         if (err)
854                 return ERR_PTR(err);
855
856         erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
857         if (IS_ERR(erp))
858                 return erp;
859
860         err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
861         if (err)
862                 goto err_erp_index_get;
863
864         err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
865         if (err)
866                 goto err_table_erp_add;
867
868         err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
869         if (err)
870                 goto err_region_erp_add;
871
872         erp_table->ops = &erp_multiple_masks_ops;
873
874         return erp;
875
876 err_region_erp_add:
877         mlxsw_sp_acl_erp_table_erp_del(erp);
878 err_table_erp_add:
879         mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
880 err_erp_index_get:
881         mlxsw_sp_acl_erp_generic_destroy(erp);
882         return ERR_PTR(err);
883 }
884
885 static void
886 mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
887                               struct mlxsw_sp_acl_erp *erp)
888 {
889         if (erp->key.ctcam)
890                 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
891
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);
896
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;
900 }
901
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)
905 {
906         struct mlxsw_sp_acl_erp *erp;
907         int err;
908
909         if (key->ctcam)
910                 return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
911
912         /* Transition to use eRP table instead of master mask */
913         err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
914         if (err)
915                 return ERR_PTR(err);
916
917         erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
918         if (IS_ERR(erp)) {
919                 err = PTR_ERR(erp);
920                 goto err_erp_create;
921         }
922
923         err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
924         if (err)
925                 goto err_erp_index_get;
926
927         err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
928         if (err)
929                 goto err_table_erp_add;
930
931         err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
932         if (err)
933                 goto err_region_erp_add;
934
935         erp_table->ops = &erp_two_masks_ops;
936
937         return erp;
938
939 err_region_erp_add:
940         mlxsw_sp_acl_erp_table_erp_del(erp);
941 err_table_erp_add:
942         mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
943 err_erp_index_get:
944         mlxsw_sp_acl_erp_generic_destroy(erp);
945 err_erp_create:
946         mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
947         return ERR_PTR(err);
948 }
949
950 static void
951 mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
952                                      struct mlxsw_sp_acl_erp *erp)
953 {
954         if (erp->key.ctcam)
955                 return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
956
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);
963
964         erp_table->ops = &erp_single_mask_ops;
965 }
966
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)
970 {
971         struct mlxsw_sp_acl_erp *erp;
972
973         if (key->ctcam)
974                 return ERR_PTR(-EINVAL);
975
976         erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
977         if (IS_ERR(erp))
978                 return erp;
979
980         erp_table->ops = &erp_single_mask_ops;
981
982         return erp;
983 }
984
985 static void
986 mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
987                                     struct mlxsw_sp_acl_erp *erp)
988 {
989         mlxsw_sp_acl_erp_generic_destroy(erp);
990         erp_table->ops = &erp_no_mask_ops;
991 }
992
993 static void
994 mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
995                                  struct mlxsw_sp_acl_erp *erp)
996 {
997         WARN_ON(1);
998 }
999
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)
1003 {
1004         struct mlxsw_sp_acl_erp_key key;
1005         struct objagg_obj *objagg_obj;
1006
1007         /* eRPs are allocated from a shared resource, but currently all
1008          * allocations are done under RTNL.
1009          */
1010         ASSERT_RTNL();
1011
1012         memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN);
1013         key.ctcam = ctcam;
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;
1018 }
1019
1020 void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion,
1021                                struct mlxsw_sp_acl_erp_mask *erp_mask)
1022 {
1023         struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1024
1025         objagg_obj_put(aregion->erp_table->objagg, objagg_obj);
1026 }
1027
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)
1032 {
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;
1036
1037         ASSERT_RTNL();
1038         if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1039                 return 0;
1040
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);
1045 }
1046
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)
1051 {
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;
1055
1056         if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1057                 return;
1058
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);
1063 }
1064
1065 bool
1066 mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1067 {
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);
1070
1071         return key->ctcam;
1072 }
1073
1074 u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1075 {
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);
1078
1079         return erp->id;
1080 }
1081
1082 struct mlxsw_sp_acl_erp_delta {
1083         struct mlxsw_sp_acl_erp_key key;
1084         u16 start;
1085         u8 mask;
1086 };
1087
1088 u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta)
1089 {
1090         return delta->start;
1091 }
1092
1093 u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta)
1094 {
1095         return delta->mask;
1096 }
1097
1098 u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta,
1099                                 const char *enc_key)
1100 {
1101         u16 start = delta->start;
1102         u8 mask = delta->mask;
1103         u16 tmp;
1104
1105         if (!mask)
1106                 return 0;
1107
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;
1111         tmp >>= start % 8;
1112         tmp &= mask;
1113         return tmp;
1114 }
1115
1116 void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta,
1117                                   const char *enc_key)
1118 {
1119         u16 start = delta->start;
1120         u8 mask = delta->mask;
1121         unsigned char *byte;
1122         u16 tmp;
1123
1124         tmp = mask;
1125         tmp <<= start % 8;
1126         tmp = ~tmp;
1127
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;
1133         }
1134 }
1135
1136 static const struct mlxsw_sp_acl_erp_delta
1137 mlxsw_sp_acl_erp_delta_default = {};
1138
1139 const struct mlxsw_sp_acl_erp_delta *
1140 mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1141 {
1142         struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1143         const struct mlxsw_sp_acl_erp_delta *delta;
1144
1145         delta = objagg_obj_delta_priv(objagg_obj);
1146         if (!delta)
1147                 delta = &mlxsw_sp_acl_erp_delta_default;
1148         return delta;
1149 }
1150
1151 static int
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)
1155 {
1156         int offset = 0;
1157         int si = -1;
1158         u16 pmask;
1159         u16 mask;
1160         int i;
1161
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)])
1165                         continue;
1166                 if (si == -1)
1167                         si = i;
1168                 else if (si != i - 1)
1169                         return -EINVAL;
1170         }
1171         if (si == -1) {
1172                 /* The masks are the same, this cannot happen.
1173                  * That means the caller is broken.
1174                  */
1175                 WARN_ON(1);
1176                 *delta_start = 0;
1177                 *delta_mask = 0;
1178                 return 0;
1179         }
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;
1185         }
1186
1187         if ((pmask ^ mask) & pmask)
1188                 return -EINVAL;
1189         mask &= ~pmask;
1190         while (!(mask & (1 << offset)))
1191                 offset++;
1192         while (!(mask & 1))
1193                 mask >>= 1;
1194         if (mask & 0xff00)
1195                 return -EINVAL;
1196
1197         *delta_start = si * 8 + offset;
1198         *delta_mask = mask;
1199
1200         return 0;
1201 }
1202
1203 static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
1204                                            void *obj)
1205 {
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;
1211         u16 delta_start;
1212         u8 delta_mask;
1213         int err;
1214
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);
1219         if (err)
1220                 return ERR_PTR(-EINVAL);
1221
1222         delta = kzalloc(sizeof(*delta), GFP_KERNEL);
1223         if (!delta)
1224                 return ERR_PTR(-ENOMEM);
1225         delta->start = delta_start;
1226         delta->mask = delta_mask;
1227
1228         err = mlxsw_sp_acl_erp_delta_inc(erp_table);
1229         if (err)
1230                 goto err_erp_delta_inc;
1231
1232         memcpy(&delta->key, key, sizeof(*key));
1233         err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key);
1234         if (err)
1235                 goto err_master_mask_set;
1236
1237         return delta;
1238
1239 err_master_mask_set:
1240         mlxsw_sp_acl_erp_delta_dec(erp_table);
1241 err_erp_delta_inc:
1242         kfree(delta);
1243         return ERR_PTR(err);
1244 }
1245
1246 static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
1247 {
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;
1251
1252         mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key);
1253         mlxsw_sp_acl_erp_delta_dec(erp_table);
1254         kfree(delta);
1255 }
1256
1257 static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj)
1258 {
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;
1262
1263         return erp_table->ops->erp_create(erp_table, key);
1264 }
1265
1266 static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
1267 {
1268         struct mlxsw_sp_acl_atcam_region *aregion = priv;
1269         struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1270
1271         erp_table->ops->erp_destroy(erp_table, root_priv);
1272 }
1273
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,
1280 };
1281
1282 static struct mlxsw_sp_acl_erp_table *
1283 mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion)
1284 {
1285         struct mlxsw_sp_acl_erp_table *erp_table;
1286         int err;
1287
1288         erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL);
1289         if (!erp_table)
1290                 return ERR_PTR(-ENOMEM);
1291
1292         erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
1293                                           aregion);
1294         if (IS_ERR(erp_table->objagg)) {
1295                 err = PTR_ERR(erp_table->objagg);
1296                 goto err_objagg_create;
1297         }
1298
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;
1303
1304         return erp_table;
1305
1306 err_objagg_create:
1307         kfree(erp_table);
1308         return ERR_PTR(err);
1309 }
1310
1311 static void
1312 mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
1313 {
1314         WARN_ON(!list_empty(&erp_table->atcam_erps_list));
1315         objagg_destroy(erp_table->objagg);
1316         kfree(erp_table);
1317 }
1318
1319 static int
1320 mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion)
1321 {
1322         struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1323         char percr_pl[MLXSW_REG_PERCR_LEN];
1324
1325         mlxsw_reg_percr_pack(percr_pl, aregion->region->id);
1326         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
1327 }
1328
1329 static int
1330 mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
1331 {
1332         struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1333         char pererp_pl[MLXSW_REG_PERERP_LEN];
1334
1335         mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0,
1336                               0, 0);
1337         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
1338 }
1339
1340 int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion)
1341 {
1342         struct mlxsw_sp_acl_erp_table *erp_table;
1343         int err;
1344
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;
1349
1350         /* Initialize the region's master mask to all zeroes */
1351         err = mlxsw_sp_acl_erp_master_mask_init(aregion);
1352         if (err)
1353                 goto err_erp_master_mask_init;
1354
1355         /* Initialize the region to not use the eRP table */
1356         err = mlxsw_sp_acl_erp_region_param_init(aregion);
1357         if (err)
1358                 goto err_erp_region_param_init;
1359
1360         return 0;
1361
1362 err_erp_region_param_init:
1363 err_erp_master_mask_init:
1364         mlxsw_sp_acl_erp_table_destroy(erp_table);
1365         return err;
1366 }
1367
1368 void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
1369 {
1370         mlxsw_sp_acl_erp_table_destroy(aregion->erp_table);
1371 }
1372
1373 static int
1374 mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp,
1375                                     struct mlxsw_sp_acl_erp_core *erp_core)
1376 {
1377         unsigned int size;
1378
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))
1383                 return -EIO;
1384
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;
1387
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;
1390
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;
1393
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;
1396
1397         return 0;
1398 }
1399
1400 static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp,
1401                                         struct mlxsw_sp_acl_erp_core *erp_core)
1402 {
1403         unsigned int erpt_bank_size;
1404         int err;
1405
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))
1408                 return -EIO;
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);
1413
1414         erp_core->erp_tables = gen_pool_create(0, -1);
1415         if (!erp_core->erp_tables)
1416                 return -ENOMEM;
1417         gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL);
1418
1419         err = gen_pool_add(erp_core->erp_tables,
1420                            MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size,
1421                            -1);
1422         if (err)
1423                 goto err_gen_pool_add;
1424
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);
1428                 goto err_bf_init;
1429         }
1430
1431         /* Different regions require masks of different sizes */
1432         err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core);
1433         if (err)
1434                 goto err_erp_tables_sizes_query;
1435
1436         return 0;
1437
1438 err_erp_tables_sizes_query:
1439         mlxsw_sp_acl_bf_fini(erp_core->bf);
1440 err_bf_init:
1441 err_gen_pool_add:
1442         gen_pool_destroy(erp_core->erp_tables);
1443         return err;
1444 }
1445
1446 static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp,
1447                                          struct mlxsw_sp_acl_erp_core *erp_core)
1448 {
1449         mlxsw_sp_acl_bf_fini(erp_core->bf);
1450         gen_pool_destroy(erp_core->erp_tables);
1451 }
1452
1453 int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
1454                            struct mlxsw_sp_acl_atcam *atcam)
1455 {
1456         struct mlxsw_sp_acl_erp_core *erp_core;
1457         int err;
1458
1459         erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL);
1460         if (!erp_core)
1461                 return -ENOMEM;
1462         erp_core->mlxsw_sp = mlxsw_sp;
1463         atcam->erp_core = erp_core;
1464
1465         err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core);
1466         if (err)
1467                 goto err_erp_tables_init;
1468
1469         return 0;
1470
1471 err_erp_tables_init:
1472         kfree(erp_core);
1473         return err;
1474 }
1475
1476 void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
1477                             struct mlxsw_sp_acl_atcam *atcam)
1478 {
1479         mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core);
1480         kfree(atcam->erp_core);
1481 }