File Index
Files and directories
Sign in
FILE

dr_table.c

File preview with syntax highlighting.

linux-6.19.14/drivers/net/ethernet/mellanox/mlx5/core/steering/sws/dr_table.c C
  1// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
  2/* Copyright (c) 2019 Mellanox Technologies. */
  3
  4#include "dr_types.h"
  5
  6static int dr_table_set_miss_action_nic(struct mlx5dr_domain *dmn,
  7					struct mlx5dr_table_rx_tx *nic_tbl,
  8					struct mlx5dr_action *action)
  9{
 10	struct mlx5dr_matcher_rx_tx *last_nic_matcher = NULL;
 11	struct mlx5dr_htbl_connect_info info;
 12	struct mlx5dr_ste_htbl *last_htbl;
 13	struct mlx5dr_icm_chunk *chunk;
 14	int ret;
 15
 16	if (!list_empty(&nic_tbl->nic_matcher_list))
 17		last_nic_matcher = list_last_entry(&nic_tbl->nic_matcher_list,
 18						   struct mlx5dr_matcher_rx_tx,
 19						   list_node);
 20
 21	if (last_nic_matcher)
 22		last_htbl = last_nic_matcher->e_anchor;
 23	else
 24		last_htbl = nic_tbl->s_anchor;
 25
 26	if (action) {
 27		chunk = nic_tbl->nic_dmn->type == DR_DOMAIN_NIC_TYPE_RX ?
 28			action->dest_tbl->tbl->rx.s_anchor->chunk :
 29			action->dest_tbl->tbl->tx.s_anchor->chunk;
 30		nic_tbl->default_icm_addr = mlx5dr_icm_pool_get_chunk_icm_addr(chunk);
 31	} else {
 32		nic_tbl->default_icm_addr = nic_tbl->nic_dmn->default_icm_addr;
 33	}
 34
 35	info.type = CONNECT_MISS;
 36	info.miss_icm_addr = nic_tbl->default_icm_addr;
 37
 38	ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_tbl->nic_dmn,
 39						last_htbl, &info, true);
 40	if (ret)
 41		mlx5dr_dbg(dmn, "Failed to set NIC RX/TX miss action, ret %d\n", ret);
 42
 43	return ret;
 44}
 45
 46int mlx5dr_table_set_miss_action(struct mlx5dr_table *tbl,
 47				 struct mlx5dr_action *action)
 48{
 49	int ret = -EOPNOTSUPP;
 50
 51	if (action && action->action_type != DR_ACTION_TYP_FT)
 52		return -EOPNOTSUPP;
 53
 54	mlx5dr_domain_lock(tbl->dmn);
 55
 56	if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX ||
 57	    tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
 58		ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->rx, action);
 59		if (ret)
 60			goto out;
 61	}
 62
 63	if (tbl->dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX ||
 64	    tbl->dmn->type == MLX5DR_DOMAIN_TYPE_FDB) {
 65		ret = dr_table_set_miss_action_nic(tbl->dmn, &tbl->tx, action);
 66		if (ret)
 67			goto out;
 68	}
 69
 70	if (ret)
 71		goto out;
 72
 73	/* Release old action */
 74	if (tbl->miss_action)
 75		refcount_dec(&tbl->miss_action->refcount);
 76
 77	/* Set new miss action */
 78	tbl->miss_action = action;
 79	if (tbl->miss_action)
 80		refcount_inc(&action->refcount);
 81
 82out:
 83	mlx5dr_domain_unlock(tbl->dmn);
 84	return ret;
 85}
 86
 87static void dr_table_uninit_nic(struct mlx5dr_table_rx_tx *nic_tbl)
 88{
 89	mlx5dr_htbl_put(nic_tbl->s_anchor);
 90}
 91
 92static void dr_table_uninit_fdb(struct mlx5dr_table *tbl)
 93{
 94	dr_table_uninit_nic(&tbl->rx);
 95	dr_table_uninit_nic(&tbl->tx);
 96}
 97
 98static void dr_table_uninit(struct mlx5dr_table *tbl)
 99{
100	mlx5dr_domain_lock(tbl->dmn);
101
102	switch (tbl->dmn->type) {
103	case MLX5DR_DOMAIN_TYPE_NIC_RX:
104		dr_table_uninit_nic(&tbl->rx);
105		break;
106	case MLX5DR_DOMAIN_TYPE_NIC_TX:
107		dr_table_uninit_nic(&tbl->tx);
108		break;
109	case MLX5DR_DOMAIN_TYPE_FDB:
110		dr_table_uninit_fdb(tbl);
111		break;
112	default:
113		WARN_ON(true);
114		break;
115	}
116
117	mlx5dr_domain_unlock(tbl->dmn);
118}
119
120static int dr_table_init_nic(struct mlx5dr_domain *dmn,
121			     struct mlx5dr_table_rx_tx *nic_tbl)
122{
123	struct mlx5dr_domain_rx_tx *nic_dmn = nic_tbl->nic_dmn;
124	struct mlx5dr_htbl_connect_info info;
125	int ret;
126
127	INIT_LIST_HEAD(&nic_tbl->nic_matcher_list);
128
129	nic_tbl->default_icm_addr = nic_dmn->default_icm_addr;
130
131	nic_tbl->s_anchor = mlx5dr_ste_htbl_alloc(dmn->ste_icm_pool,
132						  DR_CHUNK_SIZE_1,
133						  MLX5DR_STE_LU_TYPE_DONT_CARE,
134						  0);
135	if (!nic_tbl->s_anchor) {
136		mlx5dr_err(dmn, "Failed allocating htbl\n");
137		return -ENOMEM;
138	}
139
140	info.type = CONNECT_MISS;
141	info.miss_icm_addr = nic_dmn->default_icm_addr;
142	ret = mlx5dr_ste_htbl_init_and_postsend(dmn, nic_dmn,
143						nic_tbl->s_anchor,
144						&info, true);
145	if (ret) {
146		mlx5dr_err(dmn, "Failed int and send htbl\n");
147		goto free_s_anchor;
148	}
149
150	mlx5dr_htbl_get(nic_tbl->s_anchor);
151
152	return 0;
153
154free_s_anchor:
155	mlx5dr_ste_htbl_free(nic_tbl->s_anchor);
156	return ret;
157}
158
159static int dr_table_init_fdb(struct mlx5dr_table *tbl)
160{
161	int ret;
162
163	ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
164	if (ret)
165		return ret;
166
167	ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
168	if (ret)
169		goto destroy_rx;
170
171	return 0;
172
173destroy_rx:
174	dr_table_uninit_nic(&tbl->rx);
175	return ret;
176}
177
178static int dr_table_init(struct mlx5dr_table *tbl)
179{
180	int ret = 0;
181
182	INIT_LIST_HEAD(&tbl->matcher_list);
183
184	mlx5dr_domain_lock(tbl->dmn);
185
186	switch (tbl->dmn->type) {
187	case MLX5DR_DOMAIN_TYPE_NIC_RX:
188		tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_RX;
189		tbl->rx.nic_dmn = &tbl->dmn->info.rx;
190		ret = dr_table_init_nic(tbl->dmn, &tbl->rx);
191		break;
192	case MLX5DR_DOMAIN_TYPE_NIC_TX:
193		tbl->table_type = MLX5_FLOW_TABLE_TYPE_NIC_TX;
194		tbl->tx.nic_dmn = &tbl->dmn->info.tx;
195		ret = dr_table_init_nic(tbl->dmn, &tbl->tx);
196		break;
197	case MLX5DR_DOMAIN_TYPE_FDB:
198		tbl->table_type = MLX5_FLOW_TABLE_TYPE_FDB;
199		tbl->rx.nic_dmn = &tbl->dmn->info.rx;
200		tbl->tx.nic_dmn = &tbl->dmn->info.tx;
201		ret = dr_table_init_fdb(tbl);
202		break;
203	default:
204		WARN_ON(true);
205		break;
206	}
207
208	mlx5dr_domain_unlock(tbl->dmn);
209
210	return ret;
211}
212
213static int dr_table_destroy_sw_owned_tbl(struct mlx5dr_table *tbl)
214{
215	return mlx5dr_cmd_destroy_flow_table(tbl->dmn->mdev,
216					     tbl->table_id,
217					     tbl->table_type);
218}
219
220static int dr_table_create_sw_owned_tbl(struct mlx5dr_table *tbl, u16 uid)
221{
222	bool en_encap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT);
223	bool en_decap = !!(tbl->flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
224	struct mlx5dr_cmd_create_flow_table_attr ft_attr = {};
225	u64 icm_addr_rx = 0;
226	u64 icm_addr_tx = 0;
227	int ret;
228
229	if (tbl->rx.s_anchor)
230		icm_addr_rx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->rx.s_anchor->chunk);
231
232	if (tbl->tx.s_anchor)
233		icm_addr_tx = mlx5dr_icm_pool_get_chunk_icm_addr(tbl->tx.s_anchor->chunk);
234
235	ft_attr.table_type = tbl->table_type;
236	ft_attr.icm_addr_rx = icm_addr_rx;
237	ft_attr.icm_addr_tx = icm_addr_tx;
238	ft_attr.level = tbl->dmn->info.caps.max_ft_level - 1;
239	ft_attr.sw_owner = true;
240	ft_attr.decap_en = en_decap;
241	ft_attr.reformat_en = en_encap;
242	ft_attr.uid = uid;
243
244	ret = mlx5dr_cmd_create_flow_table(tbl->dmn->mdev, &ft_attr,
245					   NULL, &tbl->table_id);
246
247	return ret;
248}
249
250struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_domain *dmn, u32 level,
251					 u32 flags, u16 uid)
252{
253	struct mlx5dr_table *tbl;
254	int ret;
255
256	refcount_inc(&dmn->refcount);
257
258	tbl = kzalloc(sizeof(*tbl), GFP_KERNEL);
259	if (!tbl)
260		goto dec_ref;
261
262	tbl->dmn = dmn;
263	tbl->level = level;
264	tbl->flags = flags;
265	refcount_set(&tbl->refcount, 1);
266
267	ret = dr_table_init(tbl);
268	if (ret)
269		goto free_tbl;
270
271	ret = dr_table_create_sw_owned_tbl(tbl, uid);
272	if (ret)
273		goto uninit_tbl;
274
275	INIT_LIST_HEAD(&tbl->dbg_node);
276	mlx5dr_dbg_tbl_add(tbl);
277	return tbl;
278
279uninit_tbl:
280	dr_table_uninit(tbl);
281free_tbl:
282	kfree(tbl);
283dec_ref:
284	refcount_dec(&dmn->refcount);
285	return NULL;
286}
287
288int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
289{
290	int ret;
291
292	if (WARN_ON_ONCE(refcount_read(&tbl->refcount) > 1))
293		return -EBUSY;
294
295	mlx5dr_dbg_tbl_del(tbl);
296	ret = dr_table_destroy_sw_owned_tbl(tbl);
297	if (ret)
298		mlx5dr_err(tbl->dmn, "Failed to destroy sw owned table\n");
299
300	dr_table_uninit(tbl);
301
302	if (tbl->miss_action)
303		refcount_dec(&tbl->miss_action->refcount);
304
305	refcount_dec(&tbl->dmn->refcount);
306	kfree(tbl);
307
308	return ret;
309}
310
311u32 mlx5dr_table_get_id(struct mlx5dr_table *tbl)
312{
313	return tbl->table_id;
314}
315
316struct mlx5dr_table *mlx5dr_table_get_from_fs_ft(struct mlx5_flow_table *ft)
317{
318	return ft->fs_dr_table.dr_table;
319}
~/ Read-only file preview.