Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
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]; /* MSB blocks */
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(&region_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 &region_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(&region_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(&region_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(&region_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(&region_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(&region_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     /* For now, just assume that every region has 12 key blocks */
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     /* We already know the blocks count can not exceed the maximum
0298      * blocks count.
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     /* Compute all needed delta information and clear the delta bits
0494      * from the encrypted key.
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     /* Add rule to the list of A-TCAM rules, assuming this
0505      * rule is intended to A-TCAM. In case this rule does
0506      * not fit into A-TCAM it will be removed from the list.
0507      */
0508     list_add(&aentry->list, &aregion->entries_list);
0509 
0510     /* We can't insert identical rules into the A-TCAM, so fail and
0511      * let the rule spill into C-TCAM
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     /* Bloom filter must be updated here, before inserting the rule into
0520      * the A-TCAM.
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     /* It is possible we failed to add the rule to the A-TCAM due to
0580      * exceeded number of masks. Try to spill into C-TCAM.
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 }