linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2018 Mellanox Technologies. All rights reserved */
   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]; /* MSB blocks */
  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(&region_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 &region_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(&region_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(&region_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(&region_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(&region_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(&region_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        /* For now, just assume that every region has 12 key blocks */
 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        /* We already know the blocks count can not exceed the maximum
 300         * blocks count.
 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        /* Compute all needed delta information and clear the delta bits
 496         * from the encrypted key.
 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        /* 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.
 509         */
 510        list_add(&aentry->list, &aregion->entries_list);
 511
 512        /* We can't insert identical rules into the A-TCAM, so fail and
 513         * let the rule spill into C-TCAM
 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        /* Bloom filter must be updated here, before inserting the rule into
 522         * the A-TCAM.
 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        /* 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.
 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