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