mlxsw: spectrum_mr_tcam: Push Spectrum-specific operations into a separate file

Since Spectrum-2 has different handling of TCAM, push Spectrum MR TCAM
bits to a separate file accessible by ops which allows to implement
Spectrum-2 specific ops.

Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Signed-off-by: Ido Schimmel <idosch@mellanox.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jiri Pirko 2018-07-08 23:51:19 +03:00 committed by David S. Miller
parent 0304c00546
commit 8fae4392d4
7 changed files with 455 additions and 284 deletions

View File

@ -20,7 +20,8 @@ mlxsw_spectrum-objs := spectrum.o spectrum_buffers.o \
spectrum_flower.o spectrum_cnt.o \
spectrum_fid.o spectrum_ipip.o \
spectrum_acl_flex_actions.o \
spectrum_mr.o spectrum_mr_tcam.o \
spectrum1_mr_tcam.o \
spectrum_mr_tcam.o spectrum_mr.o \
spectrum_qdisc.o spectrum_span.o
mlxsw_spectrum-$(CONFIG_MLXSW_SPECTRUM_DCB) += spectrum_dcb.o
mlxsw_spectrum-$(CONFIG_NET_DEVLINK) += spectrum_dpipe.o

View File

@ -3623,6 +3623,7 @@ static int mlxsw_sp_init(struct mlxsw_core *mlxsw_core,
mlxsw_sp->kvdl_ops = &mlxsw_sp1_kvdl_ops;
mlxsw_sp->afa_ops = &mlxsw_sp1_act_afa_ops;
mlxsw_sp->mr_tcam_ops = &mlxsw_sp1_mr_tcam_ops;
mlxsw_sp->core = mlxsw_core;
mlxsw_sp->bus_info = mlxsw_bus_info;

View File

@ -146,6 +146,7 @@ struct mlxsw_sp_counter_pool;
struct mlxsw_sp_fid_core;
struct mlxsw_sp_kvdl;
struct mlxsw_sp_kvdl_ops;
struct mlxsw_sp_mr_tcam_ops;
struct mlxsw_sp {
struct mlxsw_sp_port **ports;
@ -171,6 +172,7 @@ struct mlxsw_sp {
} span;
const struct mlxsw_sp_kvdl_ops *kvdl_ops;
const struct mlxsw_afa_ops *afa_ops;
const struct mlxsw_sp_mr_tcam_ops *mr_tcam_ops;
};
static inline struct mlxsw_sp_upper *
@ -681,4 +683,37 @@ void mlxsw_sp_port_fids_fini(struct mlxsw_sp_port *mlxsw_sp_port);
int mlxsw_sp_fids_init(struct mlxsw_sp *mlxsw_sp);
void mlxsw_sp_fids_fini(struct mlxsw_sp *mlxsw_sp);
/* spectrum_mr.c */
enum mlxsw_sp_mr_route_prio {
MLXSW_SP_MR_ROUTE_PRIO_SG,
MLXSW_SP_MR_ROUTE_PRIO_STARG,
MLXSW_SP_MR_ROUTE_PRIO_CATCHALL,
__MLXSW_SP_MR_ROUTE_PRIO_MAX
};
#define MLXSW_SP_MR_ROUTE_PRIO_MAX (__MLXSW_SP_MR_ROUTE_PRIO_MAX - 1)
struct mlxsw_sp_mr_route_key;
struct mlxsw_sp_mr_tcam_ops {
size_t priv_size;
int (*init)(struct mlxsw_sp *mlxsw_sp, void *priv);
void (*fini)(void *priv);
size_t route_priv_size;
int (*route_create)(struct mlxsw_sp *mlxsw_sp, void *priv,
void *route_priv,
struct mlxsw_sp_mr_route_key *key,
struct mlxsw_afa_block *afa_block,
enum mlxsw_sp_mr_route_prio prio);
void (*route_destroy)(struct mlxsw_sp *mlxsw_sp, void *priv,
void *route_priv,
struct mlxsw_sp_mr_route_key *key);
int (*route_update)(struct mlxsw_sp *mlxsw_sp, void *route_priv,
struct mlxsw_sp_mr_route_key *key,
struct mlxsw_afa_block *afa_block);
};
/* spectrum1_mr_tcam.c */
extern const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops;
#endif

View File

@ -0,0 +1,374 @@
/*
* drivers/net/ethernet/mellanox/mlxsw/spectrum1_mr_tcam.c
* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
* Copyright (c) 2018 Jiri Pirko <jiri@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the names of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* Alternatively, this software may be distributed under the terms of the
* GNU General Public License ("GPL") version 2 as published by the Free
* Software Foundation.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <linux/kernel.h>
#include <linux/parman.h>
#include "reg.h"
#include "spectrum.h"
#include "core_acl_flex_actions.h"
#include "spectrum_mr.h"
struct mlxsw_sp1_mr_tcam_region {
struct mlxsw_sp *mlxsw_sp;
enum mlxsw_reg_rtar_key_type rtar_key_type;
struct parman *parman;
struct parman_prio *parman_prios;
};
struct mlxsw_sp1_mr_tcam {
struct mlxsw_sp1_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
};
struct mlxsw_sp1_mr_tcam_route {
struct parman_item parman_item;
struct parman_prio *parman_prio;
};
static int mlxsw_sp1_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
struct parman_item *parman_item,
struct mlxsw_sp_mr_route_key *key,
struct mlxsw_afa_block *afa_block)
{
char rmft2_pl[MLXSW_REG_RMFT2_LEN];
switch (key->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
key->vrid,
MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
ntohl(key->group.addr4),
ntohl(key->group_mask.addr4),
ntohl(key->source.addr4),
ntohl(key->source_mask.addr4),
mlxsw_afa_block_first_set(afa_block));
break;
case MLXSW_SP_L3_PROTO_IPV6:
mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
key->vrid,
MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
key->group.addr6,
key->group_mask.addr6,
key->source.addr6,
key->source_mask.addr6,
mlxsw_afa_block_first_set(afa_block));
}
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
}
static int mlxsw_sp1_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp,
struct parman_item *parman_item,
struct mlxsw_sp_mr_route_key *key)
{
struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
char rmft2_pl[MLXSW_REG_RMFT2_LEN];
switch (key->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
key->vrid, 0, 0, 0, 0, 0, 0, NULL);
break;
case MLXSW_SP_L3_PROTO_IPV6:
mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
key->vrid, 0, 0, zero_addr, zero_addr,
zero_addr, zero_addr, NULL);
break;
}
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
}
static struct mlxsw_sp1_mr_tcam_region *
mlxsw_sp1_mr_tcam_protocol_region(struct mlxsw_sp1_mr_tcam *mr_tcam,
enum mlxsw_sp_l3proto proto)
{
return &mr_tcam->tcam_regions[proto];
}
static int
mlxsw_sp1_mr_tcam_route_parman_item_add(struct mlxsw_sp1_mr_tcam *mr_tcam,
struct mlxsw_sp1_mr_tcam_route *route,
struct mlxsw_sp_mr_route_key *key,
enum mlxsw_sp_mr_route_prio prio)
{
struct mlxsw_sp1_mr_tcam_region *tcam_region;
int err;
tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
err = parman_item_add(tcam_region->parman,
&tcam_region->parman_prios[prio],
&route->parman_item);
if (err)
return err;
route->parman_prio = &tcam_region->parman_prios[prio];
return 0;
}
static void
mlxsw_sp1_mr_tcam_route_parman_item_remove(struct mlxsw_sp1_mr_tcam *mr_tcam,
struct mlxsw_sp1_mr_tcam_route *route,
struct mlxsw_sp_mr_route_key *key)
{
struct mlxsw_sp1_mr_tcam_region *tcam_region;
tcam_region = mlxsw_sp1_mr_tcam_protocol_region(mr_tcam, key->proto);
parman_item_remove(tcam_region->parman,
route->parman_prio, &route->parman_item);
}
static int
mlxsw_sp1_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
void *route_priv,
struct mlxsw_sp_mr_route_key *key,
struct mlxsw_afa_block *afa_block,
enum mlxsw_sp_mr_route_prio prio)
{
struct mlxsw_sp1_mr_tcam_route *route = route_priv;
struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
int err;
err = mlxsw_sp1_mr_tcam_route_parman_item_add(mr_tcam, route,
key, prio);
if (err)
return err;
err = mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
key, afa_block);
if (err)
goto err_route_replace;
return 0;
err_route_replace:
mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
return err;
}
static void
mlxsw_sp1_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp, void *priv,
void *route_priv,
struct mlxsw_sp_mr_route_key *key)
{
struct mlxsw_sp1_mr_tcam_route *route = route_priv;
struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
mlxsw_sp1_mr_tcam_route_remove(mlxsw_sp, &route->parman_item, key);
mlxsw_sp1_mr_tcam_route_parman_item_remove(mr_tcam, route, key);
}
static int
mlxsw_sp1_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp,
void *route_priv,
struct mlxsw_sp_mr_route_key *key,
struct mlxsw_afa_block *afa_block)
{
struct mlxsw_sp1_mr_tcam_route *route = route_priv;
return mlxsw_sp1_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
key, afa_block);
}
#define MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT 16
#define MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP 16
static int
mlxsw_sp1_mr_tcam_region_alloc(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
{
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rtar_pl[MLXSW_REG_RTAR_LEN];
mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
mr_tcam_region->rtar_key_type,
MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
}
static void
mlxsw_sp1_mr_tcam_region_free(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
{
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rtar_pl[MLXSW_REG_RTAR_LEN];
mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
mr_tcam_region->rtar_key_type, 0);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
}
static int mlxsw_sp1_mr_tcam_region_parman_resize(void *priv,
unsigned long new_count)
{
struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rtar_pl[MLXSW_REG_RTAR_LEN];
u64 max_tcam_rules;
max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
if (new_count > max_tcam_rules)
return -EINVAL;
mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
mr_tcam_region->rtar_key_type, new_count);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
}
static void mlxsw_sp1_mr_tcam_region_parman_move(void *priv,
unsigned long from_index,
unsigned long to_index,
unsigned long count)
{
struct mlxsw_sp1_mr_tcam_region *mr_tcam_region = priv;
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rrcr_pl[MLXSW_REG_RRCR_LEN];
mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
from_index, count,
mr_tcam_region->rtar_key_type, to_index);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
}
static const struct parman_ops mlxsw_sp1_mr_tcam_region_parman_ops = {
.base_count = MLXSW_SP1_MR_TCAM_REGION_BASE_COUNT,
.resize_step = MLXSW_SP1_MR_TCAM_REGION_RESIZE_STEP,
.resize = mlxsw_sp1_mr_tcam_region_parman_resize,
.move = mlxsw_sp1_mr_tcam_region_parman_move,
.algo = PARMAN_ALGO_TYPE_LSORT,
};
static int
mlxsw_sp1_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp1_mr_tcam_region *mr_tcam_region,
enum mlxsw_reg_rtar_key_type rtar_key_type)
{
struct parman_prio *parman_prios;
struct parman *parman;
int err;
int i;
mr_tcam_region->rtar_key_type = rtar_key_type;
mr_tcam_region->mlxsw_sp = mlxsw_sp;
err = mlxsw_sp1_mr_tcam_region_alloc(mr_tcam_region);
if (err)
return err;
parman = parman_create(&mlxsw_sp1_mr_tcam_region_parman_ops,
mr_tcam_region);
if (!parman) {
err = -ENOMEM;
goto err_parman_create;
}
mr_tcam_region->parman = parman;
parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
sizeof(*parman_prios), GFP_KERNEL);
if (!parman_prios) {
err = -ENOMEM;
goto err_parman_prios_alloc;
}
mr_tcam_region->parman_prios = parman_prios;
for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
parman_prio_init(mr_tcam_region->parman,
&mr_tcam_region->parman_prios[i], i);
return 0;
err_parman_prios_alloc:
parman_destroy(parman);
err_parman_create:
mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
return err;
}
static void
mlxsw_sp1_mr_tcam_region_fini(struct mlxsw_sp1_mr_tcam_region *mr_tcam_region)
{
int i;
for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
parman_prio_fini(&mr_tcam_region->parman_prios[i]);
kfree(mr_tcam_region->parman_prios);
parman_destroy(mr_tcam_region->parman);
mlxsw_sp1_mr_tcam_region_free(mr_tcam_region);
}
static int mlxsw_sp1_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
{
struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
u32 rtar_key;
int err;
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
return -EIO;
rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
&region[MLXSW_SP_L3_PROTO_IPV4],
rtar_key);
if (err)
return err;
rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
err = mlxsw_sp1_mr_tcam_region_init(mlxsw_sp,
&region[MLXSW_SP_L3_PROTO_IPV6],
rtar_key);
if (err)
goto err_ipv6_region_init;
return 0;
err_ipv6_region_init:
mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
return err;
}
static void mlxsw_sp1_mr_tcam_fini(void *priv)
{
struct mlxsw_sp1_mr_tcam *mr_tcam = priv;
struct mlxsw_sp1_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV6]);
mlxsw_sp1_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
}
const struct mlxsw_sp_mr_tcam_ops mlxsw_sp1_mr_tcam_ops = {
.priv_size = sizeof(struct mlxsw_sp1_mr_tcam),
.init = mlxsw_sp1_mr_tcam_init,
.fini = mlxsw_sp1_mr_tcam_fini,
.route_priv_size = sizeof(struct mlxsw_sp1_mr_tcam_route),
.route_create = mlxsw_sp1_mr_tcam_route_create,
.route_destroy = mlxsw_sp1_mr_tcam_route_destroy,
.route_update = mlxsw_sp1_mr_tcam_route_update,
};

View File

@ -1075,6 +1075,6 @@ void mlxsw_sp_mr_fini(struct mlxsw_sp *mlxsw_sp)
struct mlxsw_sp_mr *mr = mlxsw_sp->mr;
cancel_delayed_work_sync(&mr->stats_update_dw);
mr->mr_ops->fini(mr->priv);
mr->mr_ops->fini(mlxsw_sp, mr->priv);
kfree(mr);
}

View File

@ -46,15 +46,6 @@ enum mlxsw_sp_mr_route_action {
MLXSW_SP_MR_ROUTE_ACTION_TRAP_AND_FORWARD,
};
enum mlxsw_sp_mr_route_prio {
MLXSW_SP_MR_ROUTE_PRIO_SG,
MLXSW_SP_MR_ROUTE_PRIO_STARG,
MLXSW_SP_MR_ROUTE_PRIO_CATCHALL,
__MLXSW_SP_MR_ROUTE_PRIO_MAX
};
#define MLXSW_SP_MR_ROUTE_PRIO_MAX (__MLXSW_SP_MR_ROUTE_PRIO_MAX - 1)
struct mlxsw_sp_mr_route_key {
int vrid;
enum mlxsw_sp_l3proto proto;
@ -101,7 +92,7 @@ struct mlxsw_sp_mr_ops {
u16 erif_index);
void (*route_destroy)(struct mlxsw_sp *mlxsw_sp, void *priv,
void *route_priv);
void (*fini)(void *priv);
void (*fini)(struct mlxsw_sp *mlxsw_sp, void *priv);
};
struct mlxsw_sp_mr;

View File

@ -1,7 +1,8 @@
/*
* drivers/net/ethernet/mellanox/mlxsw/spectrum_mr_tcam.c
* Copyright (c) 2017 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017-2018 Mellanox Technologies. All rights reserved.
* Copyright (c) 2017 Yotam Gigi <yotamg@mellanox.com>
* Copyright (c) 2018 Jiri Pirko <jiri@mellanox.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@ -35,7 +36,6 @@
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/netdevice.h>
#include <linux/parman.h>
#include "spectrum_mr_tcam.h"
#include "reg.h"
@ -43,15 +43,8 @@
#include "core_acl_flex_actions.h"
#include "spectrum_mr.h"
struct mlxsw_sp_mr_tcam_region {
struct mlxsw_sp *mlxsw_sp;
enum mlxsw_reg_rtar_key_type rtar_key_type;
struct parman *parman;
struct parman_prio *parman_prios;
};
struct mlxsw_sp_mr_tcam {
struct mlxsw_sp_mr_tcam_region tcam_regions[MLXSW_SP_L3_PROTO_MAX];
void *priv;
};
/* This struct maps to one RIGR2 register entry */
@ -220,12 +213,11 @@ struct mlxsw_sp_mr_tcam_route {
struct mlxsw_sp_mr_tcam_erif_list erif_list;
struct mlxsw_afa_block *afa_block;
u32 counter_index;
struct parman_item parman_item;
struct parman_prio *parman_prio;
enum mlxsw_sp_mr_route_action action;
struct mlxsw_sp_mr_route_key key;
u16 irif_index;
u16 min_mtu;
void *priv;
};
static struct mlxsw_afa_block *
@ -296,60 +288,6 @@ mlxsw_sp_mr_tcam_afa_block_destroy(struct mlxsw_afa_block *afa_block)
mlxsw_afa_block_destroy(afa_block);
}
static int mlxsw_sp_mr_tcam_route_replace(struct mlxsw_sp *mlxsw_sp,
struct parman_item *parman_item,
struct mlxsw_sp_mr_route_key *key,
struct mlxsw_afa_block *afa_block)
{
char rmft2_pl[MLXSW_REG_RMFT2_LEN];
switch (key->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, true, parman_item->index,
key->vrid,
MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
ntohl(key->group.addr4),
ntohl(key->group_mask.addr4),
ntohl(key->source.addr4),
ntohl(key->source_mask.addr4),
mlxsw_afa_block_first_set(afa_block));
break;
case MLXSW_SP_L3_PROTO_IPV6:
mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, true, parman_item->index,
key->vrid,
MLXSW_REG_RMFT2_IRIF_MASK_IGNORE, 0,
key->group.addr6,
key->group_mask.addr6,
key->source.addr6,
key->source_mask.addr6,
mlxsw_afa_block_first_set(afa_block));
}
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
}
static int mlxsw_sp_mr_tcam_route_remove(struct mlxsw_sp *mlxsw_sp, int vrid,
struct mlxsw_sp_mr_route_key *key,
struct parman_item *parman_item)
{
struct in6_addr zero_addr = IN6ADDR_ANY_INIT;
char rmft2_pl[MLXSW_REG_RMFT2_LEN];
switch (key->proto) {
case MLXSW_SP_L3_PROTO_IPV4:
mlxsw_reg_rmft2_ipv4_pack(rmft2_pl, false, parman_item->index,
vrid, 0, 0, 0, 0, 0, 0, NULL);
break;
case MLXSW_SP_L3_PROTO_IPV6:
mlxsw_reg_rmft2_ipv6_pack(rmft2_pl, false, parman_item->index,
vrid, 0, 0, zero_addr, zero_addr,
zero_addr, zero_addr, NULL);
break;
}
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rmft2), rmft2_pl);
}
static int
mlxsw_sp_mr_tcam_erif_populate(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mr_tcam_erif_list *erif_list,
@ -369,51 +307,12 @@ mlxsw_sp_mr_tcam_erif_populate(struct mlxsw_sp *mlxsw_sp,
return 0;
}
static struct mlxsw_sp_mr_tcam_region *
mlxsw_sp_mr_tcam_protocol_region(struct mlxsw_sp_mr_tcam *mr_tcam,
enum mlxsw_sp_l3proto proto)
{
return &mr_tcam->tcam_regions[proto];
}
static int
mlxsw_sp_mr_tcam_route_parman_item_add(struct mlxsw_sp_mr_tcam *mr_tcam,
struct mlxsw_sp_mr_tcam_route *route,
enum mlxsw_sp_mr_route_prio prio)
{
struct mlxsw_sp_mr_tcam_region *tcam_region;
int err;
tcam_region = mlxsw_sp_mr_tcam_protocol_region(mr_tcam,
route->key.proto);
err = parman_item_add(tcam_region->parman,
&tcam_region->parman_prios[prio],
&route->parman_item);
if (err)
return err;
route->parman_prio = &tcam_region->parman_prios[prio];
return 0;
}
static void
mlxsw_sp_mr_tcam_route_parman_item_remove(struct mlxsw_sp_mr_tcam *mr_tcam,
struct mlxsw_sp_mr_tcam_route *route)
{
struct mlxsw_sp_mr_tcam_region *tcam_region;
tcam_region = mlxsw_sp_mr_tcam_protocol_region(mr_tcam,
route->key.proto);
parman_item_remove(tcam_region->parman,
route->parman_prio, &route->parman_item);
}
static int
mlxsw_sp_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
void *route_priv,
struct mlxsw_sp_mr_route_params *route_params)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam_route *route = route_priv;
struct mlxsw_sp_mr_tcam *mr_tcam = priv;
int err;
@ -447,22 +346,23 @@ mlxsw_sp_mr_tcam_route_create(struct mlxsw_sp *mlxsw_sp, void *priv,
goto err_afa_block_create;
}
/* Allocate place in the TCAM */
err = mlxsw_sp_mr_tcam_route_parman_item_add(mr_tcam, route,
route_params->prio);
if (err)
goto err_parman_item_add;
route->priv = kzalloc(ops->route_priv_size, GFP_KERNEL);
if (!route->priv) {
err = -ENOMEM;
goto err_route_priv_alloc;
}
/* Write the route to the TCAM */
err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
&route->key, route->afa_block);
err = ops->route_create(mlxsw_sp, mr_tcam->priv, route->priv,
&route->key, route->afa_block,
route_params->prio);
if (err)
goto err_route_replace;
goto err_route_create;
return 0;
err_route_replace:
mlxsw_sp_mr_tcam_route_parman_item_remove(mr_tcam, route);
err_parman_item_add:
err_route_create:
kfree(route->priv);
err_route_priv_alloc:
mlxsw_sp_mr_tcam_afa_block_destroy(route->afa_block);
err_afa_block_create:
mlxsw_sp_flow_counter_free(mlxsw_sp, route->counter_index);
@ -475,12 +375,12 @@ err_counter_alloc:
static void mlxsw_sp_mr_tcam_route_destroy(struct mlxsw_sp *mlxsw_sp,
void *priv, void *route_priv)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam_route *route = route_priv;
struct mlxsw_sp_mr_tcam *mr_tcam = priv;
mlxsw_sp_mr_tcam_route_remove(mlxsw_sp, route->key.vrid,
&route->key, &route->parman_item);
mlxsw_sp_mr_tcam_route_parman_item_remove(mr_tcam, route);
ops->route_destroy(mlxsw_sp, mr_tcam->priv, route->priv, &route->key);
kfree(route->priv);
mlxsw_sp_mr_tcam_afa_block_destroy(route->afa_block);
mlxsw_sp_flow_counter_free(mlxsw_sp, route->counter_index);
mlxsw_sp_mr_erif_list_flush(mlxsw_sp, &route->erif_list);
@ -501,6 +401,7 @@ mlxsw_sp_mr_tcam_route_action_update(struct mlxsw_sp *mlxsw_sp,
void *route_priv,
enum mlxsw_sp_mr_route_action route_action)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam_route *route = route_priv;
struct mlxsw_afa_block *afa_block;
int err;
@ -515,8 +416,7 @@ mlxsw_sp_mr_tcam_route_action_update(struct mlxsw_sp *mlxsw_sp,
return PTR_ERR(afa_block);
/* Update the TCAM route entry */
err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
&route->key, afa_block);
err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
if (err)
goto err;
@ -533,6 +433,7 @@ err:
static int mlxsw_sp_mr_tcam_route_min_mtu_update(struct mlxsw_sp *mlxsw_sp,
void *route_priv, u16 min_mtu)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam_route *route = route_priv;
struct mlxsw_afa_block *afa_block;
int err;
@ -548,8 +449,7 @@ static int mlxsw_sp_mr_tcam_route_min_mtu_update(struct mlxsw_sp *mlxsw_sp,
return PTR_ERR(afa_block);
/* Update the TCAM route entry */
err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
&route->key, afa_block);
err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
if (err)
goto err;
@ -595,6 +495,7 @@ static int mlxsw_sp_mr_tcam_route_erif_add(struct mlxsw_sp *mlxsw_sp,
static int mlxsw_sp_mr_tcam_route_erif_del(struct mlxsw_sp *mlxsw_sp,
void *route_priv, u16 erif_index)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam_route *route = route_priv;
struct mlxsw_sp_mr_erif_sublist *erif_sublist;
struct mlxsw_sp_mr_tcam_erif_list erif_list;
@ -629,8 +530,7 @@ static int mlxsw_sp_mr_tcam_route_erif_del(struct mlxsw_sp *mlxsw_sp,
}
/* Update the TCAM route entry */
err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
&route->key, afa_block);
err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
if (err)
goto err_route_write;
@ -652,6 +552,7 @@ static int
mlxsw_sp_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp, void *route_priv,
struct mlxsw_sp_mr_route_info *route_info)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam_route *route = route_priv;
struct mlxsw_sp_mr_tcam_erif_list erif_list;
struct mlxsw_afa_block *afa_block;
@ -676,8 +577,7 @@ mlxsw_sp_mr_tcam_route_update(struct mlxsw_sp *mlxsw_sp, void *route_priv,
}
/* Update the TCAM route entry */
err = mlxsw_sp_mr_tcam_route_replace(mlxsw_sp, &route->parman_item,
&route->key, afa_block);
err = ops->route_update(mlxsw_sp, route->priv, &route->key, afa_block);
if (err)
goto err_route_write;
@ -698,167 +598,36 @@ err_erif_populate:
return err;
}
#define MLXSW_SP_MR_TCAM_REGION_BASE_COUNT 16
#define MLXSW_SP_MR_TCAM_REGION_RESIZE_STEP 16
static int
mlxsw_sp_mr_tcam_region_alloc(struct mlxsw_sp_mr_tcam_region *mr_tcam_region)
{
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rtar_pl[MLXSW_REG_RTAR_LEN];
mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_ALLOCATE,
mr_tcam_region->rtar_key_type,
MLXSW_SP_MR_TCAM_REGION_BASE_COUNT);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
}
static void
mlxsw_sp_mr_tcam_region_free(struct mlxsw_sp_mr_tcam_region *mr_tcam_region)
{
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rtar_pl[MLXSW_REG_RTAR_LEN];
mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_DEALLOCATE,
mr_tcam_region->rtar_key_type, 0);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
}
static int mlxsw_sp_mr_tcam_region_parman_resize(void *priv,
unsigned long new_count)
{
struct mlxsw_sp_mr_tcam_region *mr_tcam_region = priv;
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rtar_pl[MLXSW_REG_RTAR_LEN];
u64 max_tcam_rules;
max_tcam_rules = MLXSW_CORE_RES_GET(mlxsw_sp->core, ACL_MAX_TCAM_RULES);
if (new_count > max_tcam_rules)
return -EINVAL;
mlxsw_reg_rtar_pack(rtar_pl, MLXSW_REG_RTAR_OP_RESIZE,
mr_tcam_region->rtar_key_type, new_count);
return mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rtar), rtar_pl);
}
static void mlxsw_sp_mr_tcam_region_parman_move(void *priv,
unsigned long from_index,
unsigned long to_index,
unsigned long count)
{
struct mlxsw_sp_mr_tcam_region *mr_tcam_region = priv;
struct mlxsw_sp *mlxsw_sp = mr_tcam_region->mlxsw_sp;
char rrcr_pl[MLXSW_REG_RRCR_LEN];
mlxsw_reg_rrcr_pack(rrcr_pl, MLXSW_REG_RRCR_OP_MOVE,
from_index, count,
mr_tcam_region->rtar_key_type, to_index);
mlxsw_reg_write(mlxsw_sp->core, MLXSW_REG(rrcr), rrcr_pl);
}
static const struct parman_ops mlxsw_sp_mr_tcam_region_parman_ops = {
.base_count = MLXSW_SP_MR_TCAM_REGION_BASE_COUNT,
.resize_step = MLXSW_SP_MR_TCAM_REGION_RESIZE_STEP,
.resize = mlxsw_sp_mr_tcam_region_parman_resize,
.move = mlxsw_sp_mr_tcam_region_parman_move,
.algo = PARMAN_ALGO_TYPE_LSORT,
};
static int
mlxsw_sp_mr_tcam_region_init(struct mlxsw_sp *mlxsw_sp,
struct mlxsw_sp_mr_tcam_region *mr_tcam_region,
enum mlxsw_reg_rtar_key_type rtar_key_type)
{
struct parman_prio *parman_prios;
struct parman *parman;
int err;
int i;
mr_tcam_region->rtar_key_type = rtar_key_type;
mr_tcam_region->mlxsw_sp = mlxsw_sp;
err = mlxsw_sp_mr_tcam_region_alloc(mr_tcam_region);
if (err)
return err;
parman = parman_create(&mlxsw_sp_mr_tcam_region_parman_ops,
mr_tcam_region);
if (!parman) {
err = -ENOMEM;
goto err_parman_create;
}
mr_tcam_region->parman = parman;
parman_prios = kmalloc_array(MLXSW_SP_MR_ROUTE_PRIO_MAX + 1,
sizeof(*parman_prios), GFP_KERNEL);
if (!parman_prios) {
err = -ENOMEM;
goto err_parman_prios_alloc;
}
mr_tcam_region->parman_prios = parman_prios;
for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
parman_prio_init(mr_tcam_region->parman,
&mr_tcam_region->parman_prios[i], i);
return 0;
err_parman_prios_alloc:
parman_destroy(parman);
err_parman_create:
mlxsw_sp_mr_tcam_region_free(mr_tcam_region);
return err;
}
static void
mlxsw_sp_mr_tcam_region_fini(struct mlxsw_sp_mr_tcam_region *mr_tcam_region)
{
int i;
for (i = 0; i < MLXSW_SP_MR_ROUTE_PRIO_MAX + 1; i++)
parman_prio_fini(&mr_tcam_region->parman_prios[i]);
kfree(mr_tcam_region->parman_prios);
parman_destroy(mr_tcam_region->parman);
mlxsw_sp_mr_tcam_region_free(mr_tcam_region);
}
static int mlxsw_sp_mr_tcam_init(struct mlxsw_sp *mlxsw_sp, void *priv)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam *mr_tcam = priv;
struct mlxsw_sp_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
u32 rtar_key;
int err;
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MC_ERIF_LIST_ENTRIES) ||
!MLXSW_CORE_RES_VALID(mlxsw_sp->core, ACL_MAX_TCAM_RULES))
if (!MLXSW_CORE_RES_VALID(mlxsw_sp->core, MC_ERIF_LIST_ENTRIES))
return -EIO;
rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV4_MULTICAST;
err = mlxsw_sp_mr_tcam_region_init(mlxsw_sp,
&region[MLXSW_SP_L3_PROTO_IPV4],
rtar_key);
if (err)
return err;
mr_tcam->priv = kzalloc(ops->priv_size, GFP_KERNEL);
if (!mr_tcam->priv)
return -ENOMEM;
rtar_key = MLXSW_REG_RTAR_KEY_TYPE_IPV6_MULTICAST;
err = mlxsw_sp_mr_tcam_region_init(mlxsw_sp,
&region[MLXSW_SP_L3_PROTO_IPV6],
rtar_key);
err = ops->init(mlxsw_sp, mr_tcam->priv);
if (err)
goto err_ipv6_region_init;
goto err_init;
return 0;
err_ipv6_region_init:
mlxsw_sp_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
err_init:
kfree(mr_tcam->priv);
return err;
}
static void mlxsw_sp_mr_tcam_fini(void *priv)
static void mlxsw_sp_mr_tcam_fini(struct mlxsw_sp *mlxsw_sp, void *priv)
{
const struct mlxsw_sp_mr_tcam_ops *ops = mlxsw_sp->mr_tcam_ops;
struct mlxsw_sp_mr_tcam *mr_tcam = priv;
struct mlxsw_sp_mr_tcam_region *region = &mr_tcam->tcam_regions[0];
mlxsw_sp_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV6]);
mlxsw_sp_mr_tcam_region_fini(&region[MLXSW_SP_L3_PROTO_IPV4]);
ops->fini(mr_tcam->priv);
kfree(mr_tcam->priv);
}
const struct mlxsw_sp_mr_ops mlxsw_sp_mr_tcam_ops = {