linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_erp.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/bitmap.h>
   5#include <linux/errno.h>
   6#include <linux/genalloc.h>
   7#include <linux/gfp.h>
   8#include <linux/kernel.h>
   9#include <linux/list.h>
  10#include <linux/mutex.h>
  11#include <linux/objagg.h>
  12#include <linux/rtnetlink.h>
  13#include <linux/slab.h>
  14
  15#include "core.h"
  16#include "reg.h"
  17#include "spectrum.h"
  18#include "spectrum_acl_tcam.h"
  19
  20/* gen_pool_alloc() returns 0 when allocation fails, so use an offset */
  21#define MLXSW_SP_ACL_ERP_GENALLOC_OFFSET 0x100
  22#define MLXSW_SP_ACL_ERP_MAX_PER_REGION 16
  23
  24struct mlxsw_sp_acl_erp_core {
  25        unsigned int erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_MAX + 1];
  26        struct gen_pool *erp_tables;
  27        struct mlxsw_sp *mlxsw_sp;
  28        struct mlxsw_sp_acl_bf *bf;
  29        unsigned int num_erp_banks;
  30};
  31
  32struct mlxsw_sp_acl_erp_key {
  33        char mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN];
  34#define __MASK_LEN 0x38
  35#define __MASK_IDX(i) (__MASK_LEN - (i) - 1)
  36        bool ctcam;
  37};
  38
  39struct mlxsw_sp_acl_erp {
  40        struct mlxsw_sp_acl_erp_key key;
  41        u8 id;
  42        u8 index;
  43        DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
  44        struct list_head list;
  45        struct mlxsw_sp_acl_erp_table *erp_table;
  46};
  47
  48struct mlxsw_sp_acl_erp_master_mask {
  49        DECLARE_BITMAP(bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
  50        unsigned int count[MLXSW_SP_ACL_TCAM_MASK_LEN];
  51};
  52
  53struct mlxsw_sp_acl_erp_table {
  54        struct mlxsw_sp_acl_erp_master_mask master_mask;
  55        DECLARE_BITMAP(erp_id_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
  56        DECLARE_BITMAP(erp_index_bitmap, MLXSW_SP_ACL_ERP_MAX_PER_REGION);
  57        struct list_head atcam_erps_list;
  58        struct mlxsw_sp_acl_erp_core *erp_core;
  59        struct mlxsw_sp_acl_atcam_region *aregion;
  60        const struct mlxsw_sp_acl_erp_table_ops *ops;
  61        unsigned long base_index;
  62        unsigned int num_atcam_erps;
  63        unsigned int num_max_atcam_erps;
  64        unsigned int num_ctcam_erps;
  65        unsigned int num_deltas;
  66        struct objagg *objagg;
  67        struct mutex objagg_lock; /* guards objagg manipulation */
  68};
  69
  70struct mlxsw_sp_acl_erp_table_ops {
  71        struct mlxsw_sp_acl_erp *
  72                (*erp_create)(struct mlxsw_sp_acl_erp_table *erp_table,
  73                              struct mlxsw_sp_acl_erp_key *key);
  74        void (*erp_destroy)(struct mlxsw_sp_acl_erp_table *erp_table,
  75                            struct mlxsw_sp_acl_erp *erp);
  76};
  77
  78static struct mlxsw_sp_acl_erp *
  79mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
  80                             struct mlxsw_sp_acl_erp_key *key);
  81static void
  82mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
  83                              struct mlxsw_sp_acl_erp *erp);
  84static struct mlxsw_sp_acl_erp *
  85mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
  86                                    struct mlxsw_sp_acl_erp_key *key);
  87static void
  88mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
  89                                     struct mlxsw_sp_acl_erp *erp);
  90static struct mlxsw_sp_acl_erp *
  91mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
  92                                   struct mlxsw_sp_acl_erp_key *key);
  93static void
  94mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
  95                                    struct mlxsw_sp_acl_erp *erp);
  96static void
  97mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
  98                                 struct mlxsw_sp_acl_erp *erp);
  99
 100static const struct mlxsw_sp_acl_erp_table_ops erp_multiple_masks_ops = {
 101        .erp_create = mlxsw_sp_acl_erp_mask_create,
 102        .erp_destroy = mlxsw_sp_acl_erp_mask_destroy,
 103};
 104
 105static const struct mlxsw_sp_acl_erp_table_ops erp_two_masks_ops = {
 106        .erp_create = mlxsw_sp_acl_erp_mask_create,
 107        .erp_destroy = mlxsw_sp_acl_erp_second_mask_destroy,
 108};
 109
 110static const struct mlxsw_sp_acl_erp_table_ops erp_single_mask_ops = {
 111        .erp_create = mlxsw_sp_acl_erp_second_mask_create,
 112        .erp_destroy = mlxsw_sp_acl_erp_first_mask_destroy,
 113};
 114
 115static const struct mlxsw_sp_acl_erp_table_ops erp_no_mask_ops = {
 116        .erp_create = mlxsw_sp_acl_erp_first_mask_create,
 117        .erp_destroy = mlxsw_sp_acl_erp_no_mask_destroy,
 118};
 119
 120static bool
 121mlxsw_sp_acl_erp_table_is_used(const struct mlxsw_sp_acl_erp_table *erp_table)
 122{
 123        return erp_table->ops != &erp_single_mask_ops &&
 124               erp_table->ops != &erp_no_mask_ops;
 125}
 126
 127static unsigned int
 128mlxsw_sp_acl_erp_bank_get(const struct mlxsw_sp_acl_erp *erp)
 129{
 130        return erp->index % erp->erp_table->erp_core->num_erp_banks;
 131}
 132
 133static unsigned int
 134mlxsw_sp_acl_erp_table_entry_size(const struct mlxsw_sp_acl_erp_table *erp_table)
 135{
 136        struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
 137        struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
 138
 139        return erp_core->erpt_entries_size[aregion->type];
 140}
 141
 142static int mlxsw_sp_acl_erp_id_get(struct mlxsw_sp_acl_erp_table *erp_table,
 143                                   u8 *p_id)
 144{
 145        u8 id;
 146
 147        id = find_first_zero_bit(erp_table->erp_id_bitmap,
 148                                 MLXSW_SP_ACL_ERP_MAX_PER_REGION);
 149        if (id < MLXSW_SP_ACL_ERP_MAX_PER_REGION) {
 150                __set_bit(id, erp_table->erp_id_bitmap);
 151                *p_id = id;
 152                return 0;
 153        }
 154
 155        return -ENOBUFS;
 156}
 157
 158static void mlxsw_sp_acl_erp_id_put(struct mlxsw_sp_acl_erp_table *erp_table,
 159                                    u8 id)
 160{
 161        __clear_bit(id, erp_table->erp_id_bitmap);
 162}
 163
 164static void
 165mlxsw_sp_acl_erp_master_mask_bit_set(unsigned long bit,
 166                                     struct mlxsw_sp_acl_erp_master_mask *mask)
 167{
 168        if (mask->count[bit]++ == 0)
 169                __set_bit(bit, mask->bitmap);
 170}
 171
 172static void
 173mlxsw_sp_acl_erp_master_mask_bit_clear(unsigned long bit,
 174                                       struct mlxsw_sp_acl_erp_master_mask *mask)
 175{
 176        if (--mask->count[bit] == 0)
 177                __clear_bit(bit, mask->bitmap);
 178}
 179
 180static int
 181mlxsw_sp_acl_erp_master_mask_update(struct mlxsw_sp_acl_erp_table *erp_table)
 182{
 183        struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
 184        struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
 185        char percr_pl[MLXSW_REG_PERCR_LEN];
 186        char *master_mask;
 187
 188        mlxsw_reg_percr_pack(percr_pl, region->id);
 189        master_mask = mlxsw_reg_percr_master_mask_data(percr_pl);
 190        bitmap_to_arr32((u32 *) master_mask, erp_table->master_mask.bitmap,
 191                        MLXSW_SP_ACL_TCAM_MASK_LEN);
 192
 193        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
 194}
 195
 196static int
 197mlxsw_sp_acl_erp_master_mask_set(struct mlxsw_sp_acl_erp_table *erp_table,
 198                                 struct mlxsw_sp_acl_erp_key *key)
 199{
 200        DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
 201        unsigned long bit;
 202        int err;
 203
 204        bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
 205                          MLXSW_SP_ACL_TCAM_MASK_LEN);
 206        for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
 207                mlxsw_sp_acl_erp_master_mask_bit_set(bit,
 208                                                     &erp_table->master_mask);
 209
 210        err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
 211        if (err)
 212                goto err_master_mask_update;
 213
 214        return 0;
 215
 216err_master_mask_update:
 217        for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
 218                mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
 219                                                       &erp_table->master_mask);
 220        return err;
 221}
 222
 223static int
 224mlxsw_sp_acl_erp_master_mask_clear(struct mlxsw_sp_acl_erp_table *erp_table,
 225                                   struct mlxsw_sp_acl_erp_key *key)
 226{
 227        DECLARE_BITMAP(mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN);
 228        unsigned long bit;
 229        int err;
 230
 231        bitmap_from_arr32(mask_bitmap, (u32 *) key->mask,
 232                          MLXSW_SP_ACL_TCAM_MASK_LEN);
 233        for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
 234                mlxsw_sp_acl_erp_master_mask_bit_clear(bit,
 235                                                       &erp_table->master_mask);
 236
 237        err = mlxsw_sp_acl_erp_master_mask_update(erp_table);
 238        if (err)
 239                goto err_master_mask_update;
 240
 241        return 0;
 242
 243err_master_mask_update:
 244        for_each_set_bit(bit, mask_bitmap, MLXSW_SP_ACL_TCAM_MASK_LEN)
 245                mlxsw_sp_acl_erp_master_mask_bit_set(bit,
 246                                                     &erp_table->master_mask);
 247        return err;
 248}
 249
 250static struct mlxsw_sp_acl_erp *
 251mlxsw_sp_acl_erp_generic_create(struct mlxsw_sp_acl_erp_table *erp_table,
 252                                struct mlxsw_sp_acl_erp_key *key)
 253{
 254        struct mlxsw_sp_acl_erp *erp;
 255        int err;
 256
 257        erp = kzalloc(sizeof(*erp), GFP_KERNEL);
 258        if (!erp)
 259                return ERR_PTR(-ENOMEM);
 260
 261        err = mlxsw_sp_acl_erp_id_get(erp_table, &erp->id);
 262        if (err)
 263                goto err_erp_id_get;
 264
 265        memcpy(&erp->key, key, sizeof(*key));
 266        list_add(&erp->list, &erp_table->atcam_erps_list);
 267        erp_table->num_atcam_erps++;
 268        erp->erp_table = erp_table;
 269
 270        err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
 271        if (err)
 272                goto err_master_mask_set;
 273
 274        return erp;
 275
 276err_master_mask_set:
 277        erp_table->num_atcam_erps--;
 278        list_del(&erp->list);
 279        mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
 280err_erp_id_get:
 281        kfree(erp);
 282        return ERR_PTR(err);
 283}
 284
 285static void
 286mlxsw_sp_acl_erp_generic_destroy(struct mlxsw_sp_acl_erp *erp)
 287{
 288        struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
 289
 290        mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
 291        erp_table->num_atcam_erps--;
 292        list_del(&erp->list);
 293        mlxsw_sp_acl_erp_id_put(erp_table, erp->id);
 294        kfree(erp);
 295}
 296
 297static int
 298mlxsw_sp_acl_erp_table_alloc(struct mlxsw_sp_acl_erp_core *erp_core,
 299                             unsigned int num_erps,
 300                             enum mlxsw_sp_acl_atcam_region_type region_type,
 301                             unsigned long *p_index)
 302{
 303        unsigned int num_rows, entry_size;
 304
 305        /* We only allow allocations of entire rows */
 306        if (num_erps % erp_core->num_erp_banks != 0)
 307                return -EINVAL;
 308
 309        entry_size = erp_core->erpt_entries_size[region_type];
 310        num_rows = num_erps / erp_core->num_erp_banks;
 311
 312        *p_index = gen_pool_alloc(erp_core->erp_tables, num_rows * entry_size);
 313        if (*p_index == 0)
 314                return -ENOBUFS;
 315        *p_index -= MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
 316
 317        return 0;
 318}
 319
 320static void
 321mlxsw_sp_acl_erp_table_free(struct mlxsw_sp_acl_erp_core *erp_core,
 322                            unsigned int num_erps,
 323                            enum mlxsw_sp_acl_atcam_region_type region_type,
 324                            unsigned long index)
 325{
 326        unsigned long base_index;
 327        unsigned int entry_size;
 328        size_t size;
 329
 330        entry_size = erp_core->erpt_entries_size[region_type];
 331        base_index = index + MLXSW_SP_ACL_ERP_GENALLOC_OFFSET;
 332        size = num_erps / erp_core->num_erp_banks * entry_size;
 333        gen_pool_free(erp_core->erp_tables, base_index, size);
 334}
 335
 336static struct mlxsw_sp_acl_erp *
 337mlxsw_sp_acl_erp_table_master_rp(struct mlxsw_sp_acl_erp_table *erp_table)
 338{
 339        if (!list_is_singular(&erp_table->atcam_erps_list))
 340                return NULL;
 341
 342        return list_first_entry(&erp_table->atcam_erps_list,
 343                                struct mlxsw_sp_acl_erp, list);
 344}
 345
 346static int mlxsw_sp_acl_erp_index_get(struct mlxsw_sp_acl_erp_table *erp_table,
 347                                      u8 *p_index)
 348{
 349        u8 index;
 350
 351        index = find_first_zero_bit(erp_table->erp_index_bitmap,
 352                                    erp_table->num_max_atcam_erps);
 353        if (index < erp_table->num_max_atcam_erps) {
 354                __set_bit(index, erp_table->erp_index_bitmap);
 355                *p_index = index;
 356                return 0;
 357        }
 358
 359        return -ENOBUFS;
 360}
 361
 362static void mlxsw_sp_acl_erp_index_put(struct mlxsw_sp_acl_erp_table *erp_table,
 363                                       u8 index)
 364{
 365        __clear_bit(index, erp_table->erp_index_bitmap);
 366}
 367
 368static void
 369mlxsw_sp_acl_erp_table_locate(const struct mlxsw_sp_acl_erp_table *erp_table,
 370                              const struct mlxsw_sp_acl_erp *erp,
 371                              u8 *p_erpt_bank, u8 *p_erpt_index)
 372{
 373        unsigned int entry_size = mlxsw_sp_acl_erp_table_entry_size(erp_table);
 374        struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
 375        unsigned int row;
 376
 377        *p_erpt_bank = erp->index % erp_core->num_erp_banks;
 378        row = erp->index / erp_core->num_erp_banks;
 379        *p_erpt_index = erp_table->base_index + row * entry_size;
 380}
 381
 382static int
 383mlxsw_sp_acl_erp_table_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
 384                               struct mlxsw_sp_acl_erp *erp)
 385{
 386        struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
 387        enum mlxsw_reg_perpt_key_size key_size;
 388        char perpt_pl[MLXSW_REG_PERPT_LEN];
 389        u8 erpt_bank, erpt_index;
 390
 391        mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
 392        key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
 393        mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
 394                             0, erp_table->base_index, erp->index,
 395                             erp->key.mask);
 396        mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
 397                                        MLXSW_SP_ACL_ERP_MAX_PER_REGION);
 398        mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, true);
 399        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
 400}
 401
 402static void mlxsw_sp_acl_erp_table_erp_del(struct mlxsw_sp_acl_erp *erp)
 403{
 404        char empty_mask[MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN] = { 0 };
 405        struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
 406        struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
 407        enum mlxsw_reg_perpt_key_size key_size;
 408        char perpt_pl[MLXSW_REG_PERPT_LEN];
 409        u8 erpt_bank, erpt_index;
 410
 411        mlxsw_sp_acl_erp_table_locate(erp_table, erp, &erpt_bank, &erpt_index);
 412        key_size = (enum mlxsw_reg_perpt_key_size) erp_table->aregion->type;
 413        mlxsw_reg_perpt_pack(perpt_pl, erpt_bank, erpt_index, key_size, erp->id,
 414                             0, erp_table->base_index, erp->index, empty_mask);
 415        mlxsw_reg_perpt_erp_vector_pack(perpt_pl, erp_table->erp_index_bitmap,
 416                                        MLXSW_SP_ACL_ERP_MAX_PER_REGION);
 417        mlxsw_reg_perpt_erp_vector_set(perpt_pl, erp->index, false);
 418        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(perpt), perpt_pl);
 419}
 420
 421static int
 422mlxsw_sp_acl_erp_table_enable(struct mlxsw_sp_acl_erp_table *erp_table,
 423                              bool ctcam_le)
 424{
 425        struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
 426        struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
 427        char pererp_pl[MLXSW_REG_PERERP_LEN];
 428
 429        mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
 430                              erp_table->base_index, 0);
 431        mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
 432                                         MLXSW_SP_ACL_ERP_MAX_PER_REGION);
 433
 434        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
 435}
 436
 437static void
 438mlxsw_sp_acl_erp_table_disable(struct mlxsw_sp_acl_erp_table *erp_table)
 439{
 440        struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
 441        struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
 442        char pererp_pl[MLXSW_REG_PERERP_LEN];
 443        struct mlxsw_sp_acl_erp *master_rp;
 444
 445        master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
 446        /* It is possible we do not have a master RP when we disable the
 447         * table when there are no rules in the A-TCAM and the last C-TCAM
 448         * rule is deleted
 449         */
 450        mlxsw_reg_pererp_pack(pererp_pl, region->id, false, false, 0, 0,
 451                              master_rp ? master_rp->id : 0);
 452        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
 453}
 454
 455static int
 456mlxsw_sp_acl_erp_table_relocate(struct mlxsw_sp_acl_erp_table *erp_table)
 457{
 458        struct mlxsw_sp_acl_erp *erp;
 459        int err;
 460
 461        list_for_each_entry(erp, &erp_table->atcam_erps_list, list) {
 462                err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
 463                if (err)
 464                        goto err_table_erp_add;
 465        }
 466
 467        return 0;
 468
 469err_table_erp_add:
 470        list_for_each_entry_continue_reverse(erp, &erp_table->atcam_erps_list,
 471                                             list)
 472                mlxsw_sp_acl_erp_table_erp_del(erp);
 473        return err;
 474}
 475
 476static int
 477mlxsw_sp_acl_erp_table_expand(struct mlxsw_sp_acl_erp_table *erp_table)
 478{
 479        unsigned int num_erps, old_num_erps = erp_table->num_max_atcam_erps;
 480        struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
 481        unsigned long old_base_index = erp_table->base_index;
 482        bool ctcam_le = erp_table->num_ctcam_erps > 0;
 483        int err;
 484
 485        if (erp_table->num_atcam_erps < erp_table->num_max_atcam_erps)
 486                return 0;
 487
 488        if (erp_table->num_max_atcam_erps == MLXSW_SP_ACL_ERP_MAX_PER_REGION)
 489                return -ENOBUFS;
 490
 491        num_erps = old_num_erps + erp_core->num_erp_banks;
 492        err = mlxsw_sp_acl_erp_table_alloc(erp_core, num_erps,
 493                                           erp_table->aregion->type,
 494                                           &erp_table->base_index);
 495        if (err)
 496                return err;
 497        erp_table->num_max_atcam_erps = num_erps;
 498
 499        err = mlxsw_sp_acl_erp_table_relocate(erp_table);
 500        if (err)
 501                goto err_table_relocate;
 502
 503        err = mlxsw_sp_acl_erp_table_enable(erp_table, ctcam_le);
 504        if (err)
 505                goto err_table_enable;
 506
 507        mlxsw_sp_acl_erp_table_free(erp_core, old_num_erps,
 508                                    erp_table->aregion->type, old_base_index);
 509
 510        return 0;
 511
 512err_table_enable:
 513err_table_relocate:
 514        erp_table->num_max_atcam_erps = old_num_erps;
 515        mlxsw_sp_acl_erp_table_free(erp_core, num_erps,
 516                                    erp_table->aregion->type,
 517                                    erp_table->base_index);
 518        erp_table->base_index = old_base_index;
 519        return err;
 520}
 521
 522static int
 523mlxsw_acl_erp_table_bf_add(struct mlxsw_sp_acl_erp_table *erp_table,
 524                           struct mlxsw_sp_acl_erp *erp)
 525{
 526        struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
 527        unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
 528        struct mlxsw_sp_acl_atcam_entry *aentry;
 529        int err;
 530
 531        list_for_each_entry(aentry, &aregion->entries_list, list) {
 532                err = mlxsw_sp_acl_bf_entry_add(aregion->region->mlxsw_sp,
 533                                                erp_table->erp_core->bf,
 534                                                aregion, erp_bank, aentry);
 535                if (err)
 536                        goto bf_entry_add_err;
 537        }
 538
 539        return 0;
 540
 541bf_entry_add_err:
 542        list_for_each_entry_continue_reverse(aentry, &aregion->entries_list,
 543                                             list)
 544                mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
 545                                          erp_table->erp_core->bf,
 546                                          aregion, erp_bank, aentry);
 547        return err;
 548}
 549
 550static void
 551mlxsw_acl_erp_table_bf_del(struct mlxsw_sp_acl_erp_table *erp_table,
 552                           struct mlxsw_sp_acl_erp *erp)
 553{
 554        struct mlxsw_sp_acl_atcam_region *aregion = erp_table->aregion;
 555        unsigned int erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
 556        struct mlxsw_sp_acl_atcam_entry *aentry;
 557
 558        list_for_each_entry_reverse(aentry, &aregion->entries_list, list)
 559                mlxsw_sp_acl_bf_entry_del(aregion->region->mlxsw_sp,
 560                                          erp_table->erp_core->bf,
 561                                          aregion, erp_bank, aentry);
 562}
 563
 564static int
 565mlxsw_sp_acl_erp_region_table_trans(struct mlxsw_sp_acl_erp_table *erp_table)
 566{
 567        struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
 568        struct mlxsw_sp_acl_erp *master_rp;
 569        int err;
 570
 571        /* Initially, allocate a single eRP row. Expand later as needed */
 572        err = mlxsw_sp_acl_erp_table_alloc(erp_core, erp_core->num_erp_banks,
 573                                           erp_table->aregion->type,
 574                                           &erp_table->base_index);
 575        if (err)
 576                return err;
 577        erp_table->num_max_atcam_erps = erp_core->num_erp_banks;
 578
 579        /* Transition the sole RP currently configured (the master RP)
 580         * to the eRP table
 581         */
 582        master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
 583        if (!master_rp) {
 584                err = -EINVAL;
 585                goto err_table_master_rp;
 586        }
 587
 588        /* Make sure the master RP is using a valid index, as
 589         * only a single eRP row is currently allocated.
 590         */
 591        master_rp->index = 0;
 592        __set_bit(master_rp->index, erp_table->erp_index_bitmap);
 593
 594        err = mlxsw_sp_acl_erp_table_erp_add(erp_table, master_rp);
 595        if (err)
 596                goto err_table_master_rp_add;
 597
 598        /* Update Bloom filter before enabling eRP table, as rules
 599         * on the master RP were not set to Bloom filter up to this
 600         * point.
 601         */
 602        err = mlxsw_acl_erp_table_bf_add(erp_table, master_rp);
 603        if (err)
 604                goto err_table_bf_add;
 605
 606        err = mlxsw_sp_acl_erp_table_enable(erp_table, false);
 607        if (err)
 608                goto err_table_enable;
 609
 610        return 0;
 611
 612err_table_enable:
 613        mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
 614err_table_bf_add:
 615        mlxsw_sp_acl_erp_table_erp_del(master_rp);
 616err_table_master_rp_add:
 617        __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
 618err_table_master_rp:
 619        mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
 620                                    erp_table->aregion->type,
 621                                    erp_table->base_index);
 622        return err;
 623}
 624
 625static void
 626mlxsw_sp_acl_erp_region_master_mask_trans(struct mlxsw_sp_acl_erp_table *erp_table)
 627{
 628        struct mlxsw_sp_acl_erp_core *erp_core = erp_table->erp_core;
 629        struct mlxsw_sp_acl_erp *master_rp;
 630
 631        mlxsw_sp_acl_erp_table_disable(erp_table);
 632        master_rp = mlxsw_sp_acl_erp_table_master_rp(erp_table);
 633        if (!master_rp)
 634                return;
 635        mlxsw_acl_erp_table_bf_del(erp_table, master_rp);
 636        mlxsw_sp_acl_erp_table_erp_del(master_rp);
 637        __clear_bit(master_rp->index, erp_table->erp_index_bitmap);
 638        mlxsw_sp_acl_erp_table_free(erp_core, erp_table->num_max_atcam_erps,
 639                                    erp_table->aregion->type,
 640                                    erp_table->base_index);
 641}
 642
 643static int
 644mlxsw_sp_acl_erp_region_erp_add(struct mlxsw_sp_acl_erp_table *erp_table,
 645                                struct mlxsw_sp_acl_erp *erp)
 646{
 647        struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
 648        struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
 649        bool ctcam_le = erp_table->num_ctcam_erps > 0;
 650        char pererp_pl[MLXSW_REG_PERERP_LEN];
 651
 652        mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
 653                              erp_table->base_index, 0);
 654        mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
 655                                         MLXSW_SP_ACL_ERP_MAX_PER_REGION);
 656        mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, true);
 657
 658        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
 659}
 660
 661static void mlxsw_sp_acl_erp_region_erp_del(struct mlxsw_sp_acl_erp *erp)
 662{
 663        struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
 664        struct mlxsw_sp_acl_tcam_region *region = erp_table->aregion->region;
 665        struct mlxsw_sp *mlxsw_sp = erp_table->erp_core->mlxsw_sp;
 666        bool ctcam_le = erp_table->num_ctcam_erps > 0;
 667        char pererp_pl[MLXSW_REG_PERERP_LEN];
 668
 669        mlxsw_reg_pererp_pack(pererp_pl, region->id, ctcam_le, true, 0,
 670                              erp_table->base_index, 0);
 671        mlxsw_reg_pererp_erp_vector_pack(pererp_pl, erp_table->erp_index_bitmap,
 672                                         MLXSW_SP_ACL_ERP_MAX_PER_REGION);
 673        mlxsw_reg_pererp_erpt_vector_set(pererp_pl, erp->index, false);
 674
 675        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
 676}
 677
 678static int
 679mlxsw_sp_acl_erp_region_ctcam_enable(struct mlxsw_sp_acl_erp_table *erp_table)
 680{
 681        /* No need to re-enable lookup in the C-TCAM */
 682        if (erp_table->num_ctcam_erps > 1)
 683                return 0;
 684
 685        return mlxsw_sp_acl_erp_table_enable(erp_table, true);
 686}
 687
 688static void
 689mlxsw_sp_acl_erp_region_ctcam_disable(struct mlxsw_sp_acl_erp_table *erp_table)
 690{
 691        /* Only disable C-TCAM lookup when last C-TCAM eRP is deleted */
 692        if (erp_table->num_ctcam_erps > 1)
 693                return;
 694
 695        mlxsw_sp_acl_erp_table_enable(erp_table, false);
 696}
 697
 698static int
 699__mlxsw_sp_acl_erp_table_other_inc(struct mlxsw_sp_acl_erp_table *erp_table,
 700                                   unsigned int *inc_num)
 701{
 702        int err;
 703
 704        /* If there are C-TCAM eRP or deltas in use we need to transition
 705         * the region to use eRP table, if it is not already done
 706         */
 707        if (!mlxsw_sp_acl_erp_table_is_used(erp_table)) {
 708                err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
 709                if (err)
 710                        return err;
 711        }
 712
 713        /* When C-TCAM or deltas are used, the eRP table must be used */
 714        if (erp_table->ops != &erp_multiple_masks_ops)
 715                erp_table->ops = &erp_multiple_masks_ops;
 716
 717        (*inc_num)++;
 718
 719        return 0;
 720}
 721
 722static int mlxsw_sp_acl_erp_ctcam_inc(struct mlxsw_sp_acl_erp_table *erp_table)
 723{
 724        return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
 725                                                  &erp_table->num_ctcam_erps);
 726}
 727
 728static int mlxsw_sp_acl_erp_delta_inc(struct mlxsw_sp_acl_erp_table *erp_table)
 729{
 730        return __mlxsw_sp_acl_erp_table_other_inc(erp_table,
 731                                                  &erp_table->num_deltas);
 732}
 733
 734static void
 735__mlxsw_sp_acl_erp_table_other_dec(struct mlxsw_sp_acl_erp_table *erp_table,
 736                                   unsigned int *dec_num)
 737{
 738        (*dec_num)--;
 739
 740        /* If there are no C-TCAM eRP or deltas in use, the state we
 741         * transition to depends on the number of A-TCAM eRPs currently
 742         * in use.
 743         */
 744        if (erp_table->num_ctcam_erps > 0 || erp_table->num_deltas > 0)
 745                return;
 746
 747        switch (erp_table->num_atcam_erps) {
 748        case 2:
 749                /* Keep using the eRP table, but correctly set the
 750                 * operations pointer so that when an A-TCAM eRP is
 751                 * deleted we will transition to use the master mask
 752                 */
 753                erp_table->ops = &erp_two_masks_ops;
 754                break;
 755        case 1:
 756                /* We only kept the eRP table because we had C-TCAM
 757                 * eRPs in use. Now that the last C-TCAM eRP is gone we
 758                 * can stop using the table and transition to use the
 759                 * master mask
 760                 */
 761                mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
 762                erp_table->ops = &erp_single_mask_ops;
 763                break;
 764        case 0:
 765                /* There are no more eRPs of any kind used by the region
 766                 * so free its eRP table and transition to initial state
 767                 */
 768                mlxsw_sp_acl_erp_table_disable(erp_table);
 769                mlxsw_sp_acl_erp_table_free(erp_table->erp_core,
 770                                            erp_table->num_max_atcam_erps,
 771                                            erp_table->aregion->type,
 772                                            erp_table->base_index);
 773                erp_table->ops = &erp_no_mask_ops;
 774                break;
 775        default:
 776                break;
 777        }
 778}
 779
 780static void mlxsw_sp_acl_erp_ctcam_dec(struct mlxsw_sp_acl_erp_table *erp_table)
 781{
 782        __mlxsw_sp_acl_erp_table_other_dec(erp_table,
 783                                           &erp_table->num_ctcam_erps);
 784}
 785
 786static void mlxsw_sp_acl_erp_delta_dec(struct mlxsw_sp_acl_erp_table *erp_table)
 787{
 788        __mlxsw_sp_acl_erp_table_other_dec(erp_table,
 789                                           &erp_table->num_deltas);
 790}
 791
 792static struct mlxsw_sp_acl_erp *
 793mlxsw_sp_acl_erp_ctcam_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 794                                   struct mlxsw_sp_acl_erp_key *key)
 795{
 796        struct mlxsw_sp_acl_erp *erp;
 797        int err;
 798
 799        erp = kzalloc(sizeof(*erp), GFP_KERNEL);
 800        if (!erp)
 801                return ERR_PTR(-ENOMEM);
 802
 803        memcpy(&erp->key, key, sizeof(*key));
 804        bitmap_from_arr32(erp->mask_bitmap, (u32 *) key->mask,
 805                          MLXSW_SP_ACL_TCAM_MASK_LEN);
 806
 807        err = mlxsw_sp_acl_erp_ctcam_inc(erp_table);
 808        if (err)
 809                goto err_erp_ctcam_inc;
 810
 811        erp->erp_table = erp_table;
 812
 813        err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &erp->key);
 814        if (err)
 815                goto err_master_mask_set;
 816
 817        err = mlxsw_sp_acl_erp_region_ctcam_enable(erp_table);
 818        if (err)
 819                goto err_erp_region_ctcam_enable;
 820
 821        return erp;
 822
 823err_erp_region_ctcam_enable:
 824        mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
 825err_master_mask_set:
 826        mlxsw_sp_acl_erp_ctcam_dec(erp_table);
 827err_erp_ctcam_inc:
 828        kfree(erp);
 829        return ERR_PTR(err);
 830}
 831
 832static void
 833mlxsw_sp_acl_erp_ctcam_mask_destroy(struct mlxsw_sp_acl_erp *erp)
 834{
 835        struct mlxsw_sp_acl_erp_table *erp_table = erp->erp_table;
 836
 837        mlxsw_sp_acl_erp_region_ctcam_disable(erp_table);
 838        mlxsw_sp_acl_erp_master_mask_clear(erp_table, &erp->key);
 839        mlxsw_sp_acl_erp_ctcam_dec(erp_table);
 840        kfree(erp);
 841}
 842
 843static struct mlxsw_sp_acl_erp *
 844mlxsw_sp_acl_erp_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 845                             struct mlxsw_sp_acl_erp_key *key)
 846{
 847        struct mlxsw_sp_acl_erp *erp;
 848        int err;
 849
 850        if (key->ctcam)
 851                return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
 852
 853        /* Expand the eRP table for the new eRP, if needed */
 854        err = mlxsw_sp_acl_erp_table_expand(erp_table);
 855        if (err)
 856                return ERR_PTR(err);
 857
 858        erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
 859        if (IS_ERR(erp))
 860                return erp;
 861
 862        err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
 863        if (err)
 864                goto err_erp_index_get;
 865
 866        err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
 867        if (err)
 868                goto err_table_erp_add;
 869
 870        err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
 871        if (err)
 872                goto err_region_erp_add;
 873
 874        erp_table->ops = &erp_multiple_masks_ops;
 875
 876        return erp;
 877
 878err_region_erp_add:
 879        mlxsw_sp_acl_erp_table_erp_del(erp);
 880err_table_erp_add:
 881        mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
 882err_erp_index_get:
 883        mlxsw_sp_acl_erp_generic_destroy(erp);
 884        return ERR_PTR(err);
 885}
 886
 887static void
 888mlxsw_sp_acl_erp_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
 889                              struct mlxsw_sp_acl_erp *erp)
 890{
 891        if (erp->key.ctcam)
 892                return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
 893
 894        mlxsw_sp_acl_erp_region_erp_del(erp);
 895        mlxsw_sp_acl_erp_table_erp_del(erp);
 896        mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
 897        mlxsw_sp_acl_erp_generic_destroy(erp);
 898
 899        if (erp_table->num_atcam_erps == 2 && erp_table->num_ctcam_erps == 0 &&
 900            erp_table->num_deltas == 0)
 901                erp_table->ops = &erp_two_masks_ops;
 902}
 903
 904static struct mlxsw_sp_acl_erp *
 905mlxsw_sp_acl_erp_second_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 906                                    struct mlxsw_sp_acl_erp_key *key)
 907{
 908        struct mlxsw_sp_acl_erp *erp;
 909        int err;
 910
 911        if (key->ctcam)
 912                return mlxsw_sp_acl_erp_ctcam_mask_create(erp_table, key);
 913
 914        /* Transition to use eRP table instead of master mask */
 915        err = mlxsw_sp_acl_erp_region_table_trans(erp_table);
 916        if (err)
 917                return ERR_PTR(err);
 918
 919        erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
 920        if (IS_ERR(erp)) {
 921                err = PTR_ERR(erp);
 922                goto err_erp_create;
 923        }
 924
 925        err = mlxsw_sp_acl_erp_index_get(erp_table, &erp->index);
 926        if (err)
 927                goto err_erp_index_get;
 928
 929        err = mlxsw_sp_acl_erp_table_erp_add(erp_table, erp);
 930        if (err)
 931                goto err_table_erp_add;
 932
 933        err = mlxsw_sp_acl_erp_region_erp_add(erp_table, erp);
 934        if (err)
 935                goto err_region_erp_add;
 936
 937        erp_table->ops = &erp_two_masks_ops;
 938
 939        return erp;
 940
 941err_region_erp_add:
 942        mlxsw_sp_acl_erp_table_erp_del(erp);
 943err_table_erp_add:
 944        mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
 945err_erp_index_get:
 946        mlxsw_sp_acl_erp_generic_destroy(erp);
 947err_erp_create:
 948        mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
 949        return ERR_PTR(err);
 950}
 951
 952static void
 953mlxsw_sp_acl_erp_second_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
 954                                     struct mlxsw_sp_acl_erp *erp)
 955{
 956        if (erp->key.ctcam)
 957                return mlxsw_sp_acl_erp_ctcam_mask_destroy(erp);
 958
 959        mlxsw_sp_acl_erp_region_erp_del(erp);
 960        mlxsw_sp_acl_erp_table_erp_del(erp);
 961        mlxsw_sp_acl_erp_index_put(erp_table, erp->index);
 962        mlxsw_sp_acl_erp_generic_destroy(erp);
 963        /* Transition to use master mask instead of eRP table */
 964        mlxsw_sp_acl_erp_region_master_mask_trans(erp_table);
 965
 966        erp_table->ops = &erp_single_mask_ops;
 967}
 968
 969static struct mlxsw_sp_acl_erp *
 970mlxsw_sp_acl_erp_first_mask_create(struct mlxsw_sp_acl_erp_table *erp_table,
 971                                   struct mlxsw_sp_acl_erp_key *key)
 972{
 973        struct mlxsw_sp_acl_erp *erp;
 974
 975        if (key->ctcam)
 976                return ERR_PTR(-EINVAL);
 977
 978        erp = mlxsw_sp_acl_erp_generic_create(erp_table, key);
 979        if (IS_ERR(erp))
 980                return erp;
 981
 982        erp_table->ops = &erp_single_mask_ops;
 983
 984        return erp;
 985}
 986
 987static void
 988mlxsw_sp_acl_erp_first_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
 989                                    struct mlxsw_sp_acl_erp *erp)
 990{
 991        mlxsw_sp_acl_erp_generic_destroy(erp);
 992        erp_table->ops = &erp_no_mask_ops;
 993}
 994
 995static void
 996mlxsw_sp_acl_erp_no_mask_destroy(struct mlxsw_sp_acl_erp_table *erp_table,
 997                                 struct mlxsw_sp_acl_erp *erp)
 998{
 999        WARN_ON(1);
1000}
1001
1002struct mlxsw_sp_acl_erp_mask *
1003mlxsw_sp_acl_erp_mask_get(struct mlxsw_sp_acl_atcam_region *aregion,
1004                          const char *mask, bool ctcam)
1005{
1006        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1007        struct mlxsw_sp_acl_erp_key key;
1008        struct objagg_obj *objagg_obj;
1009
1010        memcpy(key.mask, mask, MLXSW_REG_PTCEX_FLEX_KEY_BLOCKS_LEN);
1011        key.ctcam = ctcam;
1012        mutex_lock(&erp_table->objagg_lock);
1013        objagg_obj = objagg_obj_get(erp_table->objagg, &key);
1014        mutex_unlock(&erp_table->objagg_lock);
1015        if (IS_ERR(objagg_obj))
1016                return ERR_CAST(objagg_obj);
1017        return (struct mlxsw_sp_acl_erp_mask *) objagg_obj;
1018}
1019
1020void mlxsw_sp_acl_erp_mask_put(struct mlxsw_sp_acl_atcam_region *aregion,
1021                               struct mlxsw_sp_acl_erp_mask *erp_mask)
1022{
1023        struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1024        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1025
1026        mutex_lock(&erp_table->objagg_lock);
1027        objagg_obj_put(erp_table->objagg, objagg_obj);
1028        mutex_unlock(&erp_table->objagg_lock);
1029}
1030
1031int mlxsw_sp_acl_erp_bf_insert(struct mlxsw_sp *mlxsw_sp,
1032                               struct mlxsw_sp_acl_atcam_region *aregion,
1033                               struct mlxsw_sp_acl_erp_mask *erp_mask,
1034                               struct mlxsw_sp_acl_atcam_entry *aentry)
1035{
1036        struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1037        const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1038        unsigned int erp_bank;
1039
1040        if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1041                return 0;
1042
1043        erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
1044        return mlxsw_sp_acl_bf_entry_add(mlxsw_sp,
1045                                        erp->erp_table->erp_core->bf,
1046                                        aregion, erp_bank, aentry);
1047}
1048
1049void mlxsw_sp_acl_erp_bf_remove(struct mlxsw_sp *mlxsw_sp,
1050                                struct mlxsw_sp_acl_atcam_region *aregion,
1051                                struct mlxsw_sp_acl_erp_mask *erp_mask,
1052                                struct mlxsw_sp_acl_atcam_entry *aentry)
1053{
1054        struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1055        const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1056        unsigned int erp_bank;
1057
1058        if (!mlxsw_sp_acl_erp_table_is_used(erp->erp_table))
1059                return;
1060
1061        erp_bank = mlxsw_sp_acl_erp_bank_get(erp);
1062        mlxsw_sp_acl_bf_entry_del(mlxsw_sp,
1063                                  erp->erp_table->erp_core->bf,
1064                                  aregion, erp_bank, aentry);
1065}
1066
1067bool
1068mlxsw_sp_acl_erp_mask_is_ctcam(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1069{
1070        struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1071        const struct mlxsw_sp_acl_erp_key *key = objagg_obj_raw(objagg_obj);
1072
1073        return key->ctcam;
1074}
1075
1076u8 mlxsw_sp_acl_erp_mask_erp_id(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1077{
1078        struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1079        const struct mlxsw_sp_acl_erp *erp = objagg_obj_root_priv(objagg_obj);
1080
1081        return erp->id;
1082}
1083
1084struct mlxsw_sp_acl_erp_delta {
1085        struct mlxsw_sp_acl_erp_key key;
1086        u16 start;
1087        u8 mask;
1088};
1089
1090u16 mlxsw_sp_acl_erp_delta_start(const struct mlxsw_sp_acl_erp_delta *delta)
1091{
1092        return delta->start;
1093}
1094
1095u8 mlxsw_sp_acl_erp_delta_mask(const struct mlxsw_sp_acl_erp_delta *delta)
1096{
1097        return delta->mask;
1098}
1099
1100u8 mlxsw_sp_acl_erp_delta_value(const struct mlxsw_sp_acl_erp_delta *delta,
1101                                const char *enc_key)
1102{
1103        u16 start = delta->start;
1104        u8 mask = delta->mask;
1105        u16 tmp;
1106
1107        if (!mask)
1108                return 0;
1109
1110        tmp = (unsigned char) enc_key[__MASK_IDX(start / 8)];
1111        if (start / 8 + 1 < __MASK_LEN)
1112                tmp |= (unsigned char) enc_key[__MASK_IDX(start / 8 + 1)] << 8;
1113        tmp >>= start % 8;
1114        tmp &= mask;
1115        return tmp;
1116}
1117
1118void mlxsw_sp_acl_erp_delta_clear(const struct mlxsw_sp_acl_erp_delta *delta,
1119                                  const char *enc_key)
1120{
1121        u16 start = delta->start;
1122        u8 mask = delta->mask;
1123        unsigned char *byte;
1124        u16 tmp;
1125
1126        tmp = mask;
1127        tmp <<= start % 8;
1128        tmp = ~tmp;
1129
1130        byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8)];
1131        *byte &= tmp & 0xff;
1132        if (start / 8 + 1 < __MASK_LEN) {
1133                byte = (unsigned char *) &enc_key[__MASK_IDX(start / 8 + 1)];
1134                *byte &= (tmp >> 8) & 0xff;
1135        }
1136}
1137
1138static const struct mlxsw_sp_acl_erp_delta
1139mlxsw_sp_acl_erp_delta_default = {};
1140
1141const struct mlxsw_sp_acl_erp_delta *
1142mlxsw_sp_acl_erp_delta(const struct mlxsw_sp_acl_erp_mask *erp_mask)
1143{
1144        struct objagg_obj *objagg_obj = (struct objagg_obj *) erp_mask;
1145        const struct mlxsw_sp_acl_erp_delta *delta;
1146
1147        delta = objagg_obj_delta_priv(objagg_obj);
1148        if (!delta)
1149                delta = &mlxsw_sp_acl_erp_delta_default;
1150        return delta;
1151}
1152
1153static int
1154mlxsw_sp_acl_erp_delta_fill(const struct mlxsw_sp_acl_erp_key *parent_key,
1155                            const struct mlxsw_sp_acl_erp_key *key,
1156                            u16 *delta_start, u8 *delta_mask)
1157{
1158        int offset = 0;
1159        int si = -1;
1160        u16 pmask;
1161        u16 mask;
1162        int i;
1163
1164        /* The difference between 2 masks can be up to 8 consecutive bits. */
1165        for (i = 0; i < __MASK_LEN; i++) {
1166                if (parent_key->mask[__MASK_IDX(i)] == key->mask[__MASK_IDX(i)])
1167                        continue;
1168                if (si == -1)
1169                        si = i;
1170                else if (si != i - 1)
1171                        return -EINVAL;
1172        }
1173        if (si == -1) {
1174                /* The masks are the same, this can happen in case eRPs with
1175                 * the same mask were created in both A-TCAM and C-TCAM.
1176                 * The only possible condition under which this can happen
1177                 * is identical rule insertion. Delta is not possible here.
1178                 */
1179                return -EINVAL;
1180        }
1181        pmask = (unsigned char) parent_key->mask[__MASK_IDX(si)];
1182        mask = (unsigned char) key->mask[__MASK_IDX(si)];
1183        if (si + 1 < __MASK_LEN) {
1184                pmask |= (unsigned char) parent_key->mask[__MASK_IDX(si + 1)] << 8;
1185                mask |= (unsigned char) key->mask[__MASK_IDX(si + 1)] << 8;
1186        }
1187
1188        if ((pmask ^ mask) & pmask)
1189                return -EINVAL;
1190        mask &= ~pmask;
1191        while (!(mask & (1 << offset)))
1192                offset++;
1193        while (!(mask & 1))
1194                mask >>= 1;
1195        if (mask & 0xff00)
1196                return -EINVAL;
1197
1198        *delta_start = si * 8 + offset;
1199        *delta_mask = mask;
1200
1201        return 0;
1202}
1203
1204static bool mlxsw_sp_acl_erp_delta_check(void *priv, const void *parent_obj,
1205                                         const void *obj)
1206{
1207        const struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
1208        const struct mlxsw_sp_acl_erp_key *key = obj;
1209        u16 delta_start;
1210        u8 delta_mask;
1211        int err;
1212
1213        err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
1214                                          &delta_start, &delta_mask);
1215        return err ? false : true;
1216}
1217
1218static int mlxsw_sp_acl_erp_hints_obj_cmp(const void *obj1, const void *obj2)
1219{
1220        const struct mlxsw_sp_acl_erp_key *key1 = obj1;
1221        const struct mlxsw_sp_acl_erp_key *key2 = obj2;
1222
1223        /* For hints purposes, two objects are considered equal
1224         * in case the masks are the same. Does not matter what
1225         * the "ctcam" value is.
1226         */
1227        return memcmp(key1->mask, key2->mask, sizeof(key1->mask));
1228}
1229
1230static void *mlxsw_sp_acl_erp_delta_create(void *priv, void *parent_obj,
1231                                           void *obj)
1232{
1233        struct mlxsw_sp_acl_erp_key *parent_key = parent_obj;
1234        struct mlxsw_sp_acl_atcam_region *aregion = priv;
1235        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1236        struct mlxsw_sp_acl_erp_key *key = obj;
1237        struct mlxsw_sp_acl_erp_delta *delta;
1238        u16 delta_start;
1239        u8 delta_mask;
1240        int err;
1241
1242        if (parent_key->ctcam || key->ctcam)
1243                return ERR_PTR(-EINVAL);
1244        err = mlxsw_sp_acl_erp_delta_fill(parent_key, key,
1245                                          &delta_start, &delta_mask);
1246        if (err)
1247                return ERR_PTR(-EINVAL);
1248
1249        delta = kzalloc(sizeof(*delta), GFP_KERNEL);
1250        if (!delta)
1251                return ERR_PTR(-ENOMEM);
1252        delta->start = delta_start;
1253        delta->mask = delta_mask;
1254
1255        err = mlxsw_sp_acl_erp_delta_inc(erp_table);
1256        if (err)
1257                goto err_erp_delta_inc;
1258
1259        memcpy(&delta->key, key, sizeof(*key));
1260        err = mlxsw_sp_acl_erp_master_mask_set(erp_table, &delta->key);
1261        if (err)
1262                goto err_master_mask_set;
1263
1264        return delta;
1265
1266err_master_mask_set:
1267        mlxsw_sp_acl_erp_delta_dec(erp_table);
1268err_erp_delta_inc:
1269        kfree(delta);
1270        return ERR_PTR(err);
1271}
1272
1273static void mlxsw_sp_acl_erp_delta_destroy(void *priv, void *delta_priv)
1274{
1275        struct mlxsw_sp_acl_erp_delta *delta = delta_priv;
1276        struct mlxsw_sp_acl_atcam_region *aregion = priv;
1277        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1278
1279        mlxsw_sp_acl_erp_master_mask_clear(erp_table, &delta->key);
1280        mlxsw_sp_acl_erp_delta_dec(erp_table);
1281        kfree(delta);
1282}
1283
1284static void *mlxsw_sp_acl_erp_root_create(void *priv, void *obj,
1285                                          unsigned int root_id)
1286{
1287        struct mlxsw_sp_acl_atcam_region *aregion = priv;
1288        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1289        struct mlxsw_sp_acl_erp_key *key = obj;
1290
1291        if (!key->ctcam &&
1292            root_id != OBJAGG_OBJ_ROOT_ID_INVALID &&
1293            root_id >= MLXSW_SP_ACL_ERP_MAX_PER_REGION)
1294                return ERR_PTR(-ENOBUFS);
1295        return erp_table->ops->erp_create(erp_table, key);
1296}
1297
1298static void mlxsw_sp_acl_erp_root_destroy(void *priv, void *root_priv)
1299{
1300        struct mlxsw_sp_acl_atcam_region *aregion = priv;
1301        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1302
1303        erp_table->ops->erp_destroy(erp_table, root_priv);
1304}
1305
1306static const struct objagg_ops mlxsw_sp_acl_erp_objagg_ops = {
1307        .obj_size = sizeof(struct mlxsw_sp_acl_erp_key),
1308        .delta_check = mlxsw_sp_acl_erp_delta_check,
1309        .hints_obj_cmp = mlxsw_sp_acl_erp_hints_obj_cmp,
1310        .delta_create = mlxsw_sp_acl_erp_delta_create,
1311        .delta_destroy = mlxsw_sp_acl_erp_delta_destroy,
1312        .root_create = mlxsw_sp_acl_erp_root_create,
1313        .root_destroy = mlxsw_sp_acl_erp_root_destroy,
1314};
1315
1316static struct mlxsw_sp_acl_erp_table *
1317mlxsw_sp_acl_erp_table_create(struct mlxsw_sp_acl_atcam_region *aregion,
1318                              struct objagg_hints *hints)
1319{
1320        struct mlxsw_sp_acl_erp_table *erp_table;
1321        int err;
1322
1323        erp_table = kzalloc(sizeof(*erp_table), GFP_KERNEL);
1324        if (!erp_table)
1325                return ERR_PTR(-ENOMEM);
1326
1327        erp_table->objagg = objagg_create(&mlxsw_sp_acl_erp_objagg_ops,
1328                                          hints, aregion);
1329        if (IS_ERR(erp_table->objagg)) {
1330                err = PTR_ERR(erp_table->objagg);
1331                goto err_objagg_create;
1332        }
1333
1334        erp_table->erp_core = aregion->atcam->erp_core;
1335        erp_table->ops = &erp_no_mask_ops;
1336        INIT_LIST_HEAD(&erp_table->atcam_erps_list);
1337        erp_table->aregion = aregion;
1338        mutex_init(&erp_table->objagg_lock);
1339
1340        return erp_table;
1341
1342err_objagg_create:
1343        kfree(erp_table);
1344        return ERR_PTR(err);
1345}
1346
1347static void
1348mlxsw_sp_acl_erp_table_destroy(struct mlxsw_sp_acl_erp_table *erp_table)
1349{
1350        WARN_ON(!list_empty(&erp_table->atcam_erps_list));
1351        mutex_destroy(&erp_table->objagg_lock);
1352        objagg_destroy(erp_table->objagg);
1353        kfree(erp_table);
1354}
1355
1356static int
1357mlxsw_sp_acl_erp_master_mask_init(struct mlxsw_sp_acl_atcam_region *aregion)
1358{
1359        struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1360        char percr_pl[MLXSW_REG_PERCR_LEN];
1361
1362        mlxsw_reg_percr_pack(percr_pl, aregion->region->id);
1363        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(percr), percr_pl);
1364}
1365
1366static int
1367mlxsw_sp_acl_erp_region_param_init(struct mlxsw_sp_acl_atcam_region *aregion)
1368{
1369        struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1370        char pererp_pl[MLXSW_REG_PERERP_LEN];
1371
1372        mlxsw_reg_pererp_pack(pererp_pl, aregion->region->id, false, false, 0,
1373                              0, 0);
1374        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pererp), pererp_pl);
1375}
1376
1377static int
1378mlxsw_sp_acl_erp_hints_check(struct mlxsw_sp *mlxsw_sp,
1379                             struct mlxsw_sp_acl_atcam_region *aregion,
1380                             struct objagg_hints *hints, bool *p_rehash_needed)
1381{
1382        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1383        const struct objagg_stats *ostats;
1384        const struct objagg_stats *hstats;
1385        int err;
1386
1387        *p_rehash_needed = false;
1388
1389        mutex_lock(&erp_table->objagg_lock);
1390        ostats = objagg_stats_get(erp_table->objagg);
1391        mutex_unlock(&erp_table->objagg_lock);
1392        if (IS_ERR(ostats)) {
1393                dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP stats\n");
1394                return PTR_ERR(ostats);
1395        }
1396
1397        hstats = objagg_hints_stats_get(hints);
1398        if (IS_ERR(hstats)) {
1399                dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to get ERP hints stats\n");
1400                err = PTR_ERR(hstats);
1401                goto err_hints_stats_get;
1402        }
1403
1404        /* Very basic criterion for now. */
1405        if (hstats->root_count < ostats->root_count)
1406                *p_rehash_needed = true;
1407
1408        err = 0;
1409
1410        objagg_stats_put(hstats);
1411err_hints_stats_get:
1412        objagg_stats_put(ostats);
1413        return err;
1414}
1415
1416void *
1417mlxsw_sp_acl_erp_rehash_hints_get(struct mlxsw_sp_acl_atcam_region *aregion)
1418{
1419        struct mlxsw_sp_acl_erp_table *erp_table = aregion->erp_table;
1420        struct mlxsw_sp *mlxsw_sp = aregion->region->mlxsw_sp;
1421        struct objagg_hints *hints;
1422        bool rehash_needed;
1423        int err;
1424
1425        mutex_lock(&erp_table->objagg_lock);
1426        hints = objagg_hints_get(erp_table->objagg,
1427                                 OBJAGG_OPT_ALGO_SIMPLE_GREEDY);
1428        mutex_unlock(&erp_table->objagg_lock);
1429        if (IS_ERR(hints)) {
1430                dev_err_ratelimited(mlxsw_sp->bus_info->dev, "Failed to create ERP hints\n");
1431                return ERR_CAST(hints);
1432        }
1433        err = mlxsw_sp_acl_erp_hints_check(mlxsw_sp, aregion, hints,
1434                                           &rehash_needed);
1435        if (err)
1436                goto errout;
1437
1438        if (!rehash_needed) {
1439                err = -EAGAIN;
1440                goto errout;
1441        }
1442        return hints;
1443
1444errout:
1445        objagg_hints_put(hints);
1446        return ERR_PTR(err);
1447}
1448
1449void mlxsw_sp_acl_erp_rehash_hints_put(void *hints_priv)
1450{
1451        struct objagg_hints *hints = hints_priv;
1452
1453        objagg_hints_put(hints);
1454}
1455
1456int mlxsw_sp_acl_erp_region_init(struct mlxsw_sp_acl_atcam_region *aregion,
1457                                 void *hints_priv)
1458{
1459        struct mlxsw_sp_acl_erp_table *erp_table;
1460        struct objagg_hints *hints = hints_priv;
1461        int err;
1462
1463        erp_table = mlxsw_sp_acl_erp_table_create(aregion, hints);
1464        if (IS_ERR(erp_table))
1465                return PTR_ERR(erp_table);
1466        aregion->erp_table = erp_table;
1467
1468        /* Initialize the region's master mask to all zeroes */
1469        err = mlxsw_sp_acl_erp_master_mask_init(aregion);
1470        if (err)
1471                goto err_erp_master_mask_init;
1472
1473        /* Initialize the region to not use the eRP table */
1474        err = mlxsw_sp_acl_erp_region_param_init(aregion);
1475        if (err)
1476                goto err_erp_region_param_init;
1477
1478        return 0;
1479
1480err_erp_region_param_init:
1481err_erp_master_mask_init:
1482        mlxsw_sp_acl_erp_table_destroy(erp_table);
1483        return err;
1484}
1485
1486void mlxsw_sp_acl_erp_region_fini(struct mlxsw_sp_acl_atcam_region *aregion)
1487{
1488        mlxsw_sp_acl_erp_table_destroy(aregion->erp_table);
1489}
1490
1491static int
1492mlxsw_sp_acl_erp_tables_sizes_query(struct mlxsw_sp *mlxsw_sp,
1493                                    struct mlxsw_sp_acl_erp_core *erp_core)
1494{
1495        unsigned int size;
1496
1497        if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB) ||
1498            !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB) ||
1499            !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB) ||
1500            !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB))
1501                return -EIO;
1502
1503        size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_2KB);
1504        erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_2KB] = size;
1505
1506        size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_4KB);
1507        erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_4KB] = size;
1508
1509        size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_8KB);
1510        erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_8KB] = size;
1511
1512        size = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_ERPT_ENTRIES_12KB);
1513        erp_core->erpt_entries_size[MLXSW_SP_ACL_ATCAM_REGION_TYPE_12KB] = size;
1514
1515        return 0;
1516}
1517
1518static int mlxsw_sp_acl_erp_tables_init(struct mlxsw_sp *mlxsw_sp,
1519                                        struct mlxsw_sp_acl_erp_core *erp_core)
1520{
1521        unsigned int erpt_bank_size;
1522        int err;
1523
1524        if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANK_SIZE) ||
1525            !MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_ERPT_BANKS))
1526                return -EIO;
1527        erpt_bank_size = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1528                                            ACL_MAX_ERPT_BANK_SIZE);
1529        erp_core->num_erp_banks = MLXSW_CORE_RES_GET(mlxsw_sp->core,
1530                                                     ACL_MAX_ERPT_BANKS);
1531
1532        erp_core->erp_tables = gen_pool_create(0, -1);
1533        if (!erp_core->erp_tables)
1534                return -ENOMEM;
1535        gen_pool_set_algo(erp_core->erp_tables, gen_pool_best_fit, NULL);
1536
1537        err = gen_pool_add(erp_core->erp_tables,
1538                           MLXSW_SP_ACL_ERP_GENALLOC_OFFSET, erpt_bank_size,
1539                           -1);
1540        if (err)
1541                goto err_gen_pool_add;
1542
1543        erp_core->bf = mlxsw_sp_acl_bf_init(mlxsw_sp, erp_core->num_erp_banks);
1544        if (IS_ERR(erp_core->bf)) {
1545                err = PTR_ERR(erp_core->bf);
1546                goto err_bf_init;
1547        }
1548
1549        /* Different regions require masks of different sizes */
1550        err = mlxsw_sp_acl_erp_tables_sizes_query(mlxsw_sp, erp_core);
1551        if (err)
1552                goto err_erp_tables_sizes_query;
1553
1554        return 0;
1555
1556err_erp_tables_sizes_query:
1557        mlxsw_sp_acl_bf_fini(erp_core->bf);
1558err_bf_init:
1559err_gen_pool_add:
1560        gen_pool_destroy(erp_core->erp_tables);
1561        return err;
1562}
1563
1564static void mlxsw_sp_acl_erp_tables_fini(struct mlxsw_sp *mlxsw_sp,
1565                                         struct mlxsw_sp_acl_erp_core *erp_core)
1566{
1567        mlxsw_sp_acl_bf_fini(erp_core->bf);
1568        gen_pool_destroy(erp_core->erp_tables);
1569}
1570
1571int mlxsw_sp_acl_erps_init(struct mlxsw_sp *mlxsw_sp,
1572                           struct mlxsw_sp_acl_atcam *atcam)
1573{
1574        struct mlxsw_sp_acl_erp_core *erp_core;
1575        int err;
1576
1577        erp_core = kzalloc(sizeof(*erp_core), GFP_KERNEL);
1578        if (!erp_core)
1579                return -ENOMEM;
1580        erp_core->mlxsw_sp = mlxsw_sp;
1581        atcam->erp_core = erp_core;
1582
1583        err = mlxsw_sp_acl_erp_tables_init(mlxsw_sp, erp_core);
1584        if (err)
1585                goto err_erp_tables_init;
1586
1587        return 0;
1588
1589err_erp_tables_init:
1590        kfree(erp_core);
1591        return err;
1592}
1593
1594void mlxsw_sp_acl_erps_fini(struct mlxsw_sp *mlxsw_sp,
1595                            struct mlxsw_sp_acl_atcam *atcam)
1596{
1597        mlxsw_sp_acl_erp_tables_fini(mlxsw_sp, atcam->erp_core);
1598        kfree(atcam->erp_core);
1599}
1600