linux/drivers/net/ethernet/mellanox/mlxsw/spectrum1_mr_tcam.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/parman.h>
   6
   7#include "reg.h"
   8#include "spectrum.h"
   9#include "core_acl_flex_actions.h"
  10#include "spectrum_mr.h"
  11
  12struct 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
  19struct mlxsw_sp1_mr_tcam {
  20        struct mlxsw_sp1_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
  21};
  22
  23struct mlxsw_sp1_mr_tcam_route {
  24        struct parman_item parman_item;
  25        struct parman_prio *parman_prio;
  26};
  27
  28static 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
  60static 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
  82static struct mlxsw_sp1_mr_tcam_region *
  83mlxsw_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
  89static int
  90mlxsw_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
 109static void
 110mlxsw_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
 121static int
 122mlxsw_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
 143err_route_replace:
 144        mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
 145        return err;
 146}
 147
 148static void
 149mlxsw_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
 160static int
 161mlxsw_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
 175static int
 176mlxsw_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
 187static void
 188mlxsw_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
 198static 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
 214static 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
 229static 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
 237static int
 238mlxsw_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
 275err_parman_prios_alloc:
 276        parman_destroy(parman);
 277err_parman_create:
 278        mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
 279        return err;
 280}
 281
 282static void
 283mlxsw_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
 294static 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
 320err_ipv6_region_init:
 321        mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
 322        return err;
 323}
 324
 325static 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
 334const 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};
 343