linux/drivers/net/ethernet/mellanox/mlxsw/spectrum2_acl_tcam.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
   6#include "spectrum.h"
   7#include "spectrum_acl_tcam.h"
   8#include "core_acl_flex_actions.h"
   9
  10struct mlxsw_sp2_acl_tcam {
  11        struct mlxsw_sp_acl_atcam atcam;
  12        u32 kvdl_index;
  13        unsigned int kvdl_count;
  14};
  15
  16struct mlxsw_sp2_acl_tcam_region {
  17        struct mlxsw_sp_acl_atcam_region aregion;
  18        struct mlxsw_sp_acl_tcam_region *region;
  19};
  20
  21struct mlxsw_sp2_acl_tcam_chunk {
  22        struct mlxsw_sp_acl_atcam_chunk achunk;
  23};
  24
  25struct mlxsw_sp2_acl_tcam_entry {
  26        struct mlxsw_sp_acl_atcam_entry aentry;
  27        struct mlxsw_afa_block *act_block;
  28};
  29
  30static int
  31mlxsw_sp2_acl_ctcam_region_entry_insert(struct mlxsw_sp_acl_ctcam_region *cregion,
  32                                        struct mlxsw_sp_acl_ctcam_entry *centry,
  33                                        const char *mask)
  34{
  35        struct mlxsw_sp_acl_atcam_region *aregion;
  36        struct mlxsw_sp_acl_atcam_entry *aentry;
  37        struct mlxsw_sp_acl_erp_mask *erp_mask;
  38
  39        aregion = mlxsw_sp_acl_tcam_cregion_aregion(cregion);
  40        aentry = mlxsw_sp_acl_tcam_centry_aentry(centry);
  41
  42        erp_mask = mlxsw_sp_acl_erp_mask_get(aregion, mask, true);
  43        if (IS_ERR(erp_mask))
  44                return PTR_ERR(erp_mask);
  45        aentry->erp_mask = erp_mask;
  46
  47        return 0;
  48}
  49
  50static void
  51mlxsw_sp2_acl_ctcam_region_entry_remove(struct mlxsw_sp_acl_ctcam_region *cregion,
  52                                        struct mlxsw_sp_acl_ctcam_entry *centry)
  53{
  54        struct mlxsw_sp_acl_atcam_region *aregion;
  55        struct mlxsw_sp_acl_atcam_entry *aentry;
  56
  57        aregion = mlxsw_sp_acl_tcam_cregion_aregion(cregion);
  58        aentry = mlxsw_sp_acl_tcam_centry_aentry(centry);
  59
  60        mlxsw_sp_acl_erp_mask_put(aregion, aentry->erp_mask);
  61}
  62
  63static const struct mlxsw_sp_acl_ctcam_region_ops
  64mlxsw_sp2_acl_ctcam_region_ops = {
  65        .entry_insert = mlxsw_sp2_acl_ctcam_region_entry_insert,
  66        .entry_remove = mlxsw_sp2_acl_ctcam_region_entry_remove,
  67};
  68
  69static int mlxsw_sp2_acl_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv,
  70                                   struct mlxsw_sp_acl_tcam *_tcam)
  71{
  72        struct mlxsw_sp2_acl_tcam *tcam = priv;
  73        struct mlxsw_afa_block *afa_block;
  74        char pefa_pl[MLXSW_REG_PEFA_LEN];
  75        char pgcr_pl[MLXSW_REG_PGCR_LEN];
  76        char *enc_actions;
  77        int i;
  78        int err;
  79
  80        tcam->kvdl_count = _tcam->max_regions;
  81        err = mlxsw_sp_kvdl_alloc(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
  82                                  tcam->kvdl_count, &tcam->kvdl_index);
  83        if (err)
  84                return err;
  85
  86        /* Create flex action block, set default action (continue)
  87         * but don't commit. We need just the current set encoding
  88         * to be written using PEFA register to all indexes for all regions.
  89         */
  90        afa_block = mlxsw_afa_block_create(mlxsw_sp->afa);
  91        if (!afa_block) {
  92                err = -ENOMEM;
  93                goto err_afa_block;
  94        }
  95        err = mlxsw_afa_block_continue(afa_block);
  96        if (WARN_ON(err))
  97                goto err_afa_block_continue;
  98        enc_actions = mlxsw_afa_block_cur_set(afa_block);
  99
 100        for (i = 0; i < tcam->kvdl_count; i++) {
 101                mlxsw_reg_pefa_pack(pefa_pl, tcam->kvdl_index + i,
 102                                    true, enc_actions);
 103                err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pefa), pefa_pl);
 104                if (err)
 105                        goto err_pefa_write;
 106        }
 107        mlxsw_reg_pgcr_pack(pgcr_pl, tcam->kvdl_index);
 108        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(pgcr), pgcr_pl);
 109        if (err)
 110                goto err_pgcr_write;
 111
 112        err = mlxsw_sp_acl_atcam_init(mlxsw_sp, &tcam->atcam);
 113        if (err)
 114                goto err_atcam_init;
 115
 116        mlxsw_afa_block_destroy(afa_block);
 117        return 0;
 118
 119err_atcam_init:
 120err_pgcr_write:
 121err_pefa_write:
 122err_afa_block_continue:
 123        mlxsw_afa_block_destroy(afa_block);
 124err_afa_block:
 125        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
 126                           tcam->kvdl_count, tcam->kvdl_index);
 127        return err;
 128}
 129
 130static void mlxsw_sp2_acl_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
 131{
 132        struct mlxsw_sp2_acl_tcam *tcam = priv;
 133
 134        mlxsw_sp_acl_atcam_fini(mlxsw_sp, &tcam->atcam);
 135        mlxsw_sp_kvdl_free(mlxsw_sp, MLXSW_SP_KVDL_ENTRY_TYPE_ACTSET,
 136                           tcam->kvdl_count, tcam->kvdl_index);
 137}
 138
 139static int
 140mlxsw_sp2_acl_tcam_region_init(struct mlxsw_sp *mlxsw_sp, void *region_priv,
 141                               void *tcam_priv,
 142                               struct mlxsw_sp_acl_tcam_region *_region,
 143                               void *hints_priv)
 144{
 145        struct mlxsw_sp2_acl_tcam_region *region = region_priv;
 146        struct mlxsw_sp2_acl_tcam *tcam = tcam_priv;
 147
 148        region->region = _region;
 149
 150        return mlxsw_sp_acl_atcam_region_init(mlxsw_sp, &tcam->atcam,
 151                                              &region->aregion,
 152                                              _region, hints_priv,
 153                                              &mlxsw_sp2_acl_ctcam_region_ops);
 154}
 155
 156static void
 157mlxsw_sp2_acl_tcam_region_fini(struct mlxsw_sp *mlxsw_sp, void *region_priv)
 158{
 159        struct mlxsw_sp2_acl_tcam_region *region = region_priv;
 160
 161        mlxsw_sp_acl_atcam_region_fini(&region->aregion);
 162}
 163
 164static int
 165mlxsw_sp2_acl_tcam_region_associate(struct mlxsw_sp *mlxsw_sp,
 166                                    struct mlxsw_sp_acl_tcam_region *region)
 167{
 168        return mlxsw_sp_acl_atcam_region_associate(mlxsw_sp, region->id);
 169}
 170
 171static void *mlxsw_sp2_acl_tcam_region_rehash_hints_get(void *region_priv)
 172{
 173        struct mlxsw_sp2_acl_tcam_region *region = region_priv;
 174
 175        return mlxsw_sp_acl_atcam_rehash_hints_get(&region->aregion);
 176}
 177
 178static void mlxsw_sp2_acl_tcam_region_rehash_hints_put(void *hints_priv)
 179{
 180        mlxsw_sp_acl_atcam_rehash_hints_put(hints_priv);
 181}
 182
 183static void mlxsw_sp2_acl_tcam_chunk_init(void *region_priv, void *chunk_priv,
 184                                          unsigned int priority)
 185{
 186        struct mlxsw_sp2_acl_tcam_region *region = region_priv;
 187        struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
 188
 189        mlxsw_sp_acl_atcam_chunk_init(&region->aregion, &chunk->achunk,
 190                                      priority);
 191}
 192
 193static void mlxsw_sp2_acl_tcam_chunk_fini(void *chunk_priv)
 194{
 195        struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
 196
 197        mlxsw_sp_acl_atcam_chunk_fini(&chunk->achunk);
 198}
 199
 200static int mlxsw_sp2_acl_tcam_entry_add(struct mlxsw_sp *mlxsw_sp,
 201                                        void *region_priv, void *chunk_priv,
 202                                        void *entry_priv,
 203                                        struct mlxsw_sp_acl_rule_info *rulei)
 204{
 205        struct mlxsw_sp2_acl_tcam_region *region = region_priv;
 206        struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
 207        struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
 208
 209        entry->act_block = rulei->act_block;
 210        return mlxsw_sp_acl_atcam_entry_add(mlxsw_sp, &region->aregion,
 211                                            &chunk->achunk, &entry->aentry,
 212                                            rulei);
 213}
 214
 215static void mlxsw_sp2_acl_tcam_entry_del(struct mlxsw_sp *mlxsw_sp,
 216                                         void *region_priv, void *chunk_priv,
 217                                         void *entry_priv)
 218{
 219        struct mlxsw_sp2_acl_tcam_region *region = region_priv;
 220        struct mlxsw_sp2_acl_tcam_chunk *chunk = chunk_priv;
 221        struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
 222
 223        mlxsw_sp_acl_atcam_entry_del(mlxsw_sp, &region->aregion, &chunk->achunk,
 224                                     &entry->aentry);
 225}
 226
 227static int
 228mlxsw_sp2_acl_tcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
 229                                        void *region_priv, void *entry_priv,
 230                                        struct mlxsw_sp_acl_rule_info *rulei)
 231{
 232        struct mlxsw_sp2_acl_tcam_region *region = region_priv;
 233        struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
 234
 235        entry->act_block = rulei->act_block;
 236        return mlxsw_sp_acl_atcam_entry_action_replace(mlxsw_sp,
 237                                                       &region->aregion,
 238                                                       &entry->aentry, rulei);
 239}
 240
 241static int
 242mlxsw_sp2_acl_tcam_entry_activity_get(struct mlxsw_sp *mlxsw_sp,
 243                                      void *region_priv, void *entry_priv,
 244                                      bool *activity)
 245{
 246        struct mlxsw_sp2_acl_tcam_entry *entry = entry_priv;
 247
 248        return mlxsw_afa_block_activity_get(entry->act_block, activity);
 249}
 250
 251const struct mlxsw_sp_acl_tcam_ops mlxsw_sp2_acl_tcam_ops = {
 252        .key_type               = MLXSW_REG_PTAR_KEY_TYPE_FLEX2,
 253        .priv_size              = sizeof(struct mlxsw_sp2_acl_tcam),
 254        .init                   = mlxsw_sp2_acl_tcam_init,
 255        .fini                   = mlxsw_sp2_acl_tcam_fini,
 256        .region_priv_size       = sizeof(struct mlxsw_sp2_acl_tcam_region),
 257        .region_init            = mlxsw_sp2_acl_tcam_region_init,
 258        .region_fini            = mlxsw_sp2_acl_tcam_region_fini,
 259        .region_associate       = mlxsw_sp2_acl_tcam_region_associate,
 260        .region_rehash_hints_get = mlxsw_sp2_acl_tcam_region_rehash_hints_get,
 261        .region_rehash_hints_put = mlxsw_sp2_acl_tcam_region_rehash_hints_put,
 262        .chunk_priv_size        = sizeof(struct mlxsw_sp2_acl_tcam_chunk),
 263        .chunk_init             = mlxsw_sp2_acl_tcam_chunk_init,
 264        .chunk_fini             = mlxsw_sp2_acl_tcam_chunk_fini,
 265        .entry_priv_size        = sizeof(struct mlxsw_sp2_acl_tcam_entry),
 266        .entry_add              = mlxsw_sp2_acl_tcam_entry_add,
 267        .entry_del              = mlxsw_sp2_acl_tcam_entry_del,
 268        .entry_action_replace   = mlxsw_sp2_acl_tcam_entry_action_replace,
 269        .entry_activity_get     = mlxsw_sp2_acl_tcam_entry_activity_get,
 270};
 271