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

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

DEFINITIONS

This source file includes following definitions.
  1. mlxsw_sp1_mr_tcam_route_replace
  2. mlxsw_sp1_mr_tcam_route_remove
  3. mlxsw_sp1_mr_tcam_protocol_region
  4. mlxsw_sp1_mr_tcam_route_parman_item_add
  5. mlxsw_sp1_mr_tcam_route_parman_item_remove
  6. mlxsw_sp1_mr_tcam_route_create
  7. mlxsw_sp1_mr_tcam_route_destroy
  8. mlxsw_sp1_mr_tcam_route_update
  9. mlxsw_sp1_mr_tcam_region_alloc
  10. mlxsw_sp1_mr_tcam_region_free
  11. mlxsw_sp1_mr_tcam_region_parman_resize
  12. mlxsw_sp1_mr_tcam_region_parman_move
  13. mlxsw_sp1_mr_tcam_region_init
  14. mlxsw_sp1_mr_tcam_region_fini
  15. mlxsw_sp1_mr_tcam_init
  16. mlxsw_sp1_mr_tcam_fini

   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/parman.h>
   6 
   7 #include "reg.h"
   8 #include "spectrum.h"
   9 #include "core_acl_flex_actions.h"
  10 #include "spectrum_mr.h"
  11 
  12 struct mlxsw_sp1_mr_tcam_region {
  13         struct mlxsw_sp *mlxsw_sp;
  14         enum mlxsw_reg_rtar_key_type rtar_key_type;
  15         struct parman *parman;
  16         struct parman_prio *parman_prios;
  17 };
  18 
  19 struct mlxsw_sp1_mr_tcam {
  20         struct mlxsw_sp1_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
  21 };
  22 
  23 struct mlxsw_sp1_mr_tcam_route {
  24         struct parman_item parman_item;
  25         struct parman_prio *parman_prio;
  26 };
  27 
  28 static int mlxsw_sp1_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
  29                                            struct parman_item *parman_item,
  30                                            struct mlxsw_sp_mr_route_key *key,
  31                                            struct mlxsw_afa_block *afa_block)
  32 {
  33         char rmft2_pl[MLXSW_REG_RMFT2_LEN];
  34 
  35         switch (key->proto) {
  36         case MLXSW_SP_L3_PROTO_IPV4:
  37                 mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
  38                                           key->vrid,
  39                                           MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
  40                                           ntohl(key->group.addr4),
  41                                           ntohl(key->group_mask.addr4),
  42                                           ntohl(key->source.addr4),
  43                                           ntohl(key->source_mask.addr4),
  44                                           mlxsw_afa_block_first_set(afa_block));
  45                 break;
  46         case MLXSW_SP_L3_PROTO_IPV6:
  47                 mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
  48                                           key->vrid,
  49                                           MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
  50                                           key->group.addr6,
  51                                           key->group_mask.addr6,
  52                                           key->source.addr6,
  53                                           key->source_mask.addr6,
  54                                           mlxsw_afa_block_first_set(afa_block));
  55         }
  56 
  57         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
  58 }
  59 
  60 static int mlxsw_sp1_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp,
  61                                           struct parman_item *parman_item,
  62                                           struct mlxsw_sp_mr_route_key *key)
  63 {
  64         struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
  65         char rmft2_pl[MLXSW_REG_RMFT2_LEN];
  66 
  67         switch (key->proto) {
  68         case MLXSW_SP_L3_PROTO_IPV4:
  69                 mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
  70                                           key->vrid, 0, 0, 0, 0, 0, 0, NULL);
  71                 break;
  72         case MLXSW_SP_L3_PROTO_IPV6:
  73                 mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
  74                                           key->vrid, 0, 0, zero_addr, zero_addr,
  75                                           zero_addr, zero_addr, NULL);
  76                 break;
  77         }
  78 
  79         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
  80 }
  81 
  82 static struct mlxsw_sp1_mr_tcam_region *
  83 mlxsw_sp1_mr_tcam_protocol_region(struct mlxsw_sp1_mr_tcam *mr_tcam,
  84                                   enum mlxsw_sp_l3proto proto)
  85 {
  86         return &mr_tcam->tcam_regions[proto];
  87 }
  88 
  89 static int
  90 mlxsw_sp1_mr_tcam_route_parman_item_add(struct mlxsw_sp1_mr_tcam *mr_tcam,
  91                                         struct mlxsw_sp1_mr_tcam_route *route,
  92                                         struct mlxsw_sp_mr_route_key *key,
  93                                         enum mlxsw_sp_mr_route_prio prio)
  94 {
  95         struct mlxsw_sp1_mr_tcam_region *tcam_region;
  96         int err;
  97 
  98         tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
  99         err = parman_item_add(tcam_region->parman,
 100                               &tcam_region->parman_prios[prio],
 101                               &route->parman_item);
 102         if (err)
 103                 return err;
 104 
 105         route->parman_prio = &tcam_region->parman_prios[prio];
 106         return 0;
 107 }
 108 
 109 static void
 110 mlxsw_sp1_mr_tcam_route_parman_item_remove(struct mlxsw_sp1_mr_tcam *mr_tcam,
 111                                            struct mlxsw_sp1_mr_tcam_route *route,
 112                                            struct mlxsw_sp_mr_route_key *key)
 113 {
 114         struct mlxsw_sp1_mr_tcam_region *tcam_region;
 115 
 116         tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
 117         parman_item_remove(tcam_region->parman,
 118                            route->parman_prio, &route->parman_item);
 119 }
 120 
 121 static int
 122 mlxsw_sp1_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
 123                                void *route_priv,
 124                                struct mlxsw_sp_mr_route_key *key,
 125                                struct mlxsw_afa_block *afa_block,
 126                                enum mlxsw_sp_mr_route_prio prio)
 127 {
 128         struct mlxsw_sp1_mr_tcam_route *route = route_priv;
 129         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
 130         int err;
 131 
 132         err = mlxsw_sp1_mr_tcam_route_parman_item_add(mr_tcam, route,
 133                                                       key, prio);
 134         if (err)
 135                 return err;
 136 
 137         err = mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
 138                                               key, afa_block);
 139         if (err)
 140                 goto err_route_replace;
 141         return 0;
 142 
 143 err_route_replace:
 144         mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
 145         return err;
 146 }
 147 
 148 static void
 149 mlxsw_sp1_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
 150                                 void *route_priv,
 151                                 struct mlxsw_sp_mr_route_key *key)
 152 {
 153         struct mlxsw_sp1_mr_tcam_route *route = route_priv;
 154         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
 155 
 156         mlxsw_sp1_mr_tcam_route_remove(mlxsw_sp, &route->parman_item, key);
 157         mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
 158 }
 159 
 160 static int
 161 mlxsw_sp1_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
 162                                void *route_priv,
 163                                struct mlxsw_sp_mr_route_key *key,
 164                                struct mlxsw_afa_block *afa_block)
 165 {
 166         struct mlxsw_sp1_mr_tcam_route *route = route_priv;
 167 
 168         return mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
 169                                                key, afa_block);
 170 }
 171 
 172 #define MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT 16
 173 #define MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP 16
 174 
 175 static int
 176 mlxsw_sp1_mr_tcam_region_alloc(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
 177 {
 178         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
 179         char rtar_pl[MLXSW_REG_RTAR_LEN];
 180 
 181         mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
 182                             mr_tcam_region->rtar_key_type,
 183                             MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT);
 184         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
 185 }
 186 
 187 static void
 188 mlxsw_sp1_mr_tcam_region_free(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
 189 {
 190         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
 191         char rtar_pl[MLXSW_REG_RTAR_LEN];
 192 
 193         mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
 194                             mr_tcam_region->rtar_key_type, 0);
 195         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
 196 }
 197 
 198 static int mlxsw_sp1_mr_tcam_region_parman_resize(void *priv,
 199                                                   unsigned long new_count)
 200 {
 201         struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
 202         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
 203         char rtar_pl[MLXSW_REG_RTAR_LEN];
 204         u64 max_tcam_rules;
 205 
 206         max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
 207         if (new_count > max_tcam_rules)
 208                 return -EINVAL;
 209         mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
 210                             mr_tcam_region->rtar_key_type, new_count);
 211         return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
 212 }
 213 
 214 static void mlxsw_sp1_mr_tcam_region_parman_move(void *priv,
 215                                                  unsigned long from_index,
 216                                                  unsigned long to_index,
 217                                                  unsigned long count)
 218 {
 219         struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
 220         struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
 221         char rrcr_pl[MLXSW_REG_RRCR_LEN];
 222 
 223         mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
 224                             from_index, count,
 225                             mr_tcam_region->rtar_key_type, to_index);
 226         mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
 227 }
 228 
 229 static const struct parman_ops mlxsw_sp1_mr_tcam_region_parman_ops = {
 230         .base_count     = MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT,
 231         .resize_step    = MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP,
 232         .resize         = mlxsw_sp1_mr_tcam_region_parman_resize,
 233         .move           = mlxsw_sp1_mr_tcam_region_parman_move,
 234         .algo           = PARMAN_ALGO_TYPE_LSORT,
 235 };
 236 
 237 static int
 238 mlxsw_sp1_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
 239                               struct mlxsw_sp1_mr_tcam_region *mr_tcam_region,
 240                               enum mlxsw_reg_rtar_key_type rtar_key_type)
 241 {
 242         struct parman_prio *parman_prios;
 243         struct parman *parman;
 244         int err;
 245         int i;
 246 
 247         mr_tcam_region->rtar_key_type = rtar_key_type;
 248         mr_tcam_region->mlxsw_sp = mlxsw_sp;
 249 
 250         err = mlxsw_sp1_mr_tcam_region_alloc(mr_tcam_region);
 251         if (err)
 252                 return err;
 253 
 254         parman = parman_create(&mlxsw_sp1_mr_tcam_region_parman_ops,
 255                                mr_tcam_region);
 256         if (!parman) {
 257                 err = -ENOMEM;
 258                 goto err_parman_create;
 259         }
 260         mr_tcam_region->parman = parman;
 261 
 262         parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
 263                                      sizeof(*parman_prios), GFP_KERNEL);
 264         if (!parman_prios) {
 265                 err = -ENOMEM;
 266                 goto err_parman_prios_alloc;
 267         }
 268         mr_tcam_region->parman_prios = parman_prios;
 269 
 270         for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
 271                 parman_prio_init(mr_tcam_region->parman,
 272                                  &mr_tcam_region->parman_prios[i], i);
 273         return 0;
 274 
 275 err_parman_prios_alloc:
 276         parman_destroy(parman);
 277 err_parman_create:
 278         mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
 279         return err;
 280 }
 281 
 282 static void
 283 mlxsw_sp1_mr_tcam_region_fini(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
 284 {
 285         int i;
 286 
 287         for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
 288                 parman_prio_fini(&mr_tcam_region->parman_prios[i]);
 289         kfree(mr_tcam_region->parman_prios);
 290         parman_destroy(mr_tcam_region->parman);
 291         mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
 292 }
 293 
 294 static int mlxsw_sp1_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
 295 {
 296         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
 297         struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
 298         u32 rtar_key;
 299         int err;
 300 
 301         if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
 302                 return -EIO;
 303 
 304         rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
 305         err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
 306                                             &region[MLXSW_SP_L3_PROTO_IPV4],
 307                                             rtar_key);
 308         if (err)
 309                 return err;
 310 
 311         rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
 312         err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
 313                                             &region[MLXSW_SP_L3_PROTO_IPV6],
 314                                             rtar_key);
 315         if (err)
 316                 goto err_ipv6_region_init;
 317 
 318         return 0;
 319 
 320 err_ipv6_region_init:
 321         mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
 322         return err;
 323 }
 324 
 325 static void mlxsw_sp1_mr_tcam_fini(void *priv)
 326 {
 327         struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
 328         struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
 329 
 330         mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV6]);
 331         mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
 332 }
 333 
 334 const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops = {
 335         .priv_size = sizeof(struct mlxsw_sp1_mr_tcam),
 336         .init = mlxsw_sp1_mr_tcam_init,
 337         .fini = mlxsw_sp1_mr_tcam_fini,
 338         .route_priv_size = sizeof(struct mlxsw_sp1_mr_tcam_route),
 339         .route_create = mlxsw_sp1_mr_tcam_route_create,
 340         .route_destroy = mlxsw_sp1_mr_tcam_route_destroy,
 341         .route_update = mlxsw_sp1_mr_tcam_route_update,
 342 };

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