-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
net/mlx5: DR, Expose steering table functionality
Tables are objects which are used for storing matchers, each table belongs to a domain and defined by the domain type. When a packet reaches the table it is being processed by each of its matchers until a successful match. Tables can hold multiple matchers ordered by matcher priority. Each table has a level. Signed-off-by: Alex Vesker <valex@mellanox.com> Reviewed-by: Erez Shitrit <erezsh@mellanox.com> Reviewed-by: Mark Bloch <markb@mellanox.com> Signed-off-by: Saeed Mahameed <saeedm@mellanox.com>
- Loading branch information
Alex Vesker
authored and
Saeed Mahameed
committed
Sep 3, 2019
1 parent
4ec9e7b
commit 7838e17
Showing
1 changed file
with
294 additions
and
0 deletions.
There are no files selected for viewing
294 changes: 294 additions & 0 deletions
294
drivers/net/ethernet/mellanox/mlx5/core/steering/dr_table.c
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,294 @@ | ||
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB | ||
/* Copyright (c) 2019 Mellanox Technologies. */ | ||
|
||
#include "dr_types.h" | ||
|
||
int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl, | ||
struct mlx5dr_action *action) | ||
{ | ||
struct mlx5dr_matcher *last_matcher = NULL; | ||
struct mlx5dr_htbl_connect_info info; | ||
struct mlx5dr_ste_htbl *last_htbl; | ||
int ret; | ||
|
||
if (action && action->action_type != DR_ACTION_TYP_FT) | ||
return -EOPNOTSUPP; | ||
|
||
mutex_lock(&tbl->dmn->mutex); | ||
|
||
if (!list_empty(&tbl->matcher_list)) | ||
last_matcher = list_last_entry(&tbl->matcher_list, | ||
struct mlx5dr_matcher, | ||
matcher_list); | ||
|
||
if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX || | ||
tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) { | ||
if (last_matcher) | ||
last_htbl = last_matcher->rx.e_anchor; | ||
else | ||
last_htbl = tbl->rx.s_anchor; | ||
|
||
tbl->rx.default_icm_addr = action ? | ||
action->dest_tbl.tbl->rx.s_anchor->chunk->icm_addr : | ||
tbl->rx.nic_dmn->default_icm_addr; | ||
|
||
info.type = CONNECT_MISS; | ||
info.miss_icm_addr = tbl->rx.default_icm_addr; | ||
|
||
ret = mlx5dr_ste_htbl_init_and_postsend(tbl->dmn, | ||
tbl->rx.nic_dmn, | ||
last_htbl, | ||
&info, true); | ||
if (ret) { | ||
mlx5dr_dbg(tbl->dmn, "Failed to set RX miss action, ret %d\n", ret); | ||
goto out; | ||
} | ||
} | ||
|
||
if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX || | ||
tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) { | ||
if (last_matcher) | ||
last_htbl = last_matcher->tx.e_anchor; | ||
else | ||
last_htbl = tbl->tx.s_anchor; | ||
|
||
tbl->tx.default_icm_addr = action ? | ||
action->dest_tbl.tbl->tx.s_anchor->chunk->icm_addr : | ||
tbl->tx.nic_dmn->default_icm_addr; | ||
|
||
info.type = CONNECT_MISS; | ||
info.miss_icm_addr = tbl->tx.default_icm_addr; | ||
|
||
ret = mlx5dr_ste_htbl_init_and_postsend(tbl->dmn, | ||
tbl->tx.nic_dmn, | ||
last_htbl, &info, true); | ||
if (ret) { | ||
mlx5dr_dbg(tbl->dmn, "Failed to set TX miss action, ret %d\n", ret); | ||
goto out; | ||
} | ||
} | ||
|
||
/* Release old action */ | ||
if (tbl->miss_action) | ||
refcount_dec(&tbl->miss_action->refcount); | ||
|
||
/* Set new miss action */ | ||
tbl->miss_action = action; | ||
if (tbl->miss_action) | ||
refcount_inc(&action->refcount); | ||
|
||
out: | ||
mutex_unlock(&tbl->dmn->mutex); | ||
return ret; | ||
} | ||
|
||
static void dr_table_uninit_nic(struct mlx5dr_table_rx_tx *nic_tbl) | ||
{ | ||
mlx5dr_htbl_put(nic_tbl->s_anchor); | ||
} | ||
|
||
static void dr_table_uninit_fdb(struct mlx5dr_table *tbl) | ||
{ | ||
dr_table_uninit_nic(&tbl->rx); | ||
dr_table_uninit_nic(&tbl->tx); | ||
} | ||
|
||
static void dr_table_uninit(struct mlx5dr_table *tbl) | ||
{ | ||
mutex_lock(&tbl->dmn->mutex); | ||
|
||
switch (tbl->dmn->type) { | ||
case MLX5DR_DOMAIN_TYPE_NIC_RX: | ||
dr_table_uninit_nic(&tbl->rx); | ||
break; | ||
case MLX5DR_DOMAIN_TYPE_NIC_TX: | ||
dr_table_uninit_nic(&tbl->tx); | ||
break; | ||
case MLX5DR_DOMAIN_TYPE_FDB: | ||
dr_table_uninit_fdb(tbl); | ||
break; | ||
default: | ||
WARN_ON(true); | ||
break; | ||
} | ||
|
||
mutex_unlock(&tbl->dmn->mutex); | ||
} | ||
|
||
static int dr_table_init_nic(struct mlx5dr_domain *dmn, | ||
struct mlx5dr_table_rx_tx *nic_tbl) | ||
{ | ||
struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn; | ||
struct mlx5dr_htbl_connect_info info; | ||
int ret; | ||
|
||
nic_tbl->default_icm_addr = nic_dmn->default_icm_addr; | ||
|
||
nic_tbl->s_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool, | ||
DR_CHUNK_SIZE_1, | ||
MLX5DR_STE_LU_TYPE_DONT_CARE, | ||
0); | ||
if (!nic_tbl->s_anchor) | ||
return -ENOMEM; | ||
|
||
info.type = CONNECT_MISS; | ||
info.miss_icm_addr = nic_dmn->default_icm_addr; | ||
ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn, | ||
nic_tbl->s_anchor, | ||
&info, true); | ||
if (ret) | ||
goto free_s_anchor; | ||
|
||
mlx5dr_htbl_get(nic_tbl->s_anchor); | ||
|
||
return 0; | ||
|
||
free_s_anchor: | ||
mlx5dr_ste_htbl_free(nic_tbl->s_anchor); | ||
return ret; | ||
} | ||
|
||
static int dr_table_init_fdb(struct mlx5dr_table *tbl) | ||
{ | ||
int ret; | ||
|
||
ret = dr_table_init_nic(tbl->dmn, &tbl->rx); | ||
if (ret) | ||
return ret; | ||
|
||
ret = dr_table_init_nic(tbl->dmn, &tbl->tx); | ||
if (ret) | ||
goto destroy_rx; | ||
|
||
return 0; | ||
|
||
destroy_rx: | ||
dr_table_uninit_nic(&tbl->rx); | ||
return ret; | ||
} | ||
|
||
static int dr_table_init(struct mlx5dr_table *tbl) | ||
{ | ||
int ret = 0; | ||
|
||
INIT_LIST_HEAD(&tbl->matcher_list); | ||
|
||
mutex_lock(&tbl->dmn->mutex); | ||
|
||
switch (tbl->dmn->type) { | ||
case MLX5DR_DOMAIN_TYPE_NIC_RX: | ||
tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_RX; | ||
tbl->rx.nic_dmn = &tbl->dmn->info.rx; | ||
ret = dr_table_init_nic(tbl->dmn, &tbl->rx); | ||
break; | ||
case MLX5DR_DOMAIN_TYPE_NIC_TX: | ||
tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_TX; | ||
tbl->tx.nic_dmn = &tbl->dmn->info.tx; | ||
ret = dr_table_init_nic(tbl->dmn, &tbl->tx); | ||
break; | ||
case MLX5DR_DOMAIN_TYPE_FDB: | ||
tbl->table_type = MLX5_FLOW_TABLE_TYPE_FDB; | ||
tbl->rx.nic_dmn = &tbl->dmn->info.rx; | ||
tbl->tx.nic_dmn = &tbl->dmn->info.tx; | ||
ret = dr_table_init_fdb(tbl); | ||
break; | ||
default: | ||
WARN_ON(true); | ||
break; | ||
} | ||
|
||
mutex_unlock(&tbl->dmn->mutex); | ||
|
||
return ret; | ||
} | ||
|
||
static int dr_table_destroy_sw_owned_tbl(struct mlx5dr_table *tbl) | ||
{ | ||
return mlx5dr_cmd_destroy_flow_table(tbl->dmn->mdev, | ||
tbl->table_id, | ||
tbl->table_type); | ||
} | ||
|
||
static int dr_table_create_sw_owned_tbl(struct mlx5dr_table *tbl) | ||
{ | ||
u64 icm_addr_rx = 0; | ||
u64 icm_addr_tx = 0; | ||
int ret; | ||
|
||
if (tbl->rx.s_anchor) | ||
icm_addr_rx = tbl->rx.s_anchor->chunk->icm_addr; | ||
|
||
if (tbl->tx.s_anchor) | ||
icm_addr_tx = tbl->tx.s_anchor->chunk->icm_addr; | ||
|
||
ret = mlx5dr_cmd_create_flow_table(tbl->dmn->mdev, | ||
tbl->table_type, | ||
icm_addr_rx, | ||
icm_addr_tx, | ||
tbl->dmn->info.caps.max_ft_level - 1, | ||
true, false, NULL, | ||
&tbl->table_id); | ||
|
||
return ret; | ||
} | ||
|
||
struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_domain *dmn, u32 level) | ||
{ | ||
struct mlx5dr_table *tbl; | ||
int ret; | ||
|
||
refcount_inc(&dmn->refcount); | ||
|
||
tbl = kzalloc(sizeof(*tbl), GFP_KERNEL); | ||
if (!tbl) | ||
goto dec_ref; | ||
|
||
tbl->dmn = dmn; | ||
tbl->level = level; | ||
refcount_set(&tbl->refcount, 1); | ||
|
||
ret = dr_table_init(tbl); | ||
if (ret) | ||
goto free_tbl; | ||
|
||
ret = dr_table_create_sw_owned_tbl(tbl); | ||
if (ret) | ||
goto uninit_tbl; | ||
|
||
return tbl; | ||
|
||
uninit_tbl: | ||
dr_table_uninit(tbl); | ||
free_tbl: | ||
kfree(tbl); | ||
dec_ref: | ||
refcount_dec(&dmn->refcount); | ||
return NULL; | ||
} | ||
|
||
int mlx5dr_table_destroy(struct mlx5dr_table *tbl) | ||
{ | ||
int ret; | ||
|
||
if (refcount_read(&tbl->refcount) > 1) | ||
return -EBUSY; | ||
|
||
ret = dr_table_destroy_sw_owned_tbl(tbl); | ||
if (ret) | ||
return ret; | ||
|
||
dr_table_uninit(tbl); | ||
|
||
if (tbl->miss_action) | ||
refcount_dec(&tbl->miss_action->refcount); | ||
|
||
refcount_dec(&tbl->dmn->refcount); | ||
kfree(tbl); | ||
|
||
return ret; | ||
} | ||
|
||
u32 mlx5dr_table_get_id(struct mlx5dr_table *tbl) | ||
{ | ||
return tbl->table_id; | ||
} |