0001
0002
0003
0004 #include <linux/kernel.h>
0005 #include <linux/err.h>
0006 #include <linux/errno.h>
0007 #include <linux/gfp.h>
0008 #include <linux/refcount.h>
0009 #include <linux/rhashtable.h>
0010 #define CREATE_TRACE_POINTS
0011 #include <trace/events/mlxsw.h>
0012
0013 #include "reg.h"
0014 #include "core.h"
0015 #include "spectrum.h"
0016 #include "spectrum_acl_tcam.h"
0017 #include "core_acl_flex_keys.h"
0018
0019 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START 0
0020 #define MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END 5
0021
0022 struct mlxsw_sp_acl_atcam_lkey_id_ht_key {
0023 char enc_key[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN];
0024 u8 erp_id;
0025 };
0026
0027 struct mlxsw_sp_acl_atcam_lkey_id {
0028 struct rhash_head ht_node;
0029 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key;
0030 refcount_t refcnt;
0031 u32 id;
0032 };
0033
0034 struct mlxsw_sp_acl_atcam_region_ops {
0035 int (*init)(struct mlxsw_sp_acl_atcam_region *aregion);
0036 void (*fini)(struct mlxsw_sp_acl_atcam_region *aregion);
0037 struct mlxsw_sp_acl_atcam_lkey_id *
0038 (*lkey_id_get)(struct mlxsw_sp_acl_atcam_region *aregion,
0039 char *enc_key, u8 erp_id);
0040 void (*lkey_id_put)(struct mlxsw_sp_acl_atcam_region *aregion,
0041 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id);
0042 };
0043
0044 struct mlxsw_sp_acl_atcam_region_generic {
0045 struct mlxsw_sp_acl_atcam_lkey_id dummy_lkey_id;
0046 };
0047
0048 struct mlxsw_sp_acl_atcam_region_12kb {
0049 struct rhashtable lkey_ht;
0050 unsigned int max_lkey_id;
0051 unsigned long *used_lkey_id;
0052 };
0053
0054 static const struct rhashtable_params mlxsw_sp_acl_atcam_lkey_id_ht_params = {
0055 .key_len = sizeof(struct mlxsw_sp_acl_atcam_lkey_id_ht_key),
0056 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_key),
0057 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_lkey_id, ht_node),
0058 };
0059
0060 static const struct rhashtable_params mlxsw_sp_acl_atcam_entries_ht_params = {
0061 .key_len = sizeof(struct mlxsw_sp_acl_atcam_entry_ht_key),
0062 .key_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_key),
0063 .head_offset = offsetof(struct mlxsw_sp_acl_atcam_entry, ht_node),
0064 };
0065
0066 static bool
0067 mlxsw_sp_acl_atcam_is_centry(const struct mlxsw_sp_acl_atcam_entry *aentry)
0068 {
0069 return mlxsw_sp_acl_erp_mask_is_ctcam(aentry->erp_mask);
0070 }
0071
0072 static int
0073 mlxsw_sp_acl_atcam_region_generic_init(struct mlxsw_sp_acl_atcam_region *aregion)
0074 {
0075 struct mlxsw_sp_acl_atcam_region_generic *region_generic;
0076
0077 region_generic = kzalloc(sizeof(*region_generic), GFP_KERNEL);
0078 if (!region_generic)
0079 return -ENOMEM;
0080
0081 refcount_set(®ion_generic->dummy_lkey_id.refcnt, 1);
0082 aregion->priv = region_generic;
0083
0084 return 0;
0085 }
0086
0087 static void
0088 mlxsw_sp_acl_atcam_region_generic_fini(struct mlxsw_sp_acl_atcam_region *aregion)
0089 {
0090 kfree(aregion->priv);
0091 }
0092
0093 static struct mlxsw_sp_acl_atcam_lkey_id *
0094 mlxsw_sp_acl_atcam_generic_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion,
0095 char *enc_key, u8 erp_id)
0096 {
0097 struct mlxsw_sp_acl_atcam_region_generic *region_generic;
0098
0099 region_generic = aregion->priv;
0100 return ®ion_generic->dummy_lkey_id;
0101 }
0102
0103 static void
0104 mlxsw_sp_acl_atcam_generic_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion,
0105 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id)
0106 {
0107 }
0108
0109 static const struct mlxsw_sp_acl_atcam_region_ops
0110 mlxsw_sp_acl_atcam_region_generic_ops = {
0111 .init = mlxsw_sp_acl_atcam_region_generic_init,
0112 .fini = mlxsw_sp_acl_atcam_region_generic_fini,
0113 .lkey_id_get = mlxsw_sp_acl_atcam_generic_lkey_id_get,
0114 .lkey_id_put = mlxsw_sp_acl_atcam_generic_lkey_id_put,
0115 };
0116
0117 static int
0118 mlxsw_sp_acl_atcam_region_12kb_init(struct mlxsw_sp_acl_atcam_region *aregion)
0119 {
0120 struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
0121 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb;
0122 u64 max_lkey_id;
0123 int err;
0124
0125 if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID))
0126 return -EIO;
0127
0128 max_lkey_id = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_LARGE_KEY_ID);
0129 region_12kb = kzalloc(sizeof(*region_12kb), GFP_KERNEL);
0130 if (!region_12kb)
0131 return -ENOMEM;
0132
0133 region_12kb->used_lkey_id = bitmap_zalloc(max_lkey_id, GFP_KERNEL);
0134 if (!region_12kb->used_lkey_id) {
0135 err = -ENOMEM;
0136 goto err_used_lkey_id_alloc;
0137 }
0138
0139 err = rhashtable_init(®ion_12kb->lkey_ht,
0140 &mlxsw_sp_acl_atcam_lkey_id_ht_params);
0141 if (err)
0142 goto err_rhashtable_init;
0143
0144 region_12kb->max_lkey_id = max_lkey_id;
0145 aregion->priv = region_12kb;
0146
0147 return 0;
0148
0149 err_rhashtable_init:
0150 bitmap_free(region_12kb->used_lkey_id);
0151 err_used_lkey_id_alloc:
0152 kfree(region_12kb);
0153 return err;
0154 }
0155
0156 static void
0157 mlxsw_sp_acl_atcam_region_12kb_fini(struct mlxsw_sp_acl_atcam_region *aregion)
0158 {
0159 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
0160
0161 rhashtable_destroy(®ion_12kb->lkey_ht);
0162 bitmap_free(region_12kb->used_lkey_id);
0163 kfree(region_12kb);
0164 }
0165
0166 static struct mlxsw_sp_acl_atcam_lkey_id *
0167 mlxsw_sp_acl_atcam_lkey_id_create(struct mlxsw_sp_acl_atcam_region *aregion,
0168 struct mlxsw_sp_acl_atcam_lkey_id_ht_key *ht_key)
0169 {
0170 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
0171 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
0172 u32 id;
0173 int err;
0174
0175 id = find_first_zero_bit(region_12kb->used_lkey_id,
0176 region_12kb->max_lkey_id);
0177 if (id < region_12kb->max_lkey_id)
0178 __set_bit(id, region_12kb->used_lkey_id);
0179 else
0180 return ERR_PTR(-ENOBUFS);
0181
0182 lkey_id = kzalloc(sizeof(*lkey_id), GFP_KERNEL);
0183 if (!lkey_id) {
0184 err = -ENOMEM;
0185 goto err_lkey_id_alloc;
0186 }
0187
0188 lkey_id->id = id;
0189 memcpy(&lkey_id->ht_key, ht_key, sizeof(*ht_key));
0190 refcount_set(&lkey_id->refcnt, 1);
0191
0192 err = rhashtable_insert_fast(®ion_12kb->lkey_ht,
0193 &lkey_id->ht_node,
0194 mlxsw_sp_acl_atcam_lkey_id_ht_params);
0195 if (err)
0196 goto err_rhashtable_insert;
0197
0198 return lkey_id;
0199
0200 err_rhashtable_insert:
0201 kfree(lkey_id);
0202 err_lkey_id_alloc:
0203 __clear_bit(id, region_12kb->used_lkey_id);
0204 return ERR_PTR(err);
0205 }
0206
0207 static void
0208 mlxsw_sp_acl_atcam_lkey_id_destroy(struct mlxsw_sp_acl_atcam_region *aregion,
0209 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id)
0210 {
0211 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
0212 u32 id = lkey_id->id;
0213
0214 rhashtable_remove_fast(®ion_12kb->lkey_ht, &lkey_id->ht_node,
0215 mlxsw_sp_acl_atcam_lkey_id_ht_params);
0216 kfree(lkey_id);
0217 __clear_bit(id, region_12kb->used_lkey_id);
0218 }
0219
0220 static struct mlxsw_sp_acl_atcam_lkey_id *
0221 mlxsw_sp_acl_atcam_12kb_lkey_id_get(struct mlxsw_sp_acl_atcam_region *aregion,
0222 char *enc_key, u8 erp_id)
0223 {
0224 struct mlxsw_sp_acl_atcam_region_12kb *region_12kb = aregion->priv;
0225 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
0226 struct mlxsw_sp_acl_atcam_lkey_id_ht_key ht_key = {{ 0 } };
0227 struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
0228 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
0229 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
0230
0231 memcpy(ht_key.enc_key, enc_key, sizeof(ht_key.enc_key));
0232 mlxsw_afk_clear(afk, ht_key.enc_key,
0233 MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_START,
0234 MLXSW_SP_ACL_ATCAM_LKEY_ID_BLOCK_CLEAR_END);
0235 ht_key.erp_id = erp_id;
0236 lkey_id = rhashtable_lookup_fast(®ion_12kb->lkey_ht, &ht_key,
0237 mlxsw_sp_acl_atcam_lkey_id_ht_params);
0238 if (lkey_id) {
0239 refcount_inc(&lkey_id->refcnt);
0240 return lkey_id;
0241 }
0242
0243 return mlxsw_sp_acl_atcam_lkey_id_create(aregion, &ht_key);
0244 }
0245
0246 static void
0247 mlxsw_sp_acl_atcam_12kb_lkey_id_put(struct mlxsw_sp_acl_atcam_region *aregion,
0248 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id)
0249 {
0250 if (refcount_dec_and_test(&lkey_id->refcnt))
0251 mlxsw_sp_acl_atcam_lkey_id_destroy(aregion, lkey_id);
0252 }
0253
0254 static const struct mlxsw_sp_acl_atcam_region_ops
0255 mlxsw_sp_acl_atcam_region_12kb_ops = {
0256 .init = mlxsw_sp_acl_atcam_region_12kb_init,
0257 .fini = mlxsw_sp_acl_atcam_region_12kb_fini,
0258 .lkey_id_get = mlxsw_sp_acl_atcam_12kb_lkey_id_get,
0259 .lkey_id_put = mlxsw_sp_acl_atcam_12kb_lkey_id_put,
0260 };
0261
0262 static const struct mlxsw_sp_acl_atcam_region_ops *
0263 mlxsw_sp_acl_atcam_region_ops_arr[] = {
0264 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] =
0265 &mlxsw_sp_acl_atcam_region_generic_ops,
0266 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] =
0267 &mlxsw_sp_acl_atcam_region_generic_ops,
0268 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] =
0269 &mlxsw_sp_acl_atcam_region_generic_ops,
0270 [MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] =
0271 &mlxsw_sp_acl_atcam_region_12kb_ops,
0272 };
0273
0274 int mlxsw_sp_acl_atcam_region_associate(struct mlxsw_sp *mlxsw_sp,
0275 u16 region_id)
0276 {
0277 char perar_pl[MLXSW_REG_PERAR_LEN];
0278
0279 u16 hw_region = region_id * 3;
0280 u64 max_regions;
0281
0282 max_regions = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_REGIONS);
0283 if (hw_region >= max_regions)
0284 return -ENOBUFS;
0285
0286 mlxsw_reg_perar_pack(perar_pl, region_id, hw_region);
0287 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perar), perar_pl);
0288 }
0289
0290 static void
0291 mlxsw_sp_acl_atcam_region_type_init(struct mlxsw_sp_acl_atcam_region *aregion)
0292 {
0293 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
0294 enum mlxsw_sp_acl_atcam_region_type region_type;
0295 unsigned int blocks_count;
0296
0297
0298
0299
0300 blocks_count = mlxsw_afk_key_info_blocks_count_get(region->key_info);
0301 if (blocks_count <= 2)
0302 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB;
0303 else if (blocks_count <= 4)
0304 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB;
0305 else if (blocks_count <= 8)
0306 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB;
0307 else
0308 region_type = MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB;
0309
0310 aregion->type = region_type;
0311 aregion->ops = mlxsw_sp_acl_atcam_region_ops_arr[region_type];
0312 }
0313
0314 int
0315 mlxsw_sp_acl_atcam_region_init(struct mlxsw_sp *mlxsw_sp,
0316 struct mlxsw_sp_acl_atcam *atcam,
0317 struct mlxsw_sp_acl_atcam_region *aregion,
0318 struct mlxsw_sp_acl_tcam_region *region,
0319 void *hints_priv,
0320 const struct mlxsw_sp_acl_ctcam_region_ops *ops)
0321 {
0322 int err;
0323
0324 aregion->region = region;
0325 aregion->atcam = atcam;
0326 mlxsw_sp_acl_atcam_region_type_init(aregion);
0327 INIT_LIST_HEAD(&aregion->entries_list);
0328
0329 err = rhashtable_init(&aregion->entries_ht,
0330 &mlxsw_sp_acl_atcam_entries_ht_params);
0331 if (err)
0332 return err;
0333 err = aregion->ops->init(aregion);
0334 if (err)
0335 goto err_ops_init;
0336 err = mlxsw_sp_acl_erp_region_init(aregion, hints_priv);
0337 if (err)
0338 goto err_erp_region_init;
0339 err = mlxsw_sp_acl_ctcam_region_init(mlxsw_sp, &aregion->cregion,
0340 region, ops);
0341 if (err)
0342 goto err_ctcam_region_init;
0343
0344 return 0;
0345
0346 err_ctcam_region_init:
0347 mlxsw_sp_acl_erp_region_fini(aregion);
0348 err_erp_region_init:
0349 aregion->ops->fini(aregion);
0350 err_ops_init:
0351 rhashtable_destroy(&aregion->entries_ht);
0352 return err;
0353 }
0354
0355 void mlxsw_sp_acl_atcam_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
0356 {
0357 mlxsw_sp_acl_ctcam_region_fini(&aregion->cregion);
0358 mlxsw_sp_acl_erp_region_fini(aregion);
0359 aregion->ops->fini(aregion);
0360 rhashtable_destroy(&aregion->entries_ht);
0361 WARN_ON(!list_empty(&aregion->entries_list));
0362 }
0363
0364 void mlxsw_sp_acl_atcam_chunk_init(struct mlxsw_sp_acl_atcam_region *aregion,
0365 struct mlxsw_sp_acl_atcam_chunk *achunk,
0366 unsigned int priority)
0367 {
0368 mlxsw_sp_acl_ctcam_chunk_init(&aregion->cregion, &achunk->cchunk,
0369 priority);
0370 }
0371
0372 void mlxsw_sp_acl_atcam_chunk_fini(struct mlxsw_sp_acl_atcam_chunk *achunk)
0373 {
0374 mlxsw_sp_acl_ctcam_chunk_fini(&achunk->cchunk);
0375 }
0376
0377 static int
0378 mlxsw_sp_acl_atcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
0379 struct mlxsw_sp_acl_atcam_region *aregion,
0380 struct mlxsw_sp_acl_atcam_entry *aentry,
0381 struct mlxsw_sp_acl_rule_info *rulei)
0382 {
0383 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
0384 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
0385 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id;
0386 char ptce3_pl[MLXSW_REG_PTCE3_LEN];
0387 u32 kvdl_index, priority;
0388 int err;
0389
0390 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true);
0391 if (err)
0392 return err;
0393
0394 lkey_id = aregion->ops->lkey_id_get(aregion, aentry->enc_key, erp_id);
0395 if (IS_ERR(lkey_id))
0396 return PTR_ERR(lkey_id);
0397 aentry->lkey_id = lkey_id;
0398
0399 kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block);
0400 mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_WRITE,
0401 priority, region->tcam_region_info,
0402 aentry->enc_key, erp_id,
0403 aentry->delta_info.start,
0404 aentry->delta_info.mask,
0405 aentry->delta_info.value,
0406 refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
0407 kvdl_index);
0408 err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
0409 if (err)
0410 goto err_ptce3_write;
0411
0412 return 0;
0413
0414 err_ptce3_write:
0415 aregion->ops->lkey_id_put(aregion, lkey_id);
0416 return err;
0417 }
0418
0419 static void
0420 mlxsw_sp_acl_atcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
0421 struct mlxsw_sp_acl_atcam_region *aregion,
0422 struct mlxsw_sp_acl_atcam_entry *aentry)
0423 {
0424 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id;
0425 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
0426 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
0427 char ptce3_pl[MLXSW_REG_PTCE3_LEN];
0428
0429 mlxsw_reg_ptce3_pack(ptce3_pl, false, MLXSW_REG_PTCE3_OP_WRITE_WRITE, 0,
0430 region->tcam_region_info,
0431 aentry->enc_key, erp_id,
0432 aentry->delta_info.start,
0433 aentry->delta_info.mask,
0434 aentry->delta_info.value,
0435 refcount_read(&lkey_id->refcnt) != 1,
0436 lkey_id->id, 0);
0437 mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
0438 aregion->ops->lkey_id_put(aregion, lkey_id);
0439 }
0440
0441 static int
0442 mlxsw_sp_acl_atcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
0443 struct mlxsw_sp_acl_atcam_region *aregion,
0444 struct mlxsw_sp_acl_atcam_entry *aentry,
0445 struct mlxsw_sp_acl_rule_info *rulei)
0446 {
0447 struct mlxsw_sp_acl_atcam_lkey_id *lkey_id = aentry->lkey_id;
0448 u8 erp_id = mlxsw_sp_acl_erp_mask_erp_id(aentry->erp_mask);
0449 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
0450 char ptce3_pl[MLXSW_REG_PTCE3_LEN];
0451 u32 kvdl_index, priority;
0452 int err;
0453
0454 err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority, true);
0455 if (err)
0456 return err;
0457 kvdl_index = mlxsw_afa_block_first_kvdl_index(rulei->act_block);
0458 mlxsw_reg_ptce3_pack(ptce3_pl, true, MLXSW_REG_PTCE3_OP_WRITE_UPDATE,
0459 priority, region->tcam_region_info,
0460 aentry->enc_key, erp_id,
0461 aentry->delta_info.start,
0462 aentry->delta_info.mask,
0463 aentry->delta_info.value,
0464 refcount_read(&lkey_id->refcnt) != 1, lkey_id->id,
0465 kvdl_index);
0466 return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce3), ptce3_pl);
0467 }
0468
0469 static int
0470 __mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
0471 struct mlxsw_sp_acl_atcam_region *aregion,
0472 struct mlxsw_sp_acl_atcam_entry *aentry,
0473 struct mlxsw_sp_acl_rule_info *rulei)
0474 {
0475 struct mlxsw_sp_acl_tcam_region *region = aregion->region;
0476 char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
0477 struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
0478 const struct mlxsw_sp_acl_erp_delta *delta;
0479 struct mlxsw_sp_acl_erp_mask *erp_mask;
0480 int err;
0481
0482 mlxsw_afk_encode(afk, region->key_info, &rulei->values,
0483 aentry->ht_key.full_enc_key, mask);
0484
0485 erp_mask = mlxsw_sp_acl_erp_mask_get(aregion, mask, false);
0486 if (IS_ERR(erp_mask))
0487 return PTR_ERR(erp_mask);
0488 aentry->erp_mask = erp_mask;
0489 aentry->ht_key.erp_id = mlxsw_sp_acl_erp_mask_erp_id(erp_mask);
0490 memcpy(aentry->enc_key, aentry->ht_key.full_enc_key,
0491 sizeof(aentry->enc_key));
0492
0493
0494
0495
0496 delta = mlxsw_sp_acl_erp_delta(aentry->erp_mask);
0497 aentry->delta_info.start = mlxsw_sp_acl_erp_delta_start(delta);
0498 aentry->delta_info.mask = mlxsw_sp_acl_erp_delta_mask(delta);
0499 aentry->delta_info.value =
0500 mlxsw_sp_acl_erp_delta_value(delta,
0501 aentry->ht_key.full_enc_key);
0502 mlxsw_sp_acl_erp_delta_clear(delta, aentry->enc_key);
0503
0504
0505
0506
0507
0508 list_add(&aentry->list, &aregion->entries_list);
0509
0510
0511
0512
0513 err = rhashtable_lookup_insert_fast(&aregion->entries_ht,
0514 &aentry->ht_node,
0515 mlxsw_sp_acl_atcam_entries_ht_params);
0516 if (err)
0517 goto err_rhashtable_insert;
0518
0519
0520
0521
0522 err = mlxsw_sp_acl_erp_bf_insert(mlxsw_sp, aregion, erp_mask, aentry);
0523 if (err)
0524 goto err_bf_insert;
0525
0526 err = mlxsw_sp_acl_atcam_region_entry_insert(mlxsw_sp, aregion, aentry,
0527 rulei);
0528 if (err)
0529 goto err_rule_insert;
0530
0531 return 0;
0532
0533 err_rule_insert:
0534 mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, erp_mask, aentry);
0535 err_bf_insert:
0536 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
0537 mlxsw_sp_acl_atcam_entries_ht_params);
0538 err_rhashtable_insert:
0539 list_del(&aentry->list);
0540 mlxsw_sp_acl_erp_mask_put(aregion, erp_mask);
0541 return err;
0542 }
0543
0544 static void
0545 __mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
0546 struct mlxsw_sp_acl_atcam_region *aregion,
0547 struct mlxsw_sp_acl_atcam_entry *aentry)
0548 {
0549 mlxsw_sp_acl_atcam_region_entry_remove(mlxsw_sp, aregion, aentry);
0550 mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, aentry->erp_mask, aentry);
0551 rhashtable_remove_fast(&aregion->entries_ht, &aentry->ht_node,
0552 mlxsw_sp_acl_atcam_entries_ht_params);
0553 list_del(&aentry->list);
0554 mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask);
0555 }
0556
0557 static int
0558 __mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
0559 struct mlxsw_sp_acl_atcam_region *aregion,
0560 struct mlxsw_sp_acl_atcam_entry *aentry,
0561 struct mlxsw_sp_acl_rule_info *rulei)
0562 {
0563 return mlxsw_sp_acl_atcam_region_entry_action_replace(mlxsw_sp, aregion,
0564 aentry, rulei);
0565 }
0566
0567 int mlxsw_sp_acl_atcam_entry_add(struct mlxsw_sp *mlxsw_sp,
0568 struct mlxsw_sp_acl_atcam_region *aregion,
0569 struct mlxsw_sp_acl_atcam_chunk *achunk,
0570 struct mlxsw_sp_acl_atcam_entry *aentry,
0571 struct mlxsw_sp_acl_rule_info *rulei)
0572 {
0573 int err;
0574
0575 err = __mlxsw_sp_acl_atcam_entry_add(mlxsw_sp, aregion, aentry, rulei);
0576 if (!err)
0577 return 0;
0578
0579
0580
0581
0582 trace_mlxsw_sp_acl_atcam_entry_add_ctcam_spill(mlxsw_sp, aregion);
0583 err = mlxsw_sp_acl_ctcam_entry_add(mlxsw_sp, &aregion->cregion,
0584 &achunk->cchunk, &aentry->centry,
0585 rulei, true);
0586 if (!err)
0587 return 0;
0588
0589 return err;
0590 }
0591
0592 void mlxsw_sp_acl_atcam_entry_del(struct mlxsw_sp *mlxsw_sp,
0593 struct mlxsw_sp_acl_atcam_region *aregion,
0594 struct mlxsw_sp_acl_atcam_chunk *achunk,
0595 struct mlxsw_sp_acl_atcam_entry *aentry)
0596 {
0597 if (mlxsw_sp_acl_atcam_is_centry(aentry))
0598 mlxsw_sp_acl_ctcam_entry_del(mlxsw_sp, &aregion->cregion,
0599 &achunk->cchunk, &aentry->centry);
0600 else
0601 __mlxsw_sp_acl_atcam_entry_del(mlxsw_sp, aregion, aentry);
0602 }
0603
0604 int
0605 mlxsw_sp_acl_atcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
0606 struct mlxsw_sp_acl_atcam_region *aregion,
0607 struct mlxsw_sp_acl_atcam_entry *aentry,
0608 struct mlxsw_sp_acl_rule_info *rulei)
0609 {
0610 int err;
0611
0612 if (mlxsw_sp_acl_atcam_is_centry(aentry))
0613 err = mlxsw_sp_acl_ctcam_entry_action_replace(mlxsw_sp,
0614 &aregion->cregion,
0615 &aentry->centry,
0616 rulei);
0617 else
0618 err = __mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp,
0619 aregion, aentry,
0620 rulei);
0621
0622 return err;
0623 }
0624
0625 int mlxsw_sp_acl_atcam_init(struct mlxsw_sp *mlxsw_sp,
0626 struct mlxsw_sp_acl_atcam *atcam)
0627 {
0628 return mlxsw_sp_acl_erps_init(mlxsw_sp, atcam);
0629 }
0630
0631 void mlxsw_sp_acl_atcam_fini(struct mlxsw_sp *mlxsw_sp,
0632 struct mlxsw_sp_acl_atcam *atcam)
0633 {
0634 mlxsw_sp_acl_erps_fini(mlxsw_sp, atcam);
0635 }
0636
0637 void *
0638 mlxsw_sp_acl_atcam_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
0639 {
0640 return mlxsw_sp_acl_erp_rehash_hints_get(aregion);
0641 }
0642
0643 void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv)
0644 {
0645 mlxsw_sp_acl_erp_rehash_hints_put(hints_priv);
0646 }