1
2
3
4#include <linux/kernel.h>
5#include <linux/err.h>
6#include <linux/errno.h>
7#include <linux/gfp.h>
8#include <linux/refcount.h>
9#include <linux/rhashtable.h>
10#define CREATE_TRACE_POINTS
11#include <trace/events/mlxsw.h>
12
13#include "reg.h"
14#include "core.h"
15#include "spectrum.h"
16#include "spectrum_acl_tcam.h"
17#include "core_acl_flex_keys.h"
18
19#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START 0
20#define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END 5
21
22struct mlxsw_sp_acl_atcam_lkey_id_ht_key {
23 char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN];
24 u8 erp_id;
25};
26
27struct mlxsw_sp_acl_atcam_lkey_id {
28 struct rhash_head ht_node;
29 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key;
30 refcount_t refcnt;
31 u32 id;
32};
33
34struct mlxsw_sp_acl_atcam_region_ops {
35 int (*init)(struct mlxsw_sp_acl_atcam_region *aregion);
36 void (*fini)(struct mlxsw_sp_acl_atcam_region *aregion);
37 struct mlxsw_sp_acl_atcam_lkey_id *
38 (*lkey_id_get)(struct mlxsw_sp_acl_atcam_region *aregion,
39 char *enc_key, u8 erp_id);
40 void (*lkey_id_put)(struct mlxsw_sp_acl_atcam_region *aregion,
41 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id);
42};
43
44struct mlxsw_sp_acl_atcam_region_generic {
45 struct mlxsw_sp_acl_atcam_lkey_id dummy_lkey_id;
46};
47
48struct mlxsw_sp_acl_atcam_region_12kb {
49 struct rhashtable lkey_ht;
50 unsigned int max_lkey_id;
51 unsigned long *used_lkey_id;
52};
53
54static const struct rhashtable_params mlxsw_sp_acl_atcam_lkey_id_ht_params = {
55 .key_len = sizeof(struct mlxsw_sp_acl_atcam_lkey_id_ht_key),
56 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_key),
57 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_node),
58};
59
60static const struct rhashtable_params mlxsw_sp_acl_atcam_entries_ht_params = {
61 .key_len = sizeof(struct mlxsw_sp_acl_atcam_entry_ht_key),
62 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_key),
63 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_node),
64};
65
66static bool
67mlxsw_sp_acl_atcam_is_centry(const struct mlxsw_sp_acl_atcam_entry *aentry)
68{
69 return mlxsw_sp_acl_erp_mask_is_ctcam(aentry->erp_mask);
70}
71
72static int
73mlxsw_sp_acl_atcam_region_generic_init(struct mlxsw_sp_acl_atcam_region *aregion)
74{
75 struct mlxsw_sp_acl_atcam_region_generic *region_generic;
76
77 region_generic = kzalloc(sizeof(*region_generic), GFP_KERNEL);
78 if (!region_generic)
79 return -ENOMEM;
80
81 refcount_set(®ion_generic->dummy_lkey_id.refcnt, 1);
82 aregion->priv = region_generic;
83
84 return 0;
85}
86
87static void
88mlxsw_sp_acl_atcam_region_generic_fini(struct mlxsw_sp_acl_atcam_region *aregion)
89{
90 kfree(aregion->priv);
91}
92
93static struct mlxsw_sp_acl_atcam_lkey_id *
94mlxsw_sp_acl_atcam_generic_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion,
95 char *enc_key, u8 erp_id)
96{
97 struct mlxsw_sp_acl_atcam_region_generic *region_generic;
98
99 region_generic = aregion->priv;
100 return ®ion_generic->dummy_lkey_id;
101}
102
103static void
104mlxsw_sp_acl_atcam_generic_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion,
105 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id)
106{
107}
108
109static const struct mlxsw_sp_acl_atcam_region_ops
110mlxsw_sp_acl_atcam_region_generic_ops = {
111 .init = mlxsw_sp_acl_atcam_region_generic_init,
112 .fini = mlxsw_sp_acl_atcam_region_generic_fini,
113 .lkey_id_get = mlxsw_sp_acl_atcam_generic_lkey_id_get,
114 .lkey_id_put = mlxsw_sp_acl_atcam_generic_lkey_id_put,
115};
116
117static int
118mlxsw_sp_acl_atcam_region_12kb_init(struct mlxsw_sp_acl_atcam_region *aregion)
119{
120 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
121 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb;
122 size_t alloc_size;
123 u64 max_lkey_id;
124 int err;
125
126 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID))
127 return -EIO;
128
129 max_lkey_id = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID);
130 region_12kb = kzalloc(sizeof(*region_12kb), GFP_KERNEL);
131 if (!region_12kb)
132 return -ENOMEM;
133
134 alloc_size = BITS_TO_LONGS(max_lkey_id) * sizeof(unsigned long);
135 region_12kb->used_lkey_id = kzalloc(alloc_size, GFP_KERNEL);
136 if (!region_12kb->used_lkey_id) {
137 err = -ENOMEM;
138 goto err_used_lkey_id_alloc;
139 }
140
141 err = rhashtable_init(®ion_12kb->lkey_ht,
142 &mlxsw_sp_acl_atcam_lkey_id_ht_params);
143 if (err)
144 goto err_rhashtable_init;
145
146 region_12kb->max_lkey_id = max_lkey_id;
147 aregion->priv = region_12kb;
148
149 return 0;
150
151err_rhashtable_init:
152 kfree(region_12kb->used_lkey_id);
153err_used_lkey_id_alloc:
154 kfree(region_12kb);
155 return err;
156}
157
158static void
159mlxsw_sp_acl_atcam_region_12kb_fini(struct mlxsw_sp_acl_atcam_region *aregion)
160{
161 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
162
163 rhashtable_destroy(®ion_12kb->lkey_ht);
164 kfree(region_12kb->used_lkey_id);
165 kfree(region_12kb);
166}
167
168static struct mlxsw_sp_acl_atcam_lkey_id *
169mlxsw_sp_acl_atcam_lkey_id_create(struct mlxsw_sp_acl_atcam_region *aregion,
170 struct mlxsw_sp_acl_atcam_lkey_id_ht_key *ht_key)
171{
172 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
173 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
174 u32 id;
175 int err;
176
177 id = find_first_zero_bit(region_12kb->used_lkey_id,
178 region_12kb->max_lkey_id);
179 if (id < region_12kb->max_lkey_id)
180 __set_bit(id, region_12kb->used_lkey_id);
181 else
182 return ERR_PTR(-ENOBUFS);
183
184 lkey_id = kzalloc(sizeof(*lkey_id), GFP_KERNEL);
185 if (!lkey_id) {
186 err = -ENOMEM;
187 goto err_lkey_id_alloc;
188 }
189
190 lkey_id->id = id;
191 memcpy(&lkey_id->ht_key, ht_key, sizeof(*ht_key));
192 refcount_set(&lkey_id->refcnt, 1);
193
194 err = rhashtable_insert_fast(®ion_12kb->lkey_ht,
195 &lkey_id->ht_node,
196 mlxsw_sp_acl_atcam_lkey_id_ht_params);
197 if (err)
198 goto err_rhashtable_insert;
199
200 return lkey_id;
201
202err_rhashtable_insert:
203 kfree(lkey_id);
204err_lkey_id_alloc:
205 __clear_bit(id, region_12kb->used_lkey_id);
206 return ERR_PTR(err);
207}
208
209static void
210mlxsw_sp_acl_atcam_lkey_id_destroy(struct mlxsw_sp_acl_atcam_region *aregion,
211 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id)
212{
213 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
214 u32 id = lkey_id->id;
215
216 rhashtable_remove_fast(®ion_12kb->lkey_ht, &lkey_id->ht_node,
217 mlxsw_sp_acl_atcam_lkey_id_ht_params);
218 kfree(lkey_id);
219 __clear_bit(id, region_12kb->used_lkey_id);
220}
221
222static struct mlxsw_sp_acl_atcam_lkey_id *
223mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion,
224 char *enc_key, u8 erp_id)
225{
226 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
227 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
228 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key = {{ 0 } };
229 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
230 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
231 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
232
233 memcpy(ht_key.enc_key, enc_key, sizeof(ht_key.enc_key));
234 mlxsw_afk_clear(afk, ht_key.enc_key,
235 MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START,
236 MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END);
237 ht_key.erp_id = erp_id;
238 lkey_id = rhashtable_lookup_fast(®ion_12kb->lkey_ht, &ht_key,
239 mlxsw_sp_acl_atcam_lkey_id_ht_params);
240 if (lkey_id) {
241 refcount_inc(&lkey_id->refcnt);
242 return lkey_id;
243 }
244
245 return mlxsw_sp_acl_atcam_lkey_id_create(aregion, &ht_key);
246}
247
248static void
249mlxsw_sp_acl_atcam_12kb_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion,
250 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id)
251{
252 if (refcount_dec_and_test(&lkey_id->refcnt))
253 mlxsw_sp_acl_atcam_lkey_id_destroy(aregion, lkey_id);
254}
255
256static const struct mlxsw_sp_acl_atcam_region_ops
257mlxsw_sp_acl_atcam_region_12kb_ops = {
258 .init = mlxsw_sp_acl_atcam_region_12kb_init,
259 .fini = mlxsw_sp_acl_atcam_region_12kb_fini,
260 .lkey_id_get = mlxsw_sp_acl_atcam_12kb_lkey_id_get,
261 .lkey_id_put = mlxsw_sp_acl_atcam_12kb_lkey_id_put,
262};
263
264static const struct mlxsw_sp_acl_atcam_region_ops *
265mlxsw_sp_acl_atcam_region_ops_arr[] = {
266 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] =
267 &mlxsw_sp_acl_atcam_region_generic_ops,
268 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] =
269 &mlxsw_sp_acl_atcam_region_generic_ops,
270 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] =
271 &mlxsw_sp_acl_atcam_region_generic_ops,
272 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] =
273 &mlxsw_sp_acl_atcam_region_12kb_ops,
274};
275
276int mlxsw_sp_acl_atcam_region_associate(struct mlxsw_sp *mlxsw_sp,
277 u16 region_id)
278{
279 char perar_pl[MLXSW_REG_PERAR_LEN];
280
281 u16 hw_region = region_id * 3;
282 u64 max_regions;
283
284 max_regions = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_REGIONS);
285 if (hw_region >= max_regions)
286 return -ENOBUFS;
287
288 mlxsw_reg_perar_pack(perar_pl, region_id, hw_region);
289 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perar), perar_pl);
290}
291
292static void
293mlxsw_sp_acl_atcam_region_type_init(struct mlxsw_sp_acl_atcam_region *aregion)
294{
295 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
296 enum mlxsw_sp_acl_atcam_region_type region_type;
297 unsigned int blocks_count;
298
299
300
301
302 blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info);
303 if (blocks_count <= 2)
304 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB;
305 else if (blocks_count <= 4)
306 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB;
307 else if (blocks_count <= 8)
308 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB;
309 else
310 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB;
311
312 aregion->type = region_type;
313 aregion->ops = mlxsw_sp_acl_atcam_region_ops_arr[region_type];
314}
315
316int
317mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
318 struct mlxsw_sp_acl_atcam *atcam,
319 struct mlxsw_sp_acl_atcam_region *aregion,
320 struct mlxsw_sp_acl_tcam_region *region,
321 void *hints_priv,
322 const struct mlxsw_sp_acl_ctcam_region_ops *ops)
323{
324 int err;
325
326 aregion->region = region;
327 aregion->atcam = atcam;
328 mlxsw_sp_acl_atcam_region_type_init(aregion);
329 INIT_LIST_HEAD(&aregion->entries_list);
330
331 err = rhashtable_init(&aregion->entries_ht,
332 &mlxsw_sp_acl_atcam_entries_ht_params);
333 if (err)
334 return err;
335 err = aregion->ops->init(aregion);
336 if (err)
337 goto err_ops_init;
338 err = mlxsw_sp_acl_erp_region_init(aregion, hints_priv);
339 if (err)
340 goto err_erp_region_init;
341 err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &aregion->cregion,
342 region, ops);
343 if (err)
344 goto err_ctcam_region_init;
345
346 return 0;
347
348err_ctcam_region_init:
349 mlxsw_sp_acl_erp_region_fini(aregion);
350err_erp_region_init:
351 aregion->ops->fini(aregion);
352err_ops_init:
353 rhashtable_destroy(&aregion->entries_ht);
354 return err;
355}
356
357void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
358{
359 mlxsw_sp_acl_ctcam_region_fini(&aregion->cregion);
360 mlxsw_sp_acl_erp_region_fini(aregion);
361 aregion->ops->fini(aregion);
362 rhashtable_destroy(&aregion->entries_ht);
363 WARN_ON(!list_empty(&aregion->entries_list));
364}
365
366void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion,
367 struct mlxsw_sp_acl_atcam_chunk *achunk,
368 unsigned int priority)
369{
370 mlxsw_sp_acl_ctcam_chunk_init(&aregion->cregion, &achunk->cchunk,
371 priority);
372}
373
374void mlxsw_sp_acl_atcam_chunk_fini(struct mlxsw_sp_acl_atcam_chunk *achunk)
375{
376 mlxsw_sp_acl_ctcam_chunk_fini(&achunk->cchunk);
377}
378
379static int
380mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
381 struct mlxsw_sp_acl_atcam_region *aregion,
382 struct mlxsw_sp_acl_atcam_entry *aentry,
383 struct mlxsw_sp_acl_rule_info *rulei)
384{
385 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
386 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
387 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
388 char ptce3_pl[MLXSW_REG_PTCE3_LEN];
389 u32 kvdl_index, priority;
390 int err;
391
392 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true);
393 if (err)
394 return err;
395
396 lkey_id = aregion->ops->lkey_id_get(aregion, aentry->enc_key, erp_id);
397 if (IS_ERR(lkey_id))
398 return PTR_ERR(lkey_id);
399 aentry->lkey_id = lkey_id;
400
401 kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block);
402 mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE,
403 priority, region->tcam_region_info,
404 aentry->enc_key, erp_id,
405 aentry->delta_info.start,
406 aentry->delta_info.mask,
407 aentry->delta_info.value,
408 refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
409 kvdl_index);
410 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
411 if (err)
412 goto err_ptce3_write;
413
414 return 0;
415
416err_ptce3_write:
417 aregion->ops->lkey_id_put(aregion, lkey_id);
418 return err;
419}
420
421static void
422mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
423 struct mlxsw_sp_acl_atcam_region *aregion,
424 struct mlxsw_sp_acl_atcam_entry *aentry)
425{
426 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id;
427 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
428 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
429 char ptce3_pl[MLXSW_REG_PTCE3_LEN];
430
431 mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0,
432 region->tcam_region_info,
433 aentry->enc_key, erp_id,
434 aentry->delta_info.start,
435 aentry->delta_info.mask,
436 aentry->delta_info.value,
437 refcount_read(&lkey_id->refcnt) != 1,
438 lkey_id->id, 0);
439 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
440 aregion->ops->lkey_id_put(aregion, lkey_id);
441}
442
443static int
444mlxsw_sp_acl_atcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
445 struct mlxsw_sp_acl_atcam_region *aregion,
446 struct mlxsw_sp_acl_atcam_entry *aentry,
447 struct mlxsw_sp_acl_rule_info *rulei)
448{
449 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id;
450 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
451 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
452 char ptce3_pl[MLXSW_REG_PTCE3_LEN];
453 u32 kvdl_index, priority;
454 int err;
455
456 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true);
457 if (err)
458 return err;
459 kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block);
460 mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_UPDATE,
461 priority, region->tcam_region_info,
462 aentry->enc_key, erp_id,
463 aentry->delta_info.start,
464 aentry->delta_info.mask,
465 aentry->delta_info.value,
466 refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
467 kvdl_index);
468 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
469}
470
471static int
472__mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
473 struct mlxsw_sp_acl_atcam_region *aregion,
474 struct mlxsw_sp_acl_atcam_entry *aentry,
475 struct mlxsw_sp_acl_rule_info *rulei)
476{
477 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
478 char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
479 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
480 const struct mlxsw_sp_acl_erp_delta *delta;
481 struct mlxsw_sp_acl_erp_mask *erp_mask;
482 int err;
483
484 mlxsw_afk_encode(afk, region->key_info, &rulei->values,
485 aentry->ht_key.full_enc_key, mask);
486
487 erp_mask = mlxsw_sp_acl_erp_mask_get(aregion, mask, false);
488 if (IS_ERR(erp_mask))
489 return PTR_ERR(erp_mask);
490 aentry->erp_mask = erp_mask;
491 aentry->ht_key.erp_id = mlxsw_sp_acl_erp_mask_erp_id(erp_mask);
492 memcpy(aentry->enc_key, aentry->ht_key.full_enc_key,
493 sizeof(aentry->enc_key));
494
495
496
497
498 delta = mlxsw_sp_acl_erp_delta(aentry->erp_mask);
499 aentry->delta_info.start = mlxsw_sp_acl_erp_delta_start(delta);
500 aentry->delta_info.mask = mlxsw_sp_acl_erp_delta_mask(delta);
501 aentry->delta_info.value =
502 mlxsw_sp_acl_erp_delta_value(delta,
503 aentry->ht_key.full_enc_key);
504 mlxsw_sp_acl_erp_delta_clear(delta, aentry->enc_key);
505
506
507
508
509
510 list_add(&aentry->list, &aregion->entries_list);
511
512
513
514
515 err = rhashtable_lookup_insert_fast(&aregion->entries_ht,
516 &aentry->ht_node,
517 mlxsw_sp_acl_atcam_entries_ht_params);
518 if (err)
519 goto err_rhashtable_insert;
520
521
522
523
524 err = mlxsw_sp_acl_erp_bf_insert(mlxsw_sp, aregion, erp_mask, aentry);
525 if (err)
526 goto err_bf_insert;
527
528 err = mlxsw_sp_acl_atcam_region_entry_insert(mlxsw_sp, aregion, aentry,
529 rulei);
530 if (err)
531 goto err_rule_insert;
532
533 return 0;
534
535err_rule_insert:
536 mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, erp_mask, aentry);
537err_bf_insert:
538 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
539 mlxsw_sp_acl_atcam_entries_ht_params);
540err_rhashtable_insert:
541 list_del(&aentry->list);
542 mlxsw_sp_acl_erp_mask_put(aregion, erp_mask);
543 return err;
544}
545
546static void
547__mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
548 struct mlxsw_sp_acl_atcam_region *aregion,
549 struct mlxsw_sp_acl_atcam_entry *aentry)
550{
551 mlxsw_sp_acl_atcam_region_entry_remove(mlxsw_sp, aregion, aentry);
552 mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, aentry->erp_mask, aentry);
553 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
554 mlxsw_sp_acl_atcam_entries_ht_params);
555 list_del(&aentry->list);
556 mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask);
557}
558
559static int
560__mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
561 struct mlxsw_sp_acl_atcam_region *aregion,
562 struct mlxsw_sp_acl_atcam_entry *aentry,
563 struct mlxsw_sp_acl_rule_info *rulei)
564{
565 return mlxsw_sp_acl_atcam_region_entry_action_replace(mlxsw_sp, aregion,
566 aentry, rulei);
567}
568
569int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
570 struct mlxsw_sp_acl_atcam_region *aregion,
571 struct mlxsw_sp_acl_atcam_chunk *achunk,
572 struct mlxsw_sp_acl_atcam_entry *aentry,
573 struct mlxsw_sp_acl_rule_info *rulei)
574{
575 int err;
576
577 err = __mlxsw_sp_acl_atcam_entry_add(mlxsw_sp, aregion, aentry, rulei);
578 if (!err)
579 return 0;
580
581
582
583
584 trace_mlxsw_sp_acl_atcam_entry_add_ctcam_spill(mlxsw_sp, aregion);
585 err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &aregion->cregion,
586 &achunk->cchunk, &aentry->centry,
587 rulei, true);
588 if (!err)
589 return 0;
590
591 return err;
592}
593
594void mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
595 struct mlxsw_sp_acl_atcam_region *aregion,
596 struct mlxsw_sp_acl_atcam_chunk *achunk,
597 struct mlxsw_sp_acl_atcam_entry *aentry)
598{
599 if (mlxsw_sp_acl_atcam_is_centry(aentry))
600 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &aregion->cregion,
601 &achunk->cchunk, &aentry->centry);
602 else
603 __mlxsw_sp_acl_atcam_entry_del(mlxsw_sp, aregion, aentry);
604}
605
606int
607mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
608 struct mlxsw_sp_acl_atcam_region *aregion,
609 struct mlxsw_sp_acl_atcam_entry *aentry,
610 struct mlxsw_sp_acl_rule_info *rulei)
611{
612 int err;
613
614 if (mlxsw_sp_acl_atcam_is_centry(aentry))
615 err = mlxsw_sp_acl_ctcam_entry_action_replace(mlxsw_sp,
616 &aregion->cregion,
617 &aentry->centry,
618 rulei);
619 else
620 err = __mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp,
621 aregion, aentry,
622 rulei);
623
624 return err;
625}
626
627int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp,
628 struct mlxsw_sp_acl_atcam *atcam)
629{
630 return mlxsw_sp_acl_erps_init(mlxsw_sp, atcam);
631}
632
633void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
634 struct mlxsw_sp_acl_atcam *atcam)
635{
636 mlxsw_sp_acl_erps_fini(mlxsw_sp, atcam);
637}
638
639void *
640mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
641{
642 return mlxsw_sp_acl_erp_rehash_hints_get(aregion);
643}
644
645void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv)
646{
647 mlxsw_sp_acl_erp_rehash_hints_put(hints_priv);
648}
649