1
2
3
4#include "dr_types.h"
5
6enum dr_action_domain {
7 DR_ACTION_DOMAIN_NIC_INGRESS,
8 DR_ACTION_DOMAIN_NIC_EGRESS,
9 DR_ACTION_DOMAIN_FDB_INGRESS,
10 DR_ACTION_DOMAIN_FDB_EGRESS,
11 DR_ACTION_DOMAIN_MAX,
12};
13
14enum dr_action_valid_state {
15 DR_ACTION_STATE_ERR,
16 DR_ACTION_STATE_NO_ACTION,
17 DR_ACTION_STATE_REFORMAT,
18 DR_ACTION_STATE_MODIFY_HDR,
19 DR_ACTION_STATE_MODIFY_VLAN,
20 DR_ACTION_STATE_NON_TERM,
21 DR_ACTION_STATE_TERM,
22 DR_ACTION_STATE_MAX,
23};
24
25static const enum dr_action_valid_state
26next_action_state[DR_ACTION_DOMAIN_MAX][DR_ACTION_STATE_MAX][DR_ACTION_TYP_MAX] = {
27 [DR_ACTION_DOMAIN_NIC_INGRESS] = {
28 [DR_ACTION_STATE_NO_ACTION] = {
29 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
30 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
31 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
32 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM,
33 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
34 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
35 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
36 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
37 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
38 },
39 [DR_ACTION_STATE_REFORMAT] = {
40 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
41 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
42 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
43 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_REFORMAT,
44 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
45 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
46 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
47 },
48 [DR_ACTION_STATE_MODIFY_HDR] = {
49 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
50 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
51 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
52 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_HDR,
53 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
54 },
55 [DR_ACTION_STATE_MODIFY_VLAN] = {
56 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
57 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
58 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
59 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_MODIFY_VLAN,
60 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
61 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
62 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
63 },
64 [DR_ACTION_STATE_NON_TERM] = {
65 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
66 [DR_ACTION_TYP_QP] = DR_ACTION_STATE_TERM,
67 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
68 [DR_ACTION_TYP_TAG] = DR_ACTION_STATE_NON_TERM,
69 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
70 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
71 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
72 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
73 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
74 },
75 [DR_ACTION_STATE_TERM] = {
76 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM,
77 },
78 },
79 [DR_ACTION_DOMAIN_NIC_EGRESS] = {
80 [DR_ACTION_STATE_NO_ACTION] = {
81 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
82 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
83 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
84 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
85 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
86 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
87 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
88 },
89 [DR_ACTION_STATE_REFORMAT] = {
90 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
91 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
92 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
93 },
94 [DR_ACTION_STATE_MODIFY_HDR] = {
95 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
96 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
97 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
98 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
99 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
100 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
101 },
102 [DR_ACTION_STATE_MODIFY_VLAN] = {
103 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
104 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
105 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
106 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
107 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
108 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
109 },
110 [DR_ACTION_STATE_NON_TERM] = {
111 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
112 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
113 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
114 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
115 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
116 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
117 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
118 },
119 [DR_ACTION_STATE_TERM] = {
120 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM,
121 },
122 },
123 [DR_ACTION_DOMAIN_FDB_INGRESS] = {
124 [DR_ACTION_STATE_NO_ACTION] = {
125 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
126 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
127 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
128 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
129 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
130 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
131 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
132 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
133 },
134 [DR_ACTION_STATE_REFORMAT] = {
135 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
136 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
137 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
138 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
139 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
140 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
141 },
142 [DR_ACTION_STATE_MODIFY_HDR] = {
143 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
144 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
145 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
146 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
147 },
148 [DR_ACTION_STATE_MODIFY_VLAN] = {
149 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
150 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
151 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
152 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
153 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
154 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
155 },
156 [DR_ACTION_STATE_NON_TERM] = {
157 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
158 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
159 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
160 [DR_ACTION_TYP_TNL_L2_TO_L2] = DR_ACTION_STATE_REFORMAT,
161 [DR_ACTION_TYP_TNL_L3_TO_L2] = DR_ACTION_STATE_REFORMAT,
162 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
163 [DR_ACTION_TYP_POP_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
164 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
165 },
166 [DR_ACTION_STATE_TERM] = {
167 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM,
168 },
169 },
170 [DR_ACTION_DOMAIN_FDB_EGRESS] = {
171 [DR_ACTION_STATE_NO_ACTION] = {
172 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
173 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
174 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
175 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
176 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
177 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
178 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
179 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
180 },
181 [DR_ACTION_STATE_REFORMAT] = {
182 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
183 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
184 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_REFORMAT,
185 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
186 },
187 [DR_ACTION_STATE_MODIFY_HDR] = {
188 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
189 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
190 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_HDR,
191 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
192 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
193 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
194 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
195 },
196 [DR_ACTION_STATE_MODIFY_VLAN] = {
197 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
198 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
199 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
200 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_MODIFY_VLAN,
201 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
202 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
203 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
204 },
205 [DR_ACTION_STATE_NON_TERM] = {
206 [DR_ACTION_TYP_DROP] = DR_ACTION_STATE_TERM,
207 [DR_ACTION_TYP_FT] = DR_ACTION_STATE_TERM,
208 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_NON_TERM,
209 [DR_ACTION_TYP_MODIFY_HDR] = DR_ACTION_STATE_MODIFY_HDR,
210 [DR_ACTION_TYP_L2_TO_TNL_L2] = DR_ACTION_STATE_REFORMAT,
211 [DR_ACTION_TYP_L2_TO_TNL_L3] = DR_ACTION_STATE_REFORMAT,
212 [DR_ACTION_TYP_PUSH_VLAN] = DR_ACTION_STATE_MODIFY_VLAN,
213 [DR_ACTION_TYP_VPORT] = DR_ACTION_STATE_TERM,
214 },
215 [DR_ACTION_STATE_TERM] = {
216 [DR_ACTION_TYP_CTR] = DR_ACTION_STATE_TERM,
217 },
218 },
219};
220
221static int
222dr_action_reformat_to_action_type(enum mlx5dr_action_reformat_type reformat_type,
223 enum mlx5dr_action_type *action_type)
224{
225 switch (reformat_type) {
226 case DR_ACTION_REFORMAT_TYP_TNL_L2_TO_L2:
227 *action_type = DR_ACTION_TYP_TNL_L2_TO_L2;
228 break;
229 case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L2:
230 *action_type = DR_ACTION_TYP_L2_TO_TNL_L2;
231 break;
232 case DR_ACTION_REFORMAT_TYP_TNL_L3_TO_L2:
233 *action_type = DR_ACTION_TYP_TNL_L3_TO_L2;
234 break;
235 case DR_ACTION_REFORMAT_TYP_L2_TO_TNL_L3:
236 *action_type = DR_ACTION_TYP_L2_TO_TNL_L3;
237 break;
238 default:
239 return -EINVAL;
240 }
241
242 return 0;
243}
244
245
246
247
248
249static void dr_actions_apply(struct mlx5dr_domain *dmn,
250 enum mlx5dr_ste_entry_type ste_type,
251 u8 *action_type_set,
252 u8 *last_ste,
253 struct mlx5dr_ste_actions_attr *attr,
254 u32 *new_num_stes)
255{
256 struct mlx5dr_ste_ctx *ste_ctx = dmn->ste_ctx;
257 u32 added_stes = 0;
258
259 if (ste_type == MLX5DR_STE_TYPE_RX)
260 mlx5dr_ste_set_actions_rx(ste_ctx, dmn, action_type_set,
261 last_ste, attr, &added_stes);
262 else
263 mlx5dr_ste_set_actions_tx(ste_ctx, dmn, action_type_set,
264 last_ste, attr, &added_stes);
265
266 *new_num_stes += added_stes;
267}
268
269static enum dr_action_domain
270dr_action_get_action_domain(enum mlx5dr_domain_type domain,
271 enum mlx5dr_ste_entry_type ste_type)
272{
273 switch (domain) {
274 case MLX5DR_DOMAIN_TYPE_NIC_RX:
275 return DR_ACTION_DOMAIN_NIC_INGRESS;
276 case MLX5DR_DOMAIN_TYPE_NIC_TX:
277 return DR_ACTION_DOMAIN_NIC_EGRESS;
278 case MLX5DR_DOMAIN_TYPE_FDB:
279 if (ste_type == MLX5DR_STE_TYPE_RX)
280 return DR_ACTION_DOMAIN_FDB_INGRESS;
281 return DR_ACTION_DOMAIN_FDB_EGRESS;
282 default:
283 WARN_ON(true);
284 return DR_ACTION_DOMAIN_MAX;
285 }
286}
287
288static
289int dr_action_validate_and_get_next_state(enum dr_action_domain action_domain,
290 u32 action_type,
291 u32 *state)
292{
293 u32 cur_state = *state;
294
295
296 *state = next_action_state[action_domain][cur_state][action_type];
297
298 if (*state == DR_ACTION_STATE_ERR)
299 return -EOPNOTSUPP;
300
301 return 0;
302}
303
304static int dr_action_handle_cs_recalc(struct mlx5dr_domain *dmn,
305 struct mlx5dr_action *dest_action,
306 u64 *final_icm_addr)
307{
308 int ret;
309
310 switch (dest_action->action_type) {
311 case DR_ACTION_TYP_FT:
312
313
314
315
316 if (dest_action->dest_tbl->is_fw_tbl) {
317 *final_icm_addr = dest_action->dest_tbl->fw_tbl.rx_icm_addr;
318 } else {
319 mlx5dr_dbg(dmn,
320 "Destination FT should be terminating when modify TTL is used\n");
321 return -EINVAL;
322 }
323 break;
324
325 case DR_ACTION_TYP_VPORT:
326
327
328
329 ret = mlx5dr_domain_cache_get_recalc_cs_ft_addr(dest_action->vport->dmn,
330 dest_action->vport->caps->num,
331 final_icm_addr);
332 if (ret) {
333 mlx5dr_err(dmn, "Failed to get FW cs recalc flow table\n");
334 return ret;
335 }
336 break;
337
338 default:
339 break;
340 }
341
342 return 0;
343}
344
345#define WITH_VLAN_NUM_HW_ACTIONS 6
346
347int mlx5dr_actions_build_ste_arr(struct mlx5dr_matcher *matcher,
348 struct mlx5dr_matcher_rx_tx *nic_matcher,
349 struct mlx5dr_action *actions[],
350 u32 num_actions,
351 u8 *ste_arr,
352 u32 *new_hw_ste_arr_sz)
353{
354 struct mlx5dr_domain_rx_tx *nic_dmn = nic_matcher->nic_tbl->nic_dmn;
355 bool rx_rule = nic_dmn->ste_type == MLX5DR_STE_TYPE_RX;
356 struct mlx5dr_domain *dmn = matcher->tbl->dmn;
357 u8 action_type_set[DR_ACTION_TYP_MAX] = {};
358 struct mlx5dr_ste_actions_attr attr = {};
359 struct mlx5dr_action *dest_action = NULL;
360 u32 state = DR_ACTION_STATE_NO_ACTION;
361 enum dr_action_domain action_domain;
362 bool recalc_cs_required = false;
363 u8 *last_ste;
364 int i, ret;
365
366 attr.gvmi = dmn->info.caps.gvmi;
367 attr.hit_gvmi = dmn->info.caps.gvmi;
368 attr.final_icm_addr = nic_dmn->default_icm_addr;
369 action_domain = dr_action_get_action_domain(dmn->type, nic_dmn->ste_type);
370
371 for (i = 0; i < num_actions; i++) {
372 struct mlx5dr_action_dest_tbl *dest_tbl;
373 struct mlx5dr_action *action;
374 int max_actions_type = 1;
375 u32 action_type;
376
377 action = actions[i];
378 action_type = action->action_type;
379
380 switch (action_type) {
381 case DR_ACTION_TYP_DROP:
382 attr.final_icm_addr = nic_dmn->drop_icm_addr;
383 break;
384 case DR_ACTION_TYP_FT:
385 dest_action = action;
386 dest_tbl = action->dest_tbl;
387 if (!dest_tbl->is_fw_tbl) {
388 if (dest_tbl->tbl->dmn != dmn) {
389 mlx5dr_err(dmn,
390 "Destination table belongs to a different domain\n");
391 goto out_invalid_arg;
392 }
393 if (dest_tbl->tbl->level <= matcher->tbl->level) {
394 mlx5_core_warn_once(dmn->mdev,
395 "Connecting table to a lower/same level destination table\n");
396 mlx5dr_dbg(dmn,
397 "Connecting table at level %d to a destination table at level %d\n",
398 matcher->tbl->level,
399 dest_tbl->tbl->level);
400 }
401 attr.final_icm_addr = rx_rule ?
402 dest_tbl->tbl->rx.s_anchor->chunk->icm_addr :
403 dest_tbl->tbl->tx.s_anchor->chunk->icm_addr;
404 } else {
405 struct mlx5dr_cmd_query_flow_table_details output;
406 int ret;
407
408
409 if (!action->dest_tbl->fw_tbl.rx_icm_addr) {
410 ret = mlx5dr_cmd_query_flow_table(dmn->mdev,
411 dest_tbl->fw_tbl.type,
412 dest_tbl->fw_tbl.id,
413 &output);
414 if (!ret) {
415 dest_tbl->fw_tbl.tx_icm_addr =
416 output.sw_owner_icm_root_1;
417 dest_tbl->fw_tbl.rx_icm_addr =
418 output.sw_owner_icm_root_0;
419 } else {
420 mlx5dr_err(dmn,
421 "Failed mlx5_cmd_query_flow_table ret: %d\n",
422 ret);
423 return ret;
424 }
425 }
426 attr.final_icm_addr = rx_rule ?
427 dest_tbl->fw_tbl.rx_icm_addr :
428 dest_tbl->fw_tbl.tx_icm_addr;
429 }
430 break;
431 case DR_ACTION_TYP_QP:
432 mlx5dr_info(dmn, "Domain doesn't support QP\n");
433 goto out_invalid_arg;
434 case DR_ACTION_TYP_CTR:
435 attr.ctr_id = action->ctr->ctr_id +
436 action->ctr->offeset;
437 break;
438 case DR_ACTION_TYP_TAG:
439 attr.flow_tag = action->flow_tag->flow_tag;
440 break;
441 case DR_ACTION_TYP_TNL_L2_TO_L2:
442 break;
443 case DR_ACTION_TYP_TNL_L3_TO_L2:
444 attr.decap_index = action->rewrite->index;
445 attr.decap_actions = action->rewrite->num_of_actions;
446 attr.decap_with_vlan =
447 attr.decap_actions == WITH_VLAN_NUM_HW_ACTIONS;
448 break;
449 case DR_ACTION_TYP_MODIFY_HDR:
450 attr.modify_index = action->rewrite->index;
451 attr.modify_actions = action->rewrite->num_of_actions;
452 recalc_cs_required = action->rewrite->modify_ttl &&
453 !mlx5dr_ste_supp_ttl_cs_recalc(&dmn->info.caps);
454 break;
455 case DR_ACTION_TYP_L2_TO_TNL_L2:
456 case DR_ACTION_TYP_L2_TO_TNL_L3:
457 attr.reformat_size = action->reformat->reformat_size;
458 attr.reformat_id = action->reformat->reformat_id;
459 break;
460 case DR_ACTION_TYP_VPORT:
461 attr.hit_gvmi = action->vport->caps->vhca_gvmi;
462 dest_action = action;
463 if (rx_rule) {
464
465 if (action->vport->caps->num == WIRE_PORT)
466 goto out_invalid_arg;
467
468 attr.final_icm_addr = action->vport->caps->icm_address_rx;
469 } else {
470 attr.final_icm_addr = action->vport->caps->icm_address_tx;
471 }
472 break;
473 case DR_ACTION_TYP_POP_VLAN:
474 max_actions_type = MLX5DR_MAX_VLANS;
475 attr.vlans.count++;
476 break;
477 case DR_ACTION_TYP_PUSH_VLAN:
478 max_actions_type = MLX5DR_MAX_VLANS;
479 if (attr.vlans.count == MLX5DR_MAX_VLANS)
480 return -EINVAL;
481
482 attr.vlans.headers[attr.vlans.count++] = action->push_vlan->vlan_hdr;
483 break;
484 default:
485 goto out_invalid_arg;
486 }
487
488
489 if (++action_type_set[action_type] > max_actions_type) {
490 mlx5dr_err(dmn, "Action type %d supports only max %d time(s)\n",
491 action_type, max_actions_type);
492 goto out_invalid_arg;
493 }
494
495
496 if (dr_action_validate_and_get_next_state(action_domain,
497 action_type,
498 &state)) {
499 mlx5dr_err(dmn, "Invalid action sequence provided\n");
500 return -EOPNOTSUPP;
501 }
502 }
503
504 *new_hw_ste_arr_sz = nic_matcher->num_of_builders;
505 last_ste = ste_arr + DR_STE_SIZE * (nic_matcher->num_of_builders - 1);
506
507
508
509
510
511 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB &&
512 rx_rule && recalc_cs_required && dest_action) {
513 ret = dr_action_handle_cs_recalc(dmn, dest_action, &attr.final_icm_addr);
514 if (ret) {
515 mlx5dr_err(dmn,
516 "Failed to handle checksum recalculation err %d\n",
517 ret);
518 return ret;
519 }
520 }
521
522 dr_actions_apply(dmn,
523 nic_dmn->ste_type,
524 action_type_set,
525 last_ste,
526 &attr,
527 new_hw_ste_arr_sz);
528
529 return 0;
530
531out_invalid_arg:
532 return -EINVAL;
533}
534
535static unsigned int action_size[DR_ACTION_TYP_MAX] = {
536 [DR_ACTION_TYP_TNL_L2_TO_L2] = sizeof(struct mlx5dr_action_reformat),
537 [DR_ACTION_TYP_L2_TO_TNL_L2] = sizeof(struct mlx5dr_action_reformat),
538 [DR_ACTION_TYP_TNL_L3_TO_L2] = sizeof(struct mlx5dr_action_rewrite),
539 [DR_ACTION_TYP_L2_TO_TNL_L3] = sizeof(struct mlx5dr_action_reformat),
540 [DR_ACTION_TYP_FT] = sizeof(struct mlx5dr_action_dest_tbl),
541 [DR_ACTION_TYP_CTR] = sizeof(struct mlx5dr_action_ctr),
542 [DR_ACTION_TYP_TAG] = sizeof(struct mlx5dr_action_flow_tag),
543 [DR_ACTION_TYP_MODIFY_HDR] = sizeof(struct mlx5dr_action_rewrite),
544 [DR_ACTION_TYP_VPORT] = sizeof(struct mlx5dr_action_vport),
545 [DR_ACTION_TYP_PUSH_VLAN] = sizeof(struct mlx5dr_action_push_vlan),
546};
547
548static struct mlx5dr_action *
549dr_action_create_generic(enum mlx5dr_action_type action_type)
550{
551 struct mlx5dr_action *action;
552 int extra_size;
553
554 if (action_type < DR_ACTION_TYP_MAX)
555 extra_size = action_size[action_type];
556 else
557 return NULL;
558
559 action = kzalloc(sizeof(*action) + extra_size, GFP_KERNEL);
560 if (!action)
561 return NULL;
562
563 action->action_type = action_type;
564 refcount_set(&action->refcount, 1);
565 action->data = action + 1;
566
567 return action;
568}
569
570struct mlx5dr_action *mlx5dr_action_create_drop(void)
571{
572 return dr_action_create_generic(DR_ACTION_TYP_DROP);
573}
574
575struct mlx5dr_action *
576mlx5dr_action_create_dest_table_num(struct mlx5dr_domain *dmn, u32 table_num)
577{
578 struct mlx5dr_action *action;
579
580 action = dr_action_create_generic(DR_ACTION_TYP_FT);
581 if (!action)
582 return NULL;
583
584 action->dest_tbl->is_fw_tbl = true;
585 action->dest_tbl->fw_tbl.dmn = dmn;
586 action->dest_tbl->fw_tbl.id = table_num;
587 action->dest_tbl->fw_tbl.type = FS_FT_FDB;
588 refcount_inc(&dmn->refcount);
589
590 return action;
591}
592
593struct mlx5dr_action *
594mlx5dr_action_create_dest_table(struct mlx5dr_table *tbl)
595{
596 struct mlx5dr_action *action;
597
598 refcount_inc(&tbl->refcount);
599
600 action = dr_action_create_generic(DR_ACTION_TYP_FT);
601 if (!action)
602 goto dec_ref;
603
604 action->dest_tbl->tbl = tbl;
605
606 return action;
607
608dec_ref:
609 refcount_dec(&tbl->refcount);
610 return NULL;
611}
612
613struct mlx5dr_action *
614mlx5dr_action_create_mult_dest_tbl(struct mlx5dr_domain *dmn,
615 struct mlx5dr_action_dest *dests,
616 u32 num_of_dests)
617{
618 struct mlx5dr_cmd_flow_destination_hw_info *hw_dests;
619 struct mlx5dr_action **ref_actions;
620 struct mlx5dr_action *action;
621 bool reformat_req = false;
622 u32 num_of_ref = 0;
623 int ret;
624 int i;
625
626 if (dmn->type != MLX5DR_DOMAIN_TYPE_FDB) {
627 mlx5dr_err(dmn, "Multiple destination support is for FDB only\n");
628 return NULL;
629 }
630
631 hw_dests = kzalloc(sizeof(*hw_dests) * num_of_dests, GFP_KERNEL);
632 if (!hw_dests)
633 return NULL;
634
635 ref_actions = kzalloc(sizeof(*ref_actions) * num_of_dests * 2, GFP_KERNEL);
636 if (!ref_actions)
637 goto free_hw_dests;
638
639 for (i = 0; i < num_of_dests; i++) {
640 struct mlx5dr_action *reformat_action = dests[i].reformat;
641 struct mlx5dr_action *dest_action = dests[i].dest;
642
643 ref_actions[num_of_ref++] = dest_action;
644
645 switch (dest_action->action_type) {
646 case DR_ACTION_TYP_VPORT:
647 hw_dests[i].vport.flags = MLX5_FLOW_DEST_VPORT_VHCA_ID;
648 hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
649 hw_dests[i].vport.num = dest_action->vport->caps->num;
650 hw_dests[i].vport.vhca_id = dest_action->vport->caps->vhca_gvmi;
651 if (reformat_action) {
652 reformat_req = true;
653 hw_dests[i].vport.reformat_id =
654 reformat_action->reformat->reformat_id;
655 ref_actions[num_of_ref++] = reformat_action;
656 hw_dests[i].vport.flags |= MLX5_FLOW_DEST_VPORT_REFORMAT_ID;
657 }
658 break;
659
660 case DR_ACTION_TYP_FT:
661 hw_dests[i].type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
662 if (dest_action->dest_tbl->is_fw_tbl)
663 hw_dests[i].ft_id = dest_action->dest_tbl->fw_tbl.id;
664 else
665 hw_dests[i].ft_id = dest_action->dest_tbl->tbl->table_id;
666 break;
667
668 default:
669 mlx5dr_dbg(dmn, "Invalid multiple destinations action\n");
670 goto free_ref_actions;
671 }
672 }
673
674 action = dr_action_create_generic(DR_ACTION_TYP_FT);
675 if (!action)
676 goto free_ref_actions;
677
678 ret = mlx5dr_fw_create_md_tbl(dmn,
679 hw_dests,
680 num_of_dests,
681 reformat_req,
682 &action->dest_tbl->fw_tbl.id,
683 &action->dest_tbl->fw_tbl.group_id);
684 if (ret)
685 goto free_action;
686
687 refcount_inc(&dmn->refcount);
688
689 for (i = 0; i < num_of_ref; i++)
690 refcount_inc(&ref_actions[i]->refcount);
691
692 action->dest_tbl->is_fw_tbl = true;
693 action->dest_tbl->fw_tbl.dmn = dmn;
694 action->dest_tbl->fw_tbl.type = FS_FT_FDB;
695 action->dest_tbl->fw_tbl.ref_actions = ref_actions;
696 action->dest_tbl->fw_tbl.num_of_ref_actions = num_of_ref;
697
698 kfree(hw_dests);
699
700 return action;
701
702free_action:
703 kfree(action);
704free_ref_actions:
705 kfree(ref_actions);
706free_hw_dests:
707 kfree(hw_dests);
708 return NULL;
709}
710
711struct mlx5dr_action *
712mlx5dr_action_create_dest_flow_fw_table(struct mlx5dr_domain *dmn,
713 struct mlx5_flow_table *ft)
714{
715 struct mlx5dr_action *action;
716
717 action = dr_action_create_generic(DR_ACTION_TYP_FT);
718 if (!action)
719 return NULL;
720
721 action->dest_tbl->is_fw_tbl = 1;
722 action->dest_tbl->fw_tbl.type = ft->type;
723 action->dest_tbl->fw_tbl.id = ft->id;
724 action->dest_tbl->fw_tbl.dmn = dmn;
725
726 refcount_inc(&dmn->refcount);
727
728 return action;
729}
730
731struct mlx5dr_action *
732mlx5dr_action_create_flow_counter(u32 counter_id)
733{
734 struct mlx5dr_action *action;
735
736 action = dr_action_create_generic(DR_ACTION_TYP_CTR);
737 if (!action)
738 return NULL;
739
740 action->ctr->ctr_id = counter_id;
741
742 return action;
743}
744
745struct mlx5dr_action *mlx5dr_action_create_tag(u32 tag_value)
746{
747 struct mlx5dr_action *action;
748
749 action = dr_action_create_generic(DR_ACTION_TYP_TAG);
750 if (!action)
751 return NULL;
752
753 action->flow_tag->flow_tag = tag_value & 0xffffff;
754
755 return action;
756}
757
758static int
759dr_action_verify_reformat_params(enum mlx5dr_action_type reformat_type,
760 struct mlx5dr_domain *dmn,
761 size_t data_sz,
762 void *data)
763{
764 if ((!data && data_sz) || (data && !data_sz) || reformat_type >
765 DR_ACTION_TYP_L2_TO_TNL_L3) {
766 mlx5dr_dbg(dmn, "Invalid reformat parameter!\n");
767 goto out_err;
768 }
769
770 if (dmn->type == MLX5DR_DOMAIN_TYPE_FDB)
771 return 0;
772
773 if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_RX) {
774 if (reformat_type != DR_ACTION_TYP_TNL_L2_TO_L2 &&
775 reformat_type != DR_ACTION_TYP_TNL_L3_TO_L2) {
776 mlx5dr_dbg(dmn, "Action reformat type not support on RX domain\n");
777 goto out_err;
778 }
779 } else if (dmn->type == MLX5DR_DOMAIN_TYPE_NIC_TX) {
780 if (reformat_type != DR_ACTION_TYP_L2_TO_TNL_L2 &&
781 reformat_type != DR_ACTION_TYP_L2_TO_TNL_L3) {
782 mlx5dr_dbg(dmn, "Action reformat type not support on TX domain\n");
783 goto out_err;
784 }
785 }
786
787 return 0;
788
789out_err:
790 return -EINVAL;
791}
792
793#define ACTION_CACHE_LINE_SIZE 64
794
795static int
796dr_action_create_reformat_action(struct mlx5dr_domain *dmn,
797 size_t data_sz, void *data,
798 struct mlx5dr_action *action)
799{
800 u32 reformat_id;
801 int ret;
802
803 switch (action->action_type) {
804 case DR_ACTION_TYP_L2_TO_TNL_L2:
805 case DR_ACTION_TYP_L2_TO_TNL_L3:
806 {
807 enum mlx5_reformat_ctx_type rt;
808
809 if (action->action_type == DR_ACTION_TYP_L2_TO_TNL_L2)
810 rt = MLX5_REFORMAT_TYPE_L2_TO_L2_TUNNEL;
811 else
812 rt = MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL;
813
814 ret = mlx5dr_cmd_create_reformat_ctx(dmn->mdev, rt, data_sz, data,
815 &reformat_id);
816 if (ret)
817 return ret;
818
819 action->reformat->reformat_id = reformat_id;
820 action->reformat->reformat_size = data_sz;
821 return 0;
822 }
823 case DR_ACTION_TYP_TNL_L2_TO_L2:
824 {
825 return 0;
826 }
827 case DR_ACTION_TYP_TNL_L3_TO_L2:
828 {
829 u8 hw_actions[ACTION_CACHE_LINE_SIZE] = {};
830 int ret;
831
832 ret = mlx5dr_ste_set_action_decap_l3_list(dmn->ste_ctx,
833 data, data_sz,
834 hw_actions,
835 ACTION_CACHE_LINE_SIZE,
836 &action->rewrite->num_of_actions);
837 if (ret) {
838 mlx5dr_dbg(dmn, "Failed creating decap l3 action list\n");
839 return ret;
840 }
841
842 action->rewrite->chunk = mlx5dr_icm_alloc_chunk(dmn->action_icm_pool,
843 DR_CHUNK_SIZE_8);
844 if (!action->rewrite->chunk) {
845 mlx5dr_dbg(dmn, "Failed allocating modify header chunk\n");
846 return -ENOMEM;
847 }
848
849 action->rewrite->data = (void *)hw_actions;
850 action->rewrite->index = (action->rewrite->chunk->icm_addr -
851 dmn->info.caps.hdr_modify_icm_addr) /
852 ACTION_CACHE_LINE_SIZE;
853
854 ret = mlx5dr_send_postsend_action(dmn, action);
855 if (ret) {
856 mlx5dr_dbg(dmn, "Writing decap l3 actions to ICM failed\n");
857 mlx5dr_icm_free_chunk(action->rewrite->chunk);
858 return ret;
859 }
860 return 0;
861 }
862 default:
863 mlx5dr_info(dmn, "Reformat type is not supported %d\n", action->action_type);
864 return -EINVAL;
865 }
866}
867
868#define CVLAN_ETHERTYPE 0x8100
869#define SVLAN_ETHERTYPE 0x88a8
870
871struct mlx5dr_action *mlx5dr_action_create_pop_vlan(void)
872{
873 return dr_action_create_generic(DR_ACTION_TYP_POP_VLAN);
874}
875
876struct mlx5dr_action *mlx5dr_action_create_push_vlan(struct mlx5dr_domain *dmn,
877 __be32 vlan_hdr)
878{
879 u32 vlan_hdr_h = ntohl(vlan_hdr);
880 u16 ethertype = vlan_hdr_h >> 16;
881 struct mlx5dr_action *action;
882
883 if (ethertype != SVLAN_ETHERTYPE && ethertype != CVLAN_ETHERTYPE) {
884 mlx5dr_dbg(dmn, "Invalid vlan ethertype\n");
885 return NULL;
886 }
887
888 action = dr_action_create_generic(DR_ACTION_TYP_PUSH_VLAN);
889 if (!action)
890 return NULL;
891
892 action->push_vlan->vlan_hdr = vlan_hdr_h;
893 return action;
894}
895
896struct mlx5dr_action *
897mlx5dr_action_create_packet_reformat(struct mlx5dr_domain *dmn,
898 enum mlx5dr_action_reformat_type reformat_type,
899 size_t data_sz,
900 void *data)
901{
902 enum mlx5dr_action_type action_type;
903 struct mlx5dr_action *action;
904 int ret;
905
906 refcount_inc(&dmn->refcount);
907
908
909 ret = dr_action_reformat_to_action_type(reformat_type, &action_type);
910 if (ret) {
911 mlx5dr_dbg(dmn, "Invalid reformat_type provided\n");
912 goto dec_ref;
913 }
914
915 ret = dr_action_verify_reformat_params(action_type, dmn, data_sz, data);
916 if (ret)
917 goto dec_ref;
918
919 action = dr_action_create_generic(action_type);
920 if (!action)
921 goto dec_ref;
922
923 action->reformat->dmn = dmn;
924
925 ret = dr_action_create_reformat_action(dmn,
926 data_sz,
927 data,
928 action);
929 if (ret) {
930 mlx5dr_dbg(dmn, "Failed creating reformat action %d\n", ret);
931 goto free_action;
932 }
933
934 return action;
935
936free_action:
937 kfree(action);
938dec_ref:
939 refcount_dec(&dmn->refcount);
940 return NULL;
941}
942
943static int
944dr_action_modify_sw_to_hw_add(struct mlx5dr_domain *dmn,
945 __be64 *sw_action,
946 __be64 *hw_action,
947 const struct mlx5dr_ste_action_modify_field **ret_hw_info)
948{
949 const struct mlx5dr_ste_action_modify_field *hw_action_info;
950 u8 max_length;
951 u16 sw_field;
952 u32 data;
953
954
955 sw_field = MLX5_GET(set_action_in, sw_action, field);
956 data = MLX5_GET(set_action_in, sw_action, data);
957
958
959 hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field);
960 if (!hw_action_info) {
961 mlx5dr_dbg(dmn, "Modify add action invalid field given\n");
962 return -EINVAL;
963 }
964
965 max_length = hw_action_info->end - hw_action_info->start + 1;
966
967 mlx5dr_ste_set_action_add(dmn->ste_ctx,
968 hw_action,
969 hw_action_info->hw_field,
970 hw_action_info->start,
971 max_length,
972 data);
973
974 *ret_hw_info = hw_action_info;
975
976 return 0;
977}
978
979static int
980dr_action_modify_sw_to_hw_set(struct mlx5dr_domain *dmn,
981 __be64 *sw_action,
982 __be64 *hw_action,
983 const struct mlx5dr_ste_action_modify_field **ret_hw_info)
984{
985 const struct mlx5dr_ste_action_modify_field *hw_action_info;
986 u8 offset, length, max_length;
987 u16 sw_field;
988 u32 data;
989
990
991 length = MLX5_GET(set_action_in, sw_action, length);
992 offset = MLX5_GET(set_action_in, sw_action, offset);
993 sw_field = MLX5_GET(set_action_in, sw_action, field);
994 data = MLX5_GET(set_action_in, sw_action, data);
995
996
997 hw_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, sw_field);
998 if (!hw_action_info) {
999 mlx5dr_dbg(dmn, "Modify set action invalid field given\n");
1000 return -EINVAL;
1001 }
1002
1003
1004 length = length ? length : 32;
1005
1006 max_length = hw_action_info->end - hw_action_info->start + 1;
1007
1008 if (length + offset > max_length) {
1009 mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n");
1010 return -EINVAL;
1011 }
1012
1013 mlx5dr_ste_set_action_set(dmn->ste_ctx,
1014 hw_action,
1015 hw_action_info->hw_field,
1016 hw_action_info->start + offset,
1017 length,
1018 data);
1019
1020 *ret_hw_info = hw_action_info;
1021
1022 return 0;
1023}
1024
1025static int
1026dr_action_modify_sw_to_hw_copy(struct mlx5dr_domain *dmn,
1027 __be64 *sw_action,
1028 __be64 *hw_action,
1029 const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info,
1030 const struct mlx5dr_ste_action_modify_field **ret_src_hw_info)
1031{
1032 u8 src_offset, dst_offset, src_max_length, dst_max_length, length;
1033 const struct mlx5dr_ste_action_modify_field *hw_dst_action_info;
1034 const struct mlx5dr_ste_action_modify_field *hw_src_action_info;
1035 u16 src_field, dst_field;
1036
1037
1038 src_field = MLX5_GET(copy_action_in, sw_action, src_field);
1039 dst_field = MLX5_GET(copy_action_in, sw_action, dst_field);
1040 src_offset = MLX5_GET(copy_action_in, sw_action, src_offset);
1041 dst_offset = MLX5_GET(copy_action_in, sw_action, dst_offset);
1042 length = MLX5_GET(copy_action_in, sw_action, length);
1043
1044
1045 hw_src_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, src_field);
1046 hw_dst_action_info = mlx5dr_ste_conv_modify_hdr_sw_field(dmn->ste_ctx, dst_field);
1047 if (!hw_src_action_info || !hw_dst_action_info) {
1048 mlx5dr_dbg(dmn, "Modify copy action invalid field given\n");
1049 return -EINVAL;
1050 }
1051
1052
1053 length = length ? length : 32;
1054
1055 src_max_length = hw_src_action_info->end -
1056 hw_src_action_info->start + 1;
1057 dst_max_length = hw_dst_action_info->end -
1058 hw_dst_action_info->start + 1;
1059
1060 if (length + src_offset > src_max_length ||
1061 length + dst_offset > dst_max_length) {
1062 mlx5dr_dbg(dmn, "Modify action length + offset exceeds limit\n");
1063 return -EINVAL;
1064 }
1065
1066 mlx5dr_ste_set_action_copy(dmn->ste_ctx,
1067 hw_action,
1068 hw_dst_action_info->hw_field,
1069 hw_dst_action_info->start + dst_offset,
1070 length,
1071 hw_src_action_info->hw_field,
1072 hw_src_action_info->start + src_offset);
1073
1074 *ret_dst_hw_info = hw_dst_action_info;
1075 *ret_src_hw_info = hw_src_action_info;
1076
1077 return 0;
1078}
1079
1080static int
1081dr_action_modify_sw_to_hw(struct mlx5dr_domain *dmn,
1082 __be64 *sw_action,
1083 __be64 *hw_action,
1084 const struct mlx5dr_ste_action_modify_field **ret_dst_hw_info,
1085 const struct mlx5dr_ste_action_modify_field **ret_src_hw_info)
1086{
1087 u8 action;
1088 int ret;
1089
1090 *hw_action = 0;
1091 *ret_src_hw_info = NULL;
1092
1093
1094 action = MLX5_GET(set_action_in, sw_action, action_type);
1095
1096 switch (action) {
1097 case MLX5_ACTION_TYPE_SET:
1098 ret = dr_action_modify_sw_to_hw_set(dmn, sw_action,
1099 hw_action,
1100 ret_dst_hw_info);
1101 break;
1102
1103 case MLX5_ACTION_TYPE_ADD:
1104 ret = dr_action_modify_sw_to_hw_add(dmn, sw_action,
1105 hw_action,
1106 ret_dst_hw_info);
1107 break;
1108
1109 case MLX5_ACTION_TYPE_COPY:
1110 ret = dr_action_modify_sw_to_hw_copy(dmn, sw_action,
1111 hw_action,
1112 ret_dst_hw_info,
1113 ret_src_hw_info);
1114 break;
1115
1116 default:
1117 mlx5dr_info(dmn, "Unsupported action_type for modify action\n");
1118 ret = -EOPNOTSUPP;
1119 }
1120
1121 return ret;
1122}
1123
1124static int
1125dr_action_modify_check_set_field_limitation(struct mlx5dr_action *action,
1126 const __be64 *sw_action)
1127{
1128 u16 sw_field = MLX5_GET(set_action_in, sw_action, field);
1129 struct mlx5dr_domain *dmn = action->rewrite->dmn;
1130
1131 if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_A) {
1132 action->rewrite->allow_rx = 0;
1133 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) {
1134 mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n",
1135 sw_field);
1136 return -EINVAL;
1137 }
1138 } else if (sw_field == MLX5_ACTION_IN_FIELD_METADATA_REG_B) {
1139 action->rewrite->allow_tx = 0;
1140 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) {
1141 mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n",
1142 sw_field);
1143 return -EINVAL;
1144 }
1145 }
1146
1147 if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) {
1148 mlx5dr_dbg(dmn, "Modify SET actions not supported on both RX and TX\n");
1149 return -EINVAL;
1150 }
1151
1152 return 0;
1153}
1154
1155static int
1156dr_action_modify_check_add_field_limitation(struct mlx5dr_action *action,
1157 const __be64 *sw_action)
1158{
1159 u16 sw_field = MLX5_GET(set_action_in, sw_action, field);
1160 struct mlx5dr_domain *dmn = action->rewrite->dmn;
1161
1162 if (sw_field != MLX5_ACTION_IN_FIELD_OUT_IP_TTL &&
1163 sw_field != MLX5_ACTION_IN_FIELD_OUT_IPV6_HOPLIMIT &&
1164 sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_SEQ_NUM &&
1165 sw_field != MLX5_ACTION_IN_FIELD_OUT_TCP_ACK_NUM) {
1166 mlx5dr_dbg(dmn, "Unsupported field %d for add action\n",
1167 sw_field);
1168 return -EINVAL;
1169 }
1170
1171 return 0;
1172}
1173
1174static int
1175dr_action_modify_check_copy_field_limitation(struct mlx5dr_action *action,
1176 const __be64 *sw_action)
1177{
1178 struct mlx5dr_domain *dmn = action->rewrite->dmn;
1179 u16 sw_fields[2];
1180 int i;
1181
1182 sw_fields[0] = MLX5_GET(copy_action_in, sw_action, src_field);
1183 sw_fields[1] = MLX5_GET(copy_action_in, sw_action, dst_field);
1184
1185 for (i = 0; i < 2; i++) {
1186 if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_A) {
1187 action->rewrite->allow_rx = 0;
1188 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_TX) {
1189 mlx5dr_dbg(dmn, "Unsupported field %d for RX/FDB set action\n",
1190 sw_fields[i]);
1191 return -EINVAL;
1192 }
1193 } else if (sw_fields[i] == MLX5_ACTION_IN_FIELD_METADATA_REG_B) {
1194 action->rewrite->allow_tx = 0;
1195 if (dmn->type != MLX5DR_DOMAIN_TYPE_NIC_RX) {
1196 mlx5dr_dbg(dmn, "Unsupported field %d for TX/FDB set action\n",
1197 sw_fields[i]);
1198 return -EINVAL;
1199 }
1200 }
1201 }
1202
1203 if (!action->rewrite->allow_rx && !action->rewrite->allow_tx) {
1204 mlx5dr_dbg(dmn, "Modify copy actions not supported on both RX and TX\n");
1205 return -EINVAL;
1206 }
1207
1208 return 0;
1209}
1210
1211static int
1212dr_action_modify_check_field_limitation(struct mlx5dr_action *action,
1213 const __be64 *sw_action)
1214{
1215 struct mlx5dr_domain *dmn = action->rewrite->dmn;
1216 u8 action_type;
1217 int ret;
1218
1219 action_type = MLX5_GET(set_action_in, sw_action, action_type);
1220
1221 switch (action_type) {
1222 case MLX5_ACTION_TYPE_SET:
1223 ret = dr_action_modify_check_set_field_limitation(action,
1224 sw_action);
1225 break;
1226
1227 case MLX5_ACTION_TYPE_ADD:
1228 ret = dr_action_modify_check_add_field_limitation(action,
1229 sw_action);
1230 break;
1231
1232 case MLX5_ACTION_TYPE_COPY:
1233 ret = dr_action_modify_check_copy_field_limitation(action,
1234 sw_action);
1235 break;
1236
1237 default:
1238 mlx5dr_info(dmn, "Unsupported action %d modify action\n",
1239 action_type);
1240 ret = -EOPNOTSUPP;
1241 }
1242
1243 return ret;
1244}
1245
1246static bool
1247dr_action_modify_check_is_ttl_modify(const void *sw_action)
1248{
1249 u16 sw_field = MLX5_GET(set_action_in, sw_action, field);
1250
1251 return sw_field == MLX5_ACTION_IN_FIELD_OUT_IP_TTL;
1252}
1253
1254static int dr_actions_convert_modify_header(struct mlx5dr_action *action,
1255 u32 max_hw_actions,
1256 u32 num_sw_actions,
1257 __be64 sw_actions[],
1258 __be64 hw_actions[],
1259 u32 *num_hw_actions,
1260 bool *modify_ttl)
1261{
1262 const struct mlx5dr_ste_action_modify_field *hw_dst_action_info;
1263 const struct mlx5dr_ste_action_modify_field *hw_src_action_info;
1264 struct mlx5dr_domain *dmn = action->rewrite->dmn;
1265 int ret, i, hw_idx = 0;
1266 __be64 *sw_action;
1267 __be64 hw_action;
1268 u16 hw_field = 0;
1269 u32 l3_type = 0;
1270 u32 l4_type = 0;
1271
1272 *modify_ttl = false;
1273
1274 action->rewrite->allow_rx = 1;
1275 action->rewrite->allow_tx = 1;
1276
1277 for (i = 0; i < num_sw_actions; i++) {
1278 sw_action = &sw_actions[i];
1279
1280 ret = dr_action_modify_check_field_limitation(action,
1281 sw_action);
1282 if (ret)
1283 return ret;
1284
1285 if (!(*modify_ttl))
1286 *modify_ttl = dr_action_modify_check_is_ttl_modify(sw_action);
1287
1288
1289 ret = dr_action_modify_sw_to_hw(dmn,
1290 sw_action,
1291 &hw_action,
1292 &hw_dst_action_info,
1293 &hw_src_action_info);
1294 if (ret)
1295 return ret;
1296
1297
1298 if (l3_type && hw_dst_action_info->l3_type &&
1299 hw_dst_action_info->l3_type != l3_type) {
1300 mlx5dr_dbg(dmn, "Action list can't support two different L3 types\n");
1301 return -EINVAL;
1302 }
1303 if (hw_dst_action_info->l3_type)
1304 l3_type = hw_dst_action_info->l3_type;
1305
1306
1307 if (l4_type && hw_dst_action_info->l4_type &&
1308 hw_dst_action_info->l4_type != l4_type) {
1309 mlx5dr_dbg(dmn, "Action list can't support two different L4 types\n");
1310 return -EINVAL;
1311 }
1312 if (hw_dst_action_info->l4_type)
1313 l4_type = hw_dst_action_info->l4_type;
1314
1315
1316
1317
1318 if ((hw_idx % 2) && (hw_field == hw_dst_action_info->hw_field ||
1319 (hw_src_action_info &&
1320 hw_field == hw_src_action_info->hw_field))) {
1321
1322
1323
1324 hw_idx++;
1325 if ((num_sw_actions + hw_idx - i) >= max_hw_actions) {
1326 mlx5dr_dbg(dmn, "Modify header action number exceeds HW limit\n");
1327 return -EINVAL;
1328 }
1329 }
1330 hw_field = hw_dst_action_info->hw_field;
1331
1332 hw_actions[hw_idx] = hw_action;
1333 hw_idx++;
1334 }
1335
1336 *num_hw_actions = hw_idx;
1337
1338 return 0;
1339}
1340
1341static int dr_action_create_modify_action(struct mlx5dr_domain *dmn,
1342 size_t actions_sz,
1343 __be64 actions[],
1344 struct mlx5dr_action *action)
1345{
1346 struct mlx5dr_icm_chunk *chunk;
1347 u32 max_hw_actions;
1348 u32 num_hw_actions;
1349 u32 num_sw_actions;
1350 __be64 *hw_actions;
1351 bool modify_ttl;
1352 int ret;
1353
1354 num_sw_actions = actions_sz / DR_MODIFY_ACTION_SIZE;
1355 max_hw_actions = mlx5dr_icm_pool_chunk_size_to_entries(DR_CHUNK_SIZE_16);
1356
1357 if (num_sw_actions > max_hw_actions) {
1358 mlx5dr_dbg(dmn, "Max number of actions %d exceeds limit %d\n",
1359 num_sw_actions, max_hw_actions);
1360 return -EINVAL;
1361 }
1362
1363 chunk = mlx5dr_icm_alloc_chunk(dmn->action_icm_pool, DR_CHUNK_SIZE_16);
1364 if (!chunk)
1365 return -ENOMEM;
1366
1367 hw_actions = kcalloc(1, max_hw_actions * DR_MODIFY_ACTION_SIZE, GFP_KERNEL);
1368 if (!hw_actions) {
1369 ret = -ENOMEM;
1370 goto free_chunk;
1371 }
1372
1373 ret = dr_actions_convert_modify_header(action,
1374 max_hw_actions,
1375 num_sw_actions,
1376 actions,
1377 hw_actions,
1378 &num_hw_actions,
1379 &modify_ttl);
1380 if (ret)
1381 goto free_hw_actions;
1382
1383 action->rewrite->chunk = chunk;
1384 action->rewrite->modify_ttl = modify_ttl;
1385 action->rewrite->data = (u8 *)hw_actions;
1386 action->rewrite->num_of_actions = num_hw_actions;
1387 action->rewrite->index = (chunk->icm_addr -
1388 dmn->info.caps.hdr_modify_icm_addr) /
1389 ACTION_CACHE_LINE_SIZE;
1390
1391 ret = mlx5dr_send_postsend_action(dmn, action);
1392 if (ret)
1393 goto free_hw_actions;
1394
1395 return 0;
1396
1397free_hw_actions:
1398 kfree(hw_actions);
1399free_chunk:
1400 mlx5dr_icm_free_chunk(chunk);
1401 return ret;
1402}
1403
1404struct mlx5dr_action *
1405mlx5dr_action_create_modify_header(struct mlx5dr_domain *dmn,
1406 u32 flags,
1407 size_t actions_sz,
1408 __be64 actions[])
1409{
1410 struct mlx5dr_action *action;
1411 int ret = 0;
1412
1413 refcount_inc(&dmn->refcount);
1414
1415 if (actions_sz % DR_MODIFY_ACTION_SIZE) {
1416 mlx5dr_dbg(dmn, "Invalid modify actions size provided\n");
1417 goto dec_ref;
1418 }
1419
1420 action = dr_action_create_generic(DR_ACTION_TYP_MODIFY_HDR);
1421 if (!action)
1422 goto dec_ref;
1423
1424 action->rewrite->dmn = dmn;
1425
1426 ret = dr_action_create_modify_action(dmn,
1427 actions_sz,
1428 actions,
1429 action);
1430 if (ret) {
1431 mlx5dr_dbg(dmn, "Failed creating modify header action %d\n", ret);
1432 goto free_action;
1433 }
1434
1435 return action;
1436
1437free_action:
1438 kfree(action);
1439dec_ref:
1440 refcount_dec(&dmn->refcount);
1441 return NULL;
1442}
1443
1444struct mlx5dr_action *
1445mlx5dr_action_create_dest_vport(struct mlx5dr_domain *dmn,
1446 u32 vport, u8 vhca_id_valid,
1447 u16 vhca_id)
1448{
1449 struct mlx5dr_cmd_vport_cap *vport_cap;
1450 struct mlx5dr_domain *vport_dmn;
1451 struct mlx5dr_action *action;
1452 u8 peer_vport;
1453
1454 peer_vport = vhca_id_valid && (vhca_id != dmn->info.caps.gvmi);
1455 vport_dmn = peer_vport ? dmn->peer_dmn : dmn;
1456 if (!vport_dmn) {
1457 mlx5dr_dbg(dmn, "No peer vport domain for given vhca_id\n");
1458 return NULL;
1459 }
1460
1461 if (vport_dmn->type != MLX5DR_DOMAIN_TYPE_FDB) {
1462 mlx5dr_dbg(dmn, "Domain doesn't support vport actions\n");
1463 return NULL;
1464 }
1465
1466 vport_cap = mlx5dr_get_vport_cap(&vport_dmn->info.caps, vport);
1467 if (!vport_cap) {
1468 mlx5dr_dbg(dmn, "Failed to get vport %d caps\n", vport);
1469 return NULL;
1470 }
1471
1472 action = dr_action_create_generic(DR_ACTION_TYP_VPORT);
1473 if (!action)
1474 return NULL;
1475
1476 action->vport->dmn = vport_dmn;
1477 action->vport->caps = vport_cap;
1478
1479 return action;
1480}
1481
1482int mlx5dr_action_destroy(struct mlx5dr_action *action)
1483{
1484 if (refcount_read(&action->refcount) > 1)
1485 return -EBUSY;
1486
1487 switch (action->action_type) {
1488 case DR_ACTION_TYP_FT:
1489 if (action->dest_tbl->is_fw_tbl)
1490 refcount_dec(&action->dest_tbl->fw_tbl.dmn->refcount);
1491 else
1492 refcount_dec(&action->dest_tbl->tbl->refcount);
1493
1494 if (action->dest_tbl->is_fw_tbl &&
1495 action->dest_tbl->fw_tbl.num_of_ref_actions) {
1496 struct mlx5dr_action **ref_actions;
1497 int i;
1498
1499 ref_actions = action->dest_tbl->fw_tbl.ref_actions;
1500 for (i = 0; i < action->dest_tbl->fw_tbl.num_of_ref_actions; i++)
1501 refcount_dec(&ref_actions[i]->refcount);
1502
1503 kfree(ref_actions);
1504
1505 mlx5dr_fw_destroy_md_tbl(action->dest_tbl->fw_tbl.dmn,
1506 action->dest_tbl->fw_tbl.id,
1507 action->dest_tbl->fw_tbl.group_id);
1508 }
1509 break;
1510 case DR_ACTION_TYP_TNL_L2_TO_L2:
1511 refcount_dec(&action->reformat->dmn->refcount);
1512 break;
1513 case DR_ACTION_TYP_TNL_L3_TO_L2:
1514 mlx5dr_icm_free_chunk(action->rewrite->chunk);
1515 refcount_dec(&action->rewrite->dmn->refcount);
1516 break;
1517 case DR_ACTION_TYP_L2_TO_TNL_L2:
1518 case DR_ACTION_TYP_L2_TO_TNL_L3:
1519 mlx5dr_cmd_destroy_reformat_ctx((action->reformat->dmn)->mdev,
1520 action->reformat->reformat_id);
1521 refcount_dec(&action->reformat->dmn->refcount);
1522 break;
1523 case DR_ACTION_TYP_MODIFY_HDR:
1524 mlx5dr_icm_free_chunk(action->rewrite->chunk);
1525 kfree(action->rewrite->data);
1526 refcount_dec(&action->rewrite->dmn->refcount);
1527 break;
1528 default:
1529 break;
1530 }
1531
1532 kfree(action);
1533 return 0;
1534}
1535