xref: /dpdk/drivers/net/mlx5/hws/mlx5dr_table.c (revision 02d36ef6a9528e0f4a3403956e66bcea5fadbf8c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright (c) 2022 NVIDIA Corporation & Affiliates
3  */
4 
5 #include "mlx5dr_internal.h"
6 
7 static void mlx5dr_table_init_next_ft_attr(struct mlx5dr_table *tbl,
8 					   struct mlx5dr_cmd_ft_create_attr *ft_attr)
9 {
10 	ft_attr->type = tbl->fw_ft_type;
11 	if (tbl->type == MLX5DR_TABLE_TYPE_FDB)
12 		ft_attr->level = tbl->ctx->caps->fdb_ft.max_level - 1;
13 	else
14 		ft_attr->level = tbl->ctx->caps->nic_ft.max_level - 1;
15 	ft_attr->rtc_valid = true;
16 }
17 
18 /* Call this under ctx->ctrl_lock */
19 static int
20 mlx5dr_table_up_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
21 {
22 	struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
23 	struct mlx5dr_cmd_forward_tbl *default_miss;
24 	struct mlx5dr_context *ctx = tbl->ctx;
25 	uint8_t tbl_type = tbl->type;
26 	uint32_t vport;
27 
28 	if (tbl->type != MLX5DR_TABLE_TYPE_FDB)
29 		return 0;
30 
31 	if (ctx->common_res[tbl_type].default_miss) {
32 		ctx->common_res[tbl_type].default_miss->refcount++;
33 		return 0;
34 	}
35 
36 	ft_attr.type = tbl->fw_ft_type;
37 	ft_attr.level = tbl->ctx->caps->fdb_ft.max_level; /* The last level */
38 	ft_attr.rtc_valid = false;
39 
40 	assert(ctx->caps->eswitch_manager);
41 	vport = ctx->caps->eswitch_manager_vport_number;
42 
43 	default_miss = mlx5dr_cmd_miss_ft_create(ctx->ibv_ctx, &ft_attr, vport);
44 	if (!default_miss) {
45 		DR_LOG(ERR, "Failed to default miss table type: 0x%x", tbl_type);
46 		return rte_errno;
47 	}
48 
49 	ctx->common_res[tbl_type].default_miss = default_miss;
50 	ctx->common_res[tbl_type].default_miss->refcount++;
51 	return 0;
52 }
53 
54 /* Called under pthread_spin_lock(&ctx->ctrl_lock) */
55 static void mlx5dr_table_down_default_fdb_miss_tbl(struct mlx5dr_table *tbl)
56 {
57 	struct mlx5dr_cmd_forward_tbl *default_miss;
58 	struct mlx5dr_context *ctx = tbl->ctx;
59 	uint8_t tbl_type = tbl->type;
60 
61 	if (tbl->type != MLX5DR_TABLE_TYPE_FDB)
62 		return;
63 
64 	default_miss = ctx->common_res[tbl_type].default_miss;
65 	if (--default_miss->refcount)
66 		return;
67 
68 	mlx5dr_cmd_miss_ft_destroy(default_miss);
69 
70 	simple_free(default_miss);
71 	ctx->common_res[tbl_type].default_miss = NULL;
72 }
73 
74 static int
75 mlx5dr_table_connect_to_default_miss_tbl(struct mlx5dr_table *tbl,
76 					 struct mlx5dr_devx_obj *ft)
77 {
78 	struct mlx5dr_cmd_ft_modify_attr ft_attr = {0};
79 	int ret;
80 
81 	assert(tbl->type == MLX5DR_TABLE_TYPE_FDB);
82 
83 	mlx5dr_cmd_set_attr_connect_miss_tbl(tbl->ctx,
84 					     tbl->fw_ft_type,
85 					     tbl->type,
86 					     &ft_attr);
87 
88 	/* Connect to next */
89 	ret = mlx5dr_cmd_flow_table_modify(ft, &ft_attr);
90 	if (ret) {
91 		DR_LOG(ERR, "Failed to connect FT to default FDB FT");
92 		return errno;
93 	}
94 
95 	return 0;
96 }
97 
98 struct mlx5dr_devx_obj *
99 mlx5dr_table_create_default_ft(struct mlx5dr_table *tbl)
100 {
101 	struct mlx5dr_cmd_ft_create_attr ft_attr = {0};
102 	struct mlx5dr_devx_obj *ft_obj;
103 	int ret;
104 
105 	mlx5dr_table_init_next_ft_attr(tbl, &ft_attr);
106 
107 	ft_obj = mlx5dr_cmd_flow_table_create(tbl->ctx->ibv_ctx, &ft_attr);
108 	if (ft_obj && tbl->type == MLX5DR_TABLE_TYPE_FDB) {
109 		/* Take/create ref over the default miss */
110 		ret = mlx5dr_table_up_default_fdb_miss_tbl(tbl);
111 		if (ret) {
112 			DR_LOG(ERR, "Failed to get default fdb miss");
113 			goto free_ft_obj;
114 		}
115 		ret = mlx5dr_table_connect_to_default_miss_tbl(tbl, ft_obj);
116 		if (ret) {
117 			DR_LOG(ERR, "Failed connecting to default miss tbl");
118 			goto down_miss_tbl;
119 		}
120 	}
121 
122 	return ft_obj;
123 
124 down_miss_tbl:
125 	mlx5dr_table_down_default_fdb_miss_tbl(tbl);
126 free_ft_obj:
127 	mlx5dr_cmd_destroy_obj(ft_obj);
128 	return NULL;
129 }
130 
131 void mlx5dr_table_destroy_default_ft(struct mlx5dr_table *tbl,
132 				     struct mlx5dr_devx_obj *ft_obj)
133 {
134 	mlx5dr_cmd_destroy_obj(ft_obj);
135 	mlx5dr_table_down_default_fdb_miss_tbl(tbl);
136 }
137 
138 static int mlx5dr_table_init(struct mlx5dr_table *tbl)
139 {
140 	struct mlx5dr_context *ctx = tbl->ctx;
141 	int ret;
142 
143 	if (mlx5dr_table_is_root(tbl))
144 		return 0;
145 
146 	if (!(tbl->ctx->flags & MLX5DR_CONTEXT_FLAG_HWS_SUPPORT)) {
147 		DR_LOG(ERR, "HWS not supported, cannot create mlx5dr_table");
148 		rte_errno = EOPNOTSUPP;
149 		return rte_errno;
150 	}
151 
152 	switch (tbl->type) {
153 	case MLX5DR_TABLE_TYPE_NIC_RX:
154 		tbl->fw_ft_type = FS_FT_NIC_RX;
155 		break;
156 	case MLX5DR_TABLE_TYPE_NIC_TX:
157 		tbl->fw_ft_type = FS_FT_NIC_TX;
158 		break;
159 	case MLX5DR_TABLE_TYPE_FDB:
160 		tbl->fw_ft_type = FS_FT_FDB;
161 		break;
162 	default:
163 		assert(0);
164 		break;
165 	}
166 
167 	pthread_spin_lock(&ctx->ctrl_lock);
168 	tbl->ft = mlx5dr_table_create_default_ft(tbl);
169 	if (!tbl->ft) {
170 		DR_LOG(ERR, "Failed to create flow table devx object");
171 		pthread_spin_unlock(&ctx->ctrl_lock);
172 		return rte_errno;
173 	}
174 
175 	ret = mlx5dr_action_get_default_stc(ctx, tbl->type);
176 	if (ret)
177 		goto tbl_destroy;
178 	pthread_spin_unlock(&ctx->ctrl_lock);
179 
180 	return 0;
181 
182 tbl_destroy:
183 	mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
184 	pthread_spin_unlock(&ctx->ctrl_lock);
185 	return rte_errno;
186 }
187 
188 static void mlx5dr_table_uninit(struct mlx5dr_table *tbl)
189 {
190 	if (mlx5dr_table_is_root(tbl))
191 		return;
192 	pthread_spin_lock(&tbl->ctx->ctrl_lock);
193 	mlx5dr_action_put_default_stc(tbl->ctx, tbl->type);
194 	mlx5dr_table_destroy_default_ft(tbl, tbl->ft);
195 	pthread_spin_unlock(&tbl->ctx->ctrl_lock);
196 }
197 
198 struct mlx5dr_table *mlx5dr_table_create(struct mlx5dr_context *ctx,
199 					 struct mlx5dr_table_attr *attr)
200 {
201 	struct mlx5dr_table *tbl;
202 	int ret;
203 
204 	if (attr->type > MLX5DR_TABLE_TYPE_FDB) {
205 		DR_LOG(ERR, "Invalid table type %d", attr->type);
206 		return NULL;
207 	}
208 
209 	tbl = simple_malloc(sizeof(*tbl));
210 	if (!tbl) {
211 		rte_errno = ENOMEM;
212 		return NULL;
213 	}
214 
215 	tbl->ctx = ctx;
216 	tbl->type = attr->type;
217 	tbl->level = attr->level;
218 	LIST_INIT(&tbl->head);
219 
220 	ret = mlx5dr_table_init(tbl);
221 	if (ret) {
222 		DR_LOG(ERR, "Failed to initialise table");
223 		goto free_tbl;
224 	}
225 
226 	pthread_spin_lock(&ctx->ctrl_lock);
227 	LIST_INSERT_HEAD(&ctx->head, tbl, next);
228 	pthread_spin_unlock(&ctx->ctrl_lock);
229 
230 	return tbl;
231 
232 free_tbl:
233 	simple_free(tbl);
234 	return NULL;
235 }
236 
237 int mlx5dr_table_destroy(struct mlx5dr_table *tbl)
238 {
239 	struct mlx5dr_context *ctx = tbl->ctx;
240 
241 	pthread_spin_lock(&ctx->ctrl_lock);
242 	LIST_REMOVE(tbl, next);
243 	pthread_spin_unlock(&ctx->ctrl_lock);
244 	mlx5dr_table_uninit(tbl);
245 	simple_free(tbl);
246 
247 	return 0;
248 }
249