linux/drivers/net/ethernet/mellanox/mlxsw/spectrum_acl_ctcam.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved */
   3
   4#include <linux/kernel.h>
   5#include <linux/errno.h>
   6#include <linux/parman.h>
   7
   8#include "reg.h"
   9#include "core.h"
  10#include "spectrum.h"
  11#include "spectrum_acl_tcam.h"
  12
  13static int
  14mlxsw_sp_acl_ctcam_region_resize(struct mlxsw_sp *mlxsw_sp,
  15                                 struct mlxsw_sp_acl_tcam_region *region,
  16                                 u16 new_size)
  17{
  18        char ptar_pl[MLXSW_REG_PTAR_LEN];
  19
  20        mlxsw_reg_ptar_pack(ptar_pl, MLXSW_REG_PTAR_OP_RESIZE,
  21                            region->key_type, new_size, region->id,
  22                            region->tcam_region_info);
  23        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptar), ptar_pl);
  24}
  25
  26static void
  27mlxsw_sp_acl_ctcam_region_move(struct mlxsw_sp *mlxsw_sp,
  28                               struct mlxsw_sp_acl_tcam_region *region,
  29                               u16 src_offset, u16 dst_offset, u16 size)
  30{
  31        char prcr_pl[MLXSW_REG_PRCR_LEN];
  32
  33        mlxsw_reg_prcr_pack(prcr_pl, MLXSW_REG_PRCR_OP_MOVE,
  34                            region->tcam_region_info, src_offset,
  35                            region->tcam_region_info, dst_offset, size);
  36        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(prcr), prcr_pl);
  37}
  38
  39static int
  40mlxsw_sp_acl_ctcam_region_entry_insert(struct mlxsw_sp *mlxsw_sp,
  41                                       struct mlxsw_sp_acl_ctcam_region *cregion,
  42                                       struct mlxsw_sp_acl_ctcam_entry *centry,
  43                                       struct mlxsw_sp_acl_rule_info *rulei,
  44                                       bool fillup_priority)
  45{
  46        struct mlxsw_sp_acl_tcam_region *region = cregion->region;
  47        struct mlxsw_afk *afk = mlxsw_sp_acl_afk(mlxsw_sp->acl);
  48        char ptce2_pl[MLXSW_REG_PTCE2_LEN];
  49        char *act_set;
  50        u32 priority;
  51        char *mask;
  52        char *key;
  53        int err;
  54
  55        err = mlxsw_sp_acl_tcam_priority_get(mlxsw_sp, rulei, &priority,
  56                                             fillup_priority);
  57        if (err)
  58                return err;
  59
  60        mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_WRITE,
  61                             region->tcam_region_info,
  62                             centry->parman_item.index, priority);
  63        key = mlxsw_reg_ptce2_flex_key_blocks_data(ptce2_pl);
  64        mask = mlxsw_reg_ptce2_mask_data(ptce2_pl);
  65        mlxsw_afk_encode(afk, region->key_info, &rulei->values, key, mask);
  66
  67        err = cregion->ops->entry_insert(cregion, centry, mask);
  68        if (err)
  69                return err;
  70
  71        /* Only the first action set belongs here, the rest is in KVD */
  72        act_set = mlxsw_afa_block_first_set(rulei->act_block);
  73        mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set);
  74
  75        err = mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
  76        if (err)
  77                goto err_ptce2_write;
  78
  79        return 0;
  80
  81err_ptce2_write:
  82        cregion->ops->entry_remove(cregion, centry);
  83        return err;
  84}
  85
  86static void
  87mlxsw_sp_acl_ctcam_region_entry_remove(struct mlxsw_sp *mlxsw_sp,
  88                                       struct mlxsw_sp_acl_ctcam_region *cregion,
  89                                       struct mlxsw_sp_acl_ctcam_entry *centry)
  90{
  91        char ptce2_pl[MLXSW_REG_PTCE2_LEN];
  92
  93        mlxsw_reg_ptce2_pack(ptce2_pl, false, MLXSW_REG_PTCE2_OP_WRITE_WRITE,
  94                             cregion->region->tcam_region_info,
  95                             centry->parman_item.index, 0);
  96        mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
  97        cregion->ops->entry_remove(cregion, centry);
  98}
  99
 100static int
 101mlxsw_sp_acl_ctcam_region_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
 102                                               struct mlxsw_sp_acl_ctcam_region *cregion,
 103                                               struct mlxsw_sp_acl_ctcam_entry *centry,
 104                                               struct mlxsw_afa_block *afa_block,
 105                                               unsigned int priority)
 106{
 107        char ptce2_pl[MLXSW_REG_PTCE2_LEN];
 108        char *act_set;
 109
 110        mlxsw_reg_ptce2_pack(ptce2_pl, true, MLXSW_REG_PTCE2_OP_WRITE_UPDATE,
 111                             cregion->region->tcam_region_info,
 112                             centry->parman_item.index, priority);
 113
 114        act_set = mlxsw_afa_block_first_set(afa_block);
 115        mlxsw_reg_ptce2_flex_action_set_memcpy_to(ptce2_pl, act_set);
 116
 117        return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(ptce2), ptce2_pl);
 118}
 119
 120
 121static int mlxsw_sp_acl_ctcam_region_parman_resize(void *priv,
 122                                                   unsigned long new_count)
 123{
 124        struct mlxsw_sp_acl_ctcam_region *cregion = priv;
 125        struct mlxsw_sp_acl_tcam_region *region = cregion->region;
 126        struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
 127        u64 max_tcam_rules;
 128
 129        max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
 130        if (new_count > max_tcam_rules)
 131                return -EINVAL;
 132        return mlxsw_sp_acl_ctcam_region_resize(mlxsw_sp, region, new_count);
 133}
 134
 135static void mlxsw_sp_acl_ctcam_region_parman_move(void *priv,
 136                                                  unsigned long from_index,
 137                                                  unsigned long to_index,
 138                                                  unsigned long count)
 139{
 140        struct mlxsw_sp_acl_ctcam_region *cregion = priv;
 141        struct mlxsw_sp_acl_tcam_region *region = cregion->region;
 142        struct mlxsw_sp *mlxsw_sp = region->mlxsw_sp;
 143
 144        mlxsw_sp_acl_ctcam_region_move(mlxsw_sp, region,
 145                                       from_index, to_index, count);
 146}
 147
 148static const struct parman_ops mlxsw_sp_acl_ctcam_region_parman_ops = {
 149        .base_count     = MLXSW_SP_ACL_TCAM_REGION_BASE_COUNT,
 150        .resize_step    = MLXSW_SP_ACL_TCAM_REGION_RESIZE_STEP,
 151        .resize         = mlxsw_sp_acl_ctcam_region_parman_resize,
 152        .move           = mlxsw_sp_acl_ctcam_region_parman_move,
 153        .algo           = PARMAN_ALGO_TYPE_LSORT,
 154};
 155
 156int
 157mlxsw_sp_acl_ctcam_region_init(struct mlxsw_sp *mlxsw_sp,
 158                               struct mlxsw_sp_acl_ctcam_region *cregion,
 159                               struct mlxsw_sp_acl_tcam_region *region,
 160                               const struct mlxsw_sp_acl_ctcam_region_ops *ops)
 161{
 162        cregion->region = region;
 163        cregion->ops = ops;
 164        cregion->parman = parman_create(&mlxsw_sp_acl_ctcam_region_parman_ops,
 165                                        cregion);
 166        if (!cregion->parman)
 167                return -ENOMEM;
 168        return 0;
 169}
 170
 171void mlxsw_sp_acl_ctcam_region_fini(struct mlxsw_sp_acl_ctcam_region *cregion)
 172{
 173        parman_destroy(cregion->parman);
 174}
 175
 176void mlxsw_sp_acl_ctcam_chunk_init(struct mlxsw_sp_acl_ctcam_region *cregion,
 177                                   struct mlxsw_sp_acl_ctcam_chunk *cchunk,
 178                                   unsigned int priority)
 179{
 180        parman_prio_init(cregion->parman, &cchunk->parman_prio, priority);
 181}
 182
 183void mlxsw_sp_acl_ctcam_chunk_fini(struct mlxsw_sp_acl_ctcam_chunk *cchunk)
 184{
 185        parman_prio_fini(&cchunk->parman_prio);
 186}
 187
 188int mlxsw_sp_acl_ctcam_entry_add(struct mlxsw_sp *mlxsw_sp,
 189                                 struct mlxsw_sp_acl_ctcam_region *cregion,
 190                                 struct mlxsw_sp_acl_ctcam_chunk *cchunk,
 191                                 struct mlxsw_sp_acl_ctcam_entry *centry,
 192                                 struct mlxsw_sp_acl_rule_info *rulei,
 193                                 bool fillup_priority)
 194{
 195        int err;
 196
 197        err = parman_item_add(cregion->parman, &cchunk->parman_prio,
 198                              &centry->parman_item);
 199        if (err)
 200                return err;
 201
 202        err = mlxsw_sp_acl_ctcam_region_entry_insert(mlxsw_sp, cregion, centry,
 203                                                     rulei, fillup_priority);
 204        if (err)
 205                goto err_rule_insert;
 206        return 0;
 207
 208err_rule_insert:
 209        parman_item_remove(cregion->parman, &cchunk->parman_prio,
 210                           &centry->parman_item);
 211        return err;
 212}
 213
 214void mlxsw_sp_acl_ctcam_entry_del(struct mlxsw_sp *mlxsw_sp,
 215                                  struct mlxsw_sp_acl_ctcam_region *cregion,
 216                                  struct mlxsw_sp_acl_ctcam_chunk *cchunk,
 217                                  struct mlxsw_sp_acl_ctcam_entry *centry)
 218{
 219        mlxsw_sp_acl_ctcam_region_entry_remove(mlxsw_sp, cregion, centry);
 220        parman_item_remove(cregion->parman, &cchunk->parman_prio,
 221                           &centry->parman_item);
 222}
 223
 224int mlxsw_sp_acl_ctcam_entry_action_replace(struct mlxsw_sp *mlxsw_sp,
 225                                            struct mlxsw_sp_acl_ctcam_region *cregion,
 226                                            struct mlxsw_sp_acl_ctcam_entry *centry,
 227                                            struct mlxsw_sp_acl_rule_info *rulei)
 228{
 229        return mlxsw_sp_acl_ctcam_region_entry_action_replace(mlxsw_sp, cregion,
 230                                                              centry,
 231                                                              rulei->act_block,
 232                                                              rulei->priority);
 233}
 234