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