1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
4 #include <linux/kernel.h>
6 #include <linux/errno.h>
8 #include <linux/refcount.h>
9 #include <linux/rhashtable.h>
10 #define CREATE_TRACE_POINTS
11 #include <trace/events/mlxsw.h>
16 #include "spectrum_acl_tcam.h"
17 #include "core_acl_flex_keys.h"
19 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START 0
20 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END 5
22 struct mlxsw_sp_acl_atcam_lkey_id_ht_key
{
23 char enc_key
[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN
]; /* MSB blocks */
27 struct mlxsw_sp_acl_atcam_lkey_id
{
28 struct rhash_head ht_node
;
29 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key
;
34 struct 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
);
44 struct mlxsw_sp_acl_atcam_region_generic
{
45 struct mlxsw_sp_acl_atcam_lkey_id dummy_lkey_id
;
48 struct mlxsw_sp_acl_atcam_region_12kb
{
49 struct rhashtable lkey_ht
;
50 unsigned int max_lkey_id
;
51 unsigned long *used_lkey_id
;
54 static 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
),
60 static 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
),
67 mlxsw_sp_acl_atcam_is_centry(const struct mlxsw_sp_acl_atcam_entry
*aentry
)
69 return mlxsw_sp_acl_erp_mask_is_ctcam(aentry
->erp_mask
);
73 mlxsw_sp_acl_atcam_region_generic_init(struct mlxsw_sp_acl_atcam_region
*aregion
)
75 struct mlxsw_sp_acl_atcam_region_generic
*region_generic
;
77 region_generic
= kzalloc(sizeof(*region_generic
), GFP_KERNEL
);
81 refcount_set(®ion_generic
->dummy_lkey_id
.refcnt
, 1);
82 aregion
->priv
= region_generic
;
88 mlxsw_sp_acl_atcam_region_generic_fini(struct mlxsw_sp_acl_atcam_region
*aregion
)
93 static struct mlxsw_sp_acl_atcam_lkey_id
*
94 mlxsw_sp_acl_atcam_generic_lkey_id_get(struct mlxsw_sp_acl_atcam_region
*aregion
,
95 char *enc_key
, u8 erp_id
)
97 struct mlxsw_sp_acl_atcam_region_generic
*region_generic
;
99 region_generic
= aregion
->priv
;
100 return ®ion_generic
->dummy_lkey_id
;
104 mlxsw_sp_acl_atcam_generic_lkey_id_put(struct mlxsw_sp_acl_atcam_region
*aregion
,
105 struct mlxsw_sp_acl_atcam_lkey_id
*lkey_id
)
109 static const struct mlxsw_sp_acl_atcam_region_ops
110 mlxsw_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
,
118 mlxsw_sp_acl_atcam_region_12kb_init(struct mlxsw_sp_acl_atcam_region
*aregion
)
120 struct mlxsw_sp
*mlxsw_sp
= aregion
->region
->mlxsw_sp
;
121 struct mlxsw_sp_acl_atcam_region_12kb
*region_12kb
;
126 if (!MLXSW_CORE_RES_VALID(mlxsw_sp
->core
, ACL_MAX_LARGE_KEY_ID
))
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
);
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
) {
138 goto err_used_lkey_id_alloc
;
141 err
= rhashtable_init(®ion_12kb
->lkey_ht
,
142 &mlxsw_sp_acl_atcam_lkey_id_ht_params
);
144 goto err_rhashtable_init
;
146 region_12kb
->max_lkey_id
= max_lkey_id
;
147 aregion
->priv
= region_12kb
;
152 kfree(region_12kb
->used_lkey_id
);
153 err_used_lkey_id_alloc
:
159 mlxsw_sp_acl_atcam_region_12kb_fini(struct mlxsw_sp_acl_atcam_region
*aregion
)
161 struct mlxsw_sp_acl_atcam_region_12kb
*region_12kb
= aregion
->priv
;
163 rhashtable_destroy(®ion_12kb
->lkey_ht
);
164 kfree(region_12kb
->used_lkey_id
);
168 static struct mlxsw_sp_acl_atcam_lkey_id
*
169 mlxsw_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
)
172 struct mlxsw_sp_acl_atcam_region_12kb
*region_12kb
= aregion
->priv
;
173 struct mlxsw_sp_acl_atcam_lkey_id
*lkey_id
;
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
);
182 return ERR_PTR(-ENOBUFS
);
184 lkey_id
= kzalloc(sizeof(*lkey_id
), GFP_KERNEL
);
187 goto err_lkey_id_alloc
;
191 memcpy(&lkey_id
->ht_key
, ht_key
, sizeof(*ht_key
));
192 refcount_set(&lkey_id
->refcnt
, 1);
194 err
= rhashtable_insert_fast(®ion_12kb
->lkey_ht
,
196 mlxsw_sp_acl_atcam_lkey_id_ht_params
);
198 goto err_rhashtable_insert
;
202 err_rhashtable_insert
:
205 __clear_bit(id
, region_12kb
->used_lkey_id
);
210 mlxsw_sp_acl_atcam_lkey_id_destroy(struct mlxsw_sp_acl_atcam_region
*aregion
,
211 struct mlxsw_sp_acl_atcam_lkey_id
*lkey_id
)
213 struct mlxsw_sp_acl_atcam_region_12kb
*region_12kb
= aregion
->priv
;
214 u32 id
= lkey_id
->id
;
216 rhashtable_remove_fast(®ion_12kb
->lkey_ht
, &lkey_id
->ht_node
,
217 mlxsw_sp_acl_atcam_lkey_id_ht_params
);
219 __clear_bit(id
, region_12kb
->used_lkey_id
);
222 static struct mlxsw_sp_acl_atcam_lkey_id
*
223 mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region
*aregion
,
224 char *enc_key
, u8 erp_id
)
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
;
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
);
241 refcount_inc(&lkey_id
->refcnt
);
245 return mlxsw_sp_acl_atcam_lkey_id_create(aregion
, &ht_key
);
249 mlxsw_sp_acl_atcam_12kb_lkey_id_put(struct mlxsw_sp_acl_atcam_region
*aregion
,
250 struct mlxsw_sp_acl_atcam_lkey_id
*lkey_id
)
252 if (refcount_dec_and_test(&lkey_id
->refcnt
))
253 mlxsw_sp_acl_atcam_lkey_id_destroy(aregion
, lkey_id
);
256 static const struct mlxsw_sp_acl_atcam_region_ops
257 mlxsw_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
,
264 static const struct mlxsw_sp_acl_atcam_region_ops
*
265 mlxsw_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
,
276 int mlxsw_sp_acl_atcam_region_associate(struct mlxsw_sp
*mlxsw_sp
,
279 char perar_pl
[MLXSW_REG_PERAR_LEN
];
280 /* For now, just assume that every region has 12 key blocks */
281 u16 hw_region
= region_id
* 3;
284 max_regions
= MLXSW_CORE_RES_GET(mlxsw_sp
->core
, ACL_MAX_REGIONS
);
285 if (hw_region
>= max_regions
)
288 mlxsw_reg_perar_pack(perar_pl
, region_id
, hw_region
);
289 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(perar
), perar_pl
);
293 mlxsw_sp_acl_atcam_region_type_init(struct mlxsw_sp_acl_atcam_region
*aregion
)
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
;
299 /* We already know the blocks count can not exceed the maximum
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
;
310 region_type
= MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB
;
312 aregion
->type
= region_type
;
313 aregion
->ops
= mlxsw_sp_acl_atcam_region_ops_arr
[region_type
];
317 mlxsw_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
,
322 const struct mlxsw_sp_acl_ctcam_region_ops
*ops
)
326 aregion
->region
= region
;
327 aregion
->atcam
= atcam
;
328 mlxsw_sp_acl_atcam_region_type_init(aregion
);
329 INIT_LIST_HEAD(&aregion
->entries_list
);
331 err
= rhashtable_init(&aregion
->entries_ht
,
332 &mlxsw_sp_acl_atcam_entries_ht_params
);
335 err
= aregion
->ops
->init(aregion
);
338 err
= mlxsw_sp_acl_erp_region_init(aregion
, hints_priv
);
340 goto err_erp_region_init
;
341 err
= mlxsw_sp_acl_ctcam_region_init(mlxsw_sp
, &aregion
->cregion
,
344 goto err_ctcam_region_init
;
348 err_ctcam_region_init
:
349 mlxsw_sp_acl_erp_region_fini(aregion
);
351 aregion
->ops
->fini(aregion
);
353 rhashtable_destroy(&aregion
->entries_ht
);
357 void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region
*aregion
)
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
));
366 void 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
)
370 mlxsw_sp_acl_ctcam_chunk_init(&aregion
->cregion
, &achunk
->cchunk
,
374 void mlxsw_sp_acl_atcam_chunk_fini(struct mlxsw_sp_acl_atcam_chunk
*achunk
)
376 mlxsw_sp_acl_ctcam_chunk_fini(&achunk
->cchunk
);
380 mlxsw_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
)
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
;
392 err
= mlxsw_sp_acl_tcam_priority_get(mlxsw_sp
, rulei
, &priority
, true);
396 lkey_id
= aregion
->ops
->lkey_id_get(aregion
, aentry
->enc_key
, erp_id
);
398 return PTR_ERR(lkey_id
);
399 aentry
->lkey_id
= lkey_id
;
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
,
410 err
= mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ptce3
), ptce3_pl
);
412 goto err_ptce3_write
;
417 aregion
->ops
->lkey_id_put(aregion
, lkey_id
);
422 mlxsw_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
)
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
];
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,
439 mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ptce3
), ptce3_pl
);
440 aregion
->ops
->lkey_id_put(aregion
, lkey_id
);
444 mlxsw_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
)
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
;
456 err
= mlxsw_sp_acl_tcam_priority_get(mlxsw_sp
, rulei
, &priority
, true);
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
,
468 return mlxsw_reg_write(mlxsw_sp
->core
, MLXSW_REG(ptce3
), ptce3_pl
);
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
)
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
;
484 mlxsw_afk_encode(afk
, region
->key_info
, &rulei
->values
,
485 aentry
->ht_key
.full_enc_key
, mask
);
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
));
495 /* Compute all needed delta information and clear the delta bits
496 * from the encrypted key.
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
);
506 /* Add rule to the list of A-TCAM rules, assuming this
507 * rule is intended to A-TCAM. In case this rule does
508 * not fit into A-TCAM it will be removed from the list.
510 list_add(&aentry
->list
, &aregion
->entries_list
);
512 /* We can't insert identical rules into the A-TCAM, so fail and
513 * let the rule spill into C-TCAM
515 err
= rhashtable_lookup_insert_fast(&aregion
->entries_ht
,
517 mlxsw_sp_acl_atcam_entries_ht_params
);
519 goto err_rhashtable_insert
;
521 /* Bloom filter must be updated here, before inserting the rule into
524 err
= mlxsw_sp_acl_erp_bf_insert(mlxsw_sp
, aregion
, erp_mask
, aentry
);
528 err
= mlxsw_sp_acl_atcam_region_entry_insert(mlxsw_sp
, aregion
, aentry
,
531 goto err_rule_insert
;
536 mlxsw_sp_acl_erp_bf_remove(mlxsw_sp
, aregion
, erp_mask
, aentry
);
538 rhashtable_remove_fast(&aregion
->entries_ht
, &aentry
->ht_node
,
539 mlxsw_sp_acl_atcam_entries_ht_params
);
540 err_rhashtable_insert
:
541 list_del(&aentry
->list
);
542 mlxsw_sp_acl_erp_mask_put(aregion
, erp_mask
);
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
)
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
);
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
)
565 return mlxsw_sp_acl_atcam_region_entry_action_replace(mlxsw_sp
, aregion
,
569 int 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
)
577 err
= __mlxsw_sp_acl_atcam_entry_add(mlxsw_sp
, aregion
, aentry
, rulei
);
581 /* It is possible we failed to add the rule to the A-TCAM due to
582 * exceeded number of masks. Try to spill into C-TCAM.
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
,
594 void 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
)
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
);
603 __mlxsw_sp_acl_atcam_entry_del(mlxsw_sp
, aregion
, aentry
);
607 mlxsw_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
)
614 if (mlxsw_sp_acl_atcam_is_centry(aentry
))
615 err
= mlxsw_sp_acl_ctcam_entry_action_replace(mlxsw_sp
,
620 err
= __mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp
,
627 int mlxsw_sp_acl_atcam_init(struct mlxsw_sp
*mlxsw_sp
,
628 struct mlxsw_sp_acl_atcam
*atcam
)
630 return mlxsw_sp_acl_erps_init(mlxsw_sp
, atcam
);
633 void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp
*mlxsw_sp
,
634 struct mlxsw_sp_acl_atcam
*atcam
)
636 mlxsw_sp_acl_erps_fini(mlxsw_sp
, atcam
);
640 mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region
*aregion
)
642 return mlxsw_sp_acl_erp_rehash_hints_get(aregion
);
645 void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv
)
647 mlxsw_sp_acl_erp_rehash_hints_put(hints_priv
);