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