root/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_atcam.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp_acl_atcam_is_centry
  2. mlxsw_sp_acl_atcam_region_generic_init
  3. mlxsw_sp_acl_atcam_region_generic_fini
  4. mlxsw_sp_acl_atcam_generic_lkey_id_get
  5. mlxsw_sp_acl_atcam_generic_lkey_id_put
  6. mlxsw_sp_acl_atcam_region_12kb_init
  7. mlxsw_sp_acl_atcam_region_12kb_fini
  8. mlxsw_sp_acl_atcam_lkey_id_create
  9. mlxsw_sp_acl_atcam_lkey_id_destroy
  10. mlxsw_sp_acl_atcam_12kb_lkey_id_get
  11. mlxsw_sp_acl_atcam_12kb_lkey_id_put
  12. mlxsw_sp_acl_atcam_region_associate
  13. mlxsw_sp_acl_atcam_region_type_init
  14. mlxsw_sp_acl_atcam_region_init
  15. mlxsw_sp_acl_atcam_region_fini
  16. mlxsw_sp_acl_atcam_chunk_init
  17. mlxsw_sp_acl_atcam_chunk_fini
  18. mlxsw_sp_acl_atcam_region_entry_insert
  19. mlxsw_sp_acl_atcam_region_entry_remove
  20. mlxsw_sp_acl_atcam_region_entry_action_replace
  21. __mlxsw_sp_acl_atcam_entry_add
  22. __mlxsw_sp_acl_atcam_entry_del
  23. __mlxsw_sp_acl_atcam_entry_action_replace
  24. mlxsw_sp_acl_atcam_entry_add
  25. mlxsw_sp_acl_atcam_entry_del
  26. mlxsw_sp_acl_atcam_entry_action_replace
  27. mlxsw_sp_acl_atcam_init
  28. mlxsw_sp_acl_atcam_fini
  29. mlxsw_sp_acl_atcam_rehash_hints_get
  30. mlxsw_sp_acl_atcam_rehash_hints_put

   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 
  22 struct 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 
  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;
  30         refcount_t refcnt;
  31         u32 id;
  32 };
  33 
  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);
  42 };
  43 
  44 struct mlxsw_sp_acl_atcam_region_generic {
  45         struct mlxsw_sp_acl_atcam_lkey_id dummy_lkey_id;
  46 };
  47 
  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;
  52 };
  53 
  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),
  58 };
  59 
  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),
  64 };
  65 
  66 static bool
  67 mlxsw_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 
  72 static int
  73 mlxsw_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 
  87 static void
  88 mlxsw_sp_acl_atcam_region_generic_fini(struct mlxsw_sp_acl_atcam_region *aregion)
  89 {
  90         kfree(aregion->priv);
  91 }
  92 
  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)
  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 
 103 static void
 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)
 106 {
 107 }
 108 
 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,
 115 };
 116 
 117 static int
 118 mlxsw_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 
 151 err_rhashtable_init:
 152         kfree(region_12kb->used_lkey_id);
 153 err_used_lkey_id_alloc:
 154         kfree(region_12kb);
 155         return err;
 156 }
 157 
 158 static void
 159 mlxsw_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 
 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)
 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 
 202 err_rhashtable_insert:
 203         kfree(lkey_id);
 204 err_lkey_id_alloc:
 205         __clear_bit(id, region_12kb->used_lkey_id);
 206         return ERR_PTR(err);
 207 }
 208 
 209 static void
 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)
 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 
 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)
 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 
 248 static void
 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)
 251 {
 252         if (refcount_dec_and_test(&lkey_id->refcnt))
 253                 mlxsw_sp_acl_atcam_lkey_id_destroy(aregion, lkey_id);
 254 }
 255 
 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,
 262 };
 263 
 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,
 274 };
 275 
 276 int 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 
 292 static void
 293 mlxsw_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 
 316 int
 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,
 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 
 348 err_ctcam_region_init:
 349         mlxsw_sp_acl_erp_region_fini(aregion);
 350 err_erp_region_init:
 351         aregion->ops->fini(aregion);
 352 err_ops_init:
 353         rhashtable_destroy(&aregion->entries_ht);
 354         return err;
 355 }
 356 
 357 void 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 
 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)
 369 {
 370         mlxsw_sp_acl_ctcam_chunk_init(&aregion->cregion, &achunk->cchunk,
 371                                       priority);
 372 }
 373 
 374 void 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 
 379 static int
 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)
 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 
 416 err_ptce3_write:
 417         aregion->ops->lkey_id_put(aregion, lkey_id);
 418         return err;
 419 }
 420 
 421 static void
 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)
 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 
 443 static int
 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)
 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 
 471 static 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 
 535 err_rule_insert:
 536         mlxsw_sp_acl_erp_bf_remove(mlxsw_sp, aregion, erp_mask, aentry);
 537 err_bf_insert:
 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);
 543         return err;
 544 }
 545 
 546 static 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 
 559 static 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 
 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)
 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 
 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)
 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 
 606 int
 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)
 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 
 627 int 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 
 633 void 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 
 639 void *
 640 mlxsw_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 
 645 void mlxsw_sp_acl_atcam_rehash_hints_put(void *hints_priv)
 646 {
 647         mlxsw_sp_acl_erp_rehash_hints_put(hints_priv);
 648 }

/* [<][>][^][v][top][bottom][index][help] */