net/mlx5: DR, Allow encap action for RX for supporting devices
[linux-block.git] / drivers / net / ethernet / mellanox / mlx5 / core / fs_cmd.c
CommitLineData
26a81453
MG
1/*
2 * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
3 *
4 * This software is available to you under a choice of one of two
5 * licenses. You may choose to be licensed under the terms of the GNU
6 * General Public License (GPL) Version 2, available from the file
7 * COPYING in the main directory of this source tree, or the
8 * OpenIB.org BSD license below:
9 *
10 * Redistribution and use in source and binary forms, with or
11 * without modification, are permitted provided that the following
12 * conditions are met:
13 *
14 * - Redistributions of source code must retain the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer.
17 *
18 * - Redistributions in binary form must reproduce the above
19 * copyright notice, this list of conditions and the following
20 * disclaimer in the documentation and/or other materials
21 * provided with the distribution.
22 *
23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30 * SOFTWARE.
31 */
32
33#include <linux/mlx5/driver.h>
34#include <linux/mlx5/device.h>
35#include <linux/mlx5/mlx5_ifc.h>
36
37#include "fs_core.h"
38#include "fs_cmd.h"
4a98544d 39#include "fs_ft_pool.h"
26a81453 40#include "mlx5_core.h"
c9f1b073 41#include "eswitch.h"
26a81453 42
ae288a48 43static int mlx5_cmd_stub_update_root_ft(struct mlx5_flow_root_namespace *ns,
af76c501
MB
44 struct mlx5_flow_table *ft,
45 u32 underlay_qpn,
46 bool disconnect)
47{
48 return 0;
49}
50
ae288a48
MG
51static int mlx5_cmd_stub_create_flow_table(struct mlx5_flow_root_namespace *ns,
52 struct mlx5_flow_table *ft,
04745afb 53 unsigned int size,
ae288a48 54 struct mlx5_flow_table *next_ft)
af76c501 55{
04745afb
PB
56 ft->max_fte = size ? roundup_pow_of_two(size) : 1;
57
af76c501
MB
58 return 0;
59}
60
ae288a48 61static int mlx5_cmd_stub_destroy_flow_table(struct mlx5_flow_root_namespace *ns,
af76c501
MB
62 struct mlx5_flow_table *ft)
63{
64 return 0;
65}
66
ae288a48 67static int mlx5_cmd_stub_modify_flow_table(struct mlx5_flow_root_namespace *ns,
af76c501
MB
68 struct mlx5_flow_table *ft,
69 struct mlx5_flow_table *next_ft)
70{
71 return 0;
72}
73
ae288a48 74static int mlx5_cmd_stub_create_flow_group(struct mlx5_flow_root_namespace *ns,
af76c501
MB
75 struct mlx5_flow_table *ft,
76 u32 *in,
ae288a48 77 struct mlx5_flow_group *fg)
af76c501
MB
78{
79 return 0;
80}
81
ae288a48 82static int mlx5_cmd_stub_destroy_flow_group(struct mlx5_flow_root_namespace *ns,
af76c501 83 struct mlx5_flow_table *ft,
ae288a48 84 struct mlx5_flow_group *fg)
af76c501
MB
85{
86 return 0;
87}
88
ae288a48 89static int mlx5_cmd_stub_create_fte(struct mlx5_flow_root_namespace *ns,
af76c501
MB
90 struct mlx5_flow_table *ft,
91 struct mlx5_flow_group *group,
92 struct fs_fte *fte)
93{
94 return 0;
95}
96
ae288a48 97static int mlx5_cmd_stub_update_fte(struct mlx5_flow_root_namespace *ns,
af76c501 98 struct mlx5_flow_table *ft,
ae288a48 99 struct mlx5_flow_group *group,
af76c501
MB
100 int modify_mask,
101 struct fs_fte *fte)
102{
103 return -EOPNOTSUPP;
104}
105
ae288a48 106static int mlx5_cmd_stub_delete_fte(struct mlx5_flow_root_namespace *ns,
af76c501 107 struct mlx5_flow_table *ft,
e810bf5e 108 struct fs_fte *fte)
af76c501
MB
109{
110 return 0;
111}
112
2b688ea5
MG
113static int mlx5_cmd_stub_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
114 int reformat_type,
115 size_t size,
116 void *reformat_data,
117 enum mlx5_flow_namespace_type namespace,
118 struct mlx5_pkt_reformat *pkt_reformat)
119{
120 return 0;
121}
122
123static void mlx5_cmd_stub_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns,
124 struct mlx5_pkt_reformat *pkt_reformat)
125{
126}
127
128static int mlx5_cmd_stub_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
129 u8 namespace, u8 num_actions,
130 void *modify_actions,
131 struct mlx5_modify_hdr *modify_hdr)
132{
133 return 0;
134}
135
136static void mlx5_cmd_stub_modify_header_dealloc(struct mlx5_flow_root_namespace *ns,
137 struct mlx5_modify_hdr *modify_hdr)
138{
139}
140
6a48faee
MG
141static int mlx5_cmd_stub_set_peer(struct mlx5_flow_root_namespace *ns,
142 struct mlx5_flow_root_namespace *peer_ns)
143{
144 return 0;
145}
146
147static int mlx5_cmd_stub_create_ns(struct mlx5_flow_root_namespace *ns)
148{
149 return 0;
150}
151
152static int mlx5_cmd_stub_destroy_ns(struct mlx5_flow_root_namespace *ns)
153{
154 return 0;
155}
156
ae288a48 157static int mlx5_cmd_update_root_ft(struct mlx5_flow_root_namespace *ns,
af76c501
MB
158 struct mlx5_flow_table *ft, u32 underlay_qpn,
159 bool disconnect)
2cc43b49 160{
31a0956e 161 u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)] = {};
ae288a48 162 struct mlx5_core_dev *dev = ns->dev;
2cc43b49 163
b3ba5149 164 if ((MLX5_CAP_GEN(dev, port_type) == MLX5_CAP_PORT_TYPE_IB) &&
50854114 165 underlay_qpn == 0)
b3ba5149
ES
166 return 0;
167
2cc43b49
MG
168 MLX5_SET(set_flow_table_root_in, in, opcode,
169 MLX5_CMD_OP_SET_FLOW_TABLE_ROOT);
170 MLX5_SET(set_flow_table_root_in, in, table_type, ft->type);
dae37456 171
31a0956e 172 if (disconnect)
dae37456 173 MLX5_SET(set_flow_table_root_in, in, op_mod, 1);
31a0956e 174 else
dae37456 175 MLX5_SET(set_flow_table_root_in, in, table_id, ft->id);
dae37456 176
50854114 177 MLX5_SET(set_flow_table_root_in, in, underlay_qpn, underlay_qpn);
617b860c
PP
178 MLX5_SET(set_flow_table_root_in, in, vport_number, ft->vport);
179 MLX5_SET(set_flow_table_root_in, in, other_vport,
180 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
2cc43b49 181
31a0956e 182 return mlx5_cmd_exec_in(dev, set_flow_table_root, in);
2cc43b49
MG
183}
184
ae288a48
MG
185static int mlx5_cmd_create_flow_table(struct mlx5_flow_root_namespace *ns,
186 struct mlx5_flow_table *ft,
04745afb 187 unsigned int size,
ae288a48 188 struct mlx5_flow_table *next_ft)
26a81453 189{
ae288a48
MG
190 int en_encap = !!(ft->flags & MLX5_FLOW_TABLE_TUNNEL_EN_REFORMAT);
191 int en_decap = !!(ft->flags & MLX5_FLOW_TABLE_TUNNEL_EN_DECAP);
c6d4e45d 192 int term = !!(ft->flags & MLX5_FLOW_TABLE_TERMINATION);
31a0956e
LR
193 u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {};
194 u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {};
ae288a48 195 struct mlx5_core_dev *dev = ns->dev;
26a81453
MG
196 int err;
197
4a98544d
PB
198 if (size != POOL_NEXT_SIZE)
199 size = roundup_pow_of_two(size);
200 size = mlx5_ft_pool_get_avail_sz(dev, ft->type, size);
201 if (!size)
202 return -ENOSPC;
04745afb 203
26a81453
MG
204 MLX5_SET(create_flow_table_in, in, opcode,
205 MLX5_CMD_OP_CREATE_FLOW_TABLE);
206
ae288a48
MG
207 MLX5_SET(create_flow_table_in, in, table_type, ft->type);
208 MLX5_SET(create_flow_table_in, in, flow_table_context.level, ft->level);
4a98544d 209 MLX5_SET(create_flow_table_in, in, flow_table_context.log_size, size ? ilog2(size) : 0);
617b860c
PP
210 MLX5_SET(create_flow_table_in, in, vport_number, ft->vport);
211 MLX5_SET(create_flow_table_in, in, other_vport,
212 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
26a81453 213
0c90e9c6 214 MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en,
61444b45 215 en_decap);
60786f09 216 MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en,
61444b45 217 en_encap);
c6d4e45d
EB
218 MLX5_SET(create_flow_table_in, in, flow_table_context.termination_table,
219 term);
c9f1b073 220
ae288a48 221 switch (ft->op_mod) {
aaff1bea
AH
222 case FS_FT_OP_MOD_NORMAL:
223 if (next_ft) {
0c90e9c6 224 MLX5_SET(create_flow_table_in, in,
f6f7d6b5
MG
225 flow_table_context.table_miss_action,
226 MLX5_FLOW_TABLE_MISS_ACTION_FWD);
0c90e9c6
MG
227 MLX5_SET(create_flow_table_in, in,
228 flow_table_context.table_miss_id, next_ft->id);
f6f7d6b5
MG
229 } else {
230 MLX5_SET(create_flow_table_in, in,
231 flow_table_context.table_miss_action,
f66ad830 232 ft->def_miss_action);
aaff1bea
AH
233 }
234 break;
235
236 case FS_FT_OP_MOD_LAG_DEMUX:
237 MLX5_SET(create_flow_table_in, in, op_mod, 0x1);
238 if (next_ft)
0c90e9c6
MG
239 MLX5_SET(create_flow_table_in, in,
240 flow_table_context.lag_master_next_table_id,
aaff1bea
AH
241 next_ft->id);
242 break;
243 }
244
31a0956e 245 err = mlx5_cmd_exec_inout(dev, create_flow_table, in, out);
4a98544d 246 if (!err) {
ae288a48
MG
247 ft->id = MLX5_GET(create_flow_table_out, out,
248 table_id);
4a98544d
PB
249 ft->max_fte = size;
250 } else {
251 mlx5_ft_pool_put_sz(ns->dev, size);
252 }
253
26a81453
MG
254 return err;
255}
256
ae288a48 257static int mlx5_cmd_destroy_flow_table(struct mlx5_flow_root_namespace *ns,
af76c501 258 struct mlx5_flow_table *ft)
26a81453 259{
31a0956e 260 u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {};
ae288a48 261 struct mlx5_core_dev *dev = ns->dev;
4a98544d 262 int err;
26a81453
MG
263
264 MLX5_SET(destroy_flow_table_in, in, opcode,
265 MLX5_CMD_OP_DESTROY_FLOW_TABLE);
266 MLX5_SET(destroy_flow_table_in, in, table_type, ft->type);
267 MLX5_SET(destroy_flow_table_in, in, table_id, ft->id);
617b860c
PP
268 MLX5_SET(destroy_flow_table_in, in, vport_number, ft->vport);
269 MLX5_SET(destroy_flow_table_in, in, other_vport,
270 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
26a81453 271
4a98544d
PB
272 err = mlx5_cmd_exec_in(dev, destroy_flow_table, in);
273 if (!err)
274 mlx5_ft_pool_put_sz(ns->dev, ft->max_fte);
275
276 return err;
26a81453
MG
277}
278
ae288a48 279static int mlx5_cmd_modify_flow_table(struct mlx5_flow_root_namespace *ns,
af76c501
MB
280 struct mlx5_flow_table *ft,
281 struct mlx5_flow_table *next_ft)
34a40e68 282{
31a0956e 283 u32 in[MLX5_ST_SZ_DW(modify_flow_table_in)] = {};
ae288a48 284 struct mlx5_core_dev *dev = ns->dev;
34a40e68
MG
285
286 MLX5_SET(modify_flow_table_in, in, opcode,
287 MLX5_CMD_OP_MODIFY_FLOW_TABLE);
288 MLX5_SET(modify_flow_table_in, in, table_type, ft->type);
289 MLX5_SET(modify_flow_table_in, in, table_id, ft->id);
aaff1bea
AH
290
291 if (ft->op_mod == FS_FT_OP_MOD_LAG_DEMUX) {
292 MLX5_SET(modify_flow_table_in, in, modify_field_select,
293 MLX5_MODIFY_FLOW_TABLE_LAG_NEXT_TABLE_ID);
294 if (next_ft) {
295 MLX5_SET(modify_flow_table_in, in,
0c90e9c6 296 flow_table_context.lag_master_next_table_id, next_ft->id);
aaff1bea
AH
297 } else {
298 MLX5_SET(modify_flow_table_in, in,
0c90e9c6 299 flow_table_context.lag_master_next_table_id, 0);
aaff1bea 300 }
34a40e68 301 } else {
617b860c
PP
302 MLX5_SET(modify_flow_table_in, in, vport_number, ft->vport);
303 MLX5_SET(modify_flow_table_in, in, other_vport,
304 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
aaff1bea
AH
305 MLX5_SET(modify_flow_table_in, in, modify_field_select,
306 MLX5_MODIFY_FLOW_TABLE_MISS_TABLE_ID);
307 if (next_ft) {
0c90e9c6 308 MLX5_SET(modify_flow_table_in, in,
f6f7d6b5
MG
309 flow_table_context.table_miss_action,
310 MLX5_FLOW_TABLE_MISS_ACTION_FWD);
0c90e9c6
MG
311 MLX5_SET(modify_flow_table_in, in,
312 flow_table_context.table_miss_id,
aaff1bea
AH
313 next_ft->id);
314 } else {
0c90e9c6 315 MLX5_SET(modify_flow_table_in, in,
f6f7d6b5 316 flow_table_context.table_miss_action,
f66ad830 317 ft->def_miss_action);
aaff1bea 318 }
34a40e68
MG
319 }
320
31a0956e 321 return mlx5_cmd_exec_in(dev, modify_flow_table, in);
34a40e68
MG
322}
323
ae288a48 324static int mlx5_cmd_create_flow_group(struct mlx5_flow_root_namespace *ns,
af76c501
MB
325 struct mlx5_flow_table *ft,
326 u32 *in,
ae288a48 327 struct mlx5_flow_group *fg)
26a81453 328{
31a0956e 329 u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {};
ae288a48 330 struct mlx5_core_dev *dev = ns->dev;
26a81453
MG
331 int err;
332
26a81453
MG
333 MLX5_SET(create_flow_group_in, in, opcode,
334 MLX5_CMD_OP_CREATE_FLOW_GROUP);
335 MLX5_SET(create_flow_group_in, in, table_type, ft->type);
336 MLX5_SET(create_flow_group_in, in, table_id, ft->id);
efdc810b
MHY
337 if (ft->vport) {
338 MLX5_SET(create_flow_group_in, in, vport_number, ft->vport);
339 MLX5_SET(create_flow_group_in, in, other_vport, 1);
340 }
26a81453 341
617b860c
PP
342 MLX5_SET(create_flow_group_in, in, vport_number, ft->vport);
343 MLX5_SET(create_flow_group_in, in, other_vport,
344 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
31a0956e 345 err = mlx5_cmd_exec_inout(dev, create_flow_group, in, out);
26a81453 346 if (!err)
ae288a48
MG
347 fg->id = MLX5_GET(create_flow_group_out, out,
348 group_id);
26a81453
MG
349 return err;
350}
351
ae288a48 352static int mlx5_cmd_destroy_flow_group(struct mlx5_flow_root_namespace *ns,
af76c501 353 struct mlx5_flow_table *ft,
ae288a48 354 struct mlx5_flow_group *fg)
26a81453 355{
31a0956e 356 u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {};
ae288a48 357 struct mlx5_core_dev *dev = ns->dev;
26a81453
MG
358
359 MLX5_SET(destroy_flow_group_in, in, opcode,
360 MLX5_CMD_OP_DESTROY_FLOW_GROUP);
361 MLX5_SET(destroy_flow_group_in, in, table_type, ft->type);
362 MLX5_SET(destroy_flow_group_in, in, table_id, ft->id);
ae288a48 363 MLX5_SET(destroy_flow_group_in, in, group_id, fg->id);
617b860c
PP
364 MLX5_SET(destroy_flow_group_in, in, vport_number, ft->vport);
365 MLX5_SET(destroy_flow_group_in, in, other_vport,
366 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
31a0956e 367 return mlx5_cmd_exec_in(dev, destroy_flow_group, in);
26a81453
MG
368}
369
a2c6162b
EB
370static int mlx5_set_extended_dest(struct mlx5_core_dev *dev,
371 struct fs_fte *fte, bool *extended_dest)
372{
373 int fw_log_max_fdb_encap_uplink =
374 MLX5_CAP_ESW(dev, log_max_fdb_encap_uplink);
375 int num_fwd_destinations = 0;
376 struct mlx5_flow_rule *dst;
377 int num_encap = 0;
378
379 *extended_dest = false;
380 if (!(fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
381 return 0;
382
383 list_for_each_entry(dst, &fte->node.children, node.list) {
384 if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
385 continue;
386 if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_VPORT &&
387 dst->dest_attr.vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID)
388 num_encap++;
389 num_fwd_destinations++;
390 }
391 if (num_fwd_destinations > 1 && num_encap > 0)
392 *extended_dest = true;
393
394 if (*extended_dest && !fw_log_max_fdb_encap_uplink) {
395 mlx5_core_warn(dev, "FW does not support extended destination");
396 return -EOPNOTSUPP;
397 }
398 if (num_encap > (1 << fw_log_max_fdb_encap_uplink)) {
399 mlx5_core_warn(dev, "FW does not support more than %d encaps",
400 1 << fw_log_max_fdb_encap_uplink);
401 return -EOPNOTSUPP;
402 }
403
404 return 0;
405}
26a81453
MG
406static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
407 int opmod, int modify_mask,
408 struct mlx5_flow_table *ft,
409 unsigned group_id,
410 struct fs_fte *fte)
411{
c4f287c4 412 u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {0};
a2c6162b 413 bool extended_dest = false;
26a81453 414 struct mlx5_flow_rule *dst;
0c06897a 415 void *in_flow_context, *vlan;
26a81453 416 void *in_match_value;
a2c6162b
EB
417 unsigned int inlen;
418 int dst_cnt_size;
26a81453
MG
419 void *in_dests;
420 u32 *in;
421 int err;
422
a2c6162b
EB
423 if (mlx5_set_extended_dest(dev, fte, &extended_dest))
424 return -EOPNOTSUPP;
425
426 if (!extended_dest)
427 dst_cnt_size = MLX5_ST_SZ_BYTES(dest_format_struct);
428 else
429 dst_cnt_size = MLX5_ST_SZ_BYTES(extended_dest_format);
430
431 inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fte->dests_size * dst_cnt_size;
1b9a07ee
LR
432 in = kvzalloc(inlen, GFP_KERNEL);
433 if (!in)
26a81453 434 return -ENOMEM;
26a81453
MG
435
436 MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY);
437 MLX5_SET(set_fte_in, in, op_mod, opmod);
438 MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask);
439 MLX5_SET(set_fte_in, in, table_type, ft->type);
440 MLX5_SET(set_fte_in, in, table_id, ft->id);
441 MLX5_SET(set_fte_in, in, flow_index, fte->index);
ff189b43
PB
442 MLX5_SET(set_fte_in, in, ignore_flow_level,
443 !!(fte->action.flags & FLOW_ACT_IGNORE_FLOW_LEVEL));
444
617b860c
PP
445 MLX5_SET(set_fte_in, in, vport_number, ft->vport);
446 MLX5_SET(set_fte_in, in, other_vport,
447 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
26a81453
MG
448
449 in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
450 MLX5_SET(flow_context, in_flow_context, group_id, group_id);
0c06897a 451
bb0ee7dc
JL
452 MLX5_SET(flow_context, in_flow_context, flow_tag,
453 fte->flow_context.flow_tag);
8d212ff0
JL
454 MLX5_SET(flow_context, in_flow_context, flow_source,
455 fte->flow_context.flow_source);
456
a2c6162b
EB
457 MLX5_SET(flow_context, in_flow_context, extended_destination,
458 extended_dest);
459 if (extended_dest) {
460 u32 action;
461
462 action = fte->action.action &
463 ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
464 MLX5_SET(flow_context, in_flow_context, action, action);
465 } else {
466 MLX5_SET(flow_context, in_flow_context, action,
467 fte->action.action);
2b688ea5
MG
468 if (fte->action.pkt_reformat)
469 MLX5_SET(flow_context, in_flow_context, packet_reformat_id,
470 fte->action.pkt_reformat->id);
a2c6162b 471 }
2b688ea5
MG
472 if (fte->action.modify_hdr)
473 MLX5_SET(flow_context, in_flow_context, modify_header_id,
474 fte->action.modify_hdr->id);
0c06897a 475
5e466345
HN
476 MLX5_SET(flow_context, in_flow_context, ipsec_obj_id, fte->action.ipsec_obj_id);
477
0c06897a
OG
478 vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan);
479
8da6fe2a
JL
480 MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[0].ethtype);
481 MLX5_SET(vlan, vlan, vid, fte->action.vlan[0].vid);
482 MLX5_SET(vlan, vlan, prio, fte->action.vlan[0].prio);
483
484 vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan_2);
485
486 MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[1].ethtype);
487 MLX5_SET(vlan, vlan, vid, fte->action.vlan[1].vid);
488 MLX5_SET(vlan, vlan, prio, fte->action.vlan[1].prio);
0c06897a 489
26a81453
MG
490 in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context,
491 match_value);
667cb65a 492 memcpy(in_match_value, &fte->val, sizeof(fte->val));
26a81453 493
bd5251db 494 in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
d2ec6a35 495 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
bd5251db
AV
496 int list_size = 0;
497
60ab4584 498 list_for_each_entry(dst, &fte->node.children, node.list) {
664000b6 499 unsigned int id, type = dst->dest_attr.type;
60ab4584 500
664000b6 501 if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
bd5251db
AV
502 continue;
503
664000b6
YH
504 switch (type) {
505 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM:
506 id = dst->dest_attr.ft_num;
507 type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
508 break;
509 case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE:
60ab4584 510 id = dst->dest_attr.ft->id;
664000b6
YH
511 break;
512 case MLX5_FLOW_DESTINATION_TYPE_VPORT:
b17f7fc1
SK
513 id = dst->dest_attr.vport.num;
514 MLX5_SET(dest_format_struct, in_dests,
515 destination_eswitch_owner_vhca_id_valid,
aa39c2c0
EB
516 !!(dst->dest_attr.vport.flags &
517 MLX5_FLOW_DEST_VPORT_VHCA_ID));
b17f7fc1
SK
518 MLX5_SET(dest_format_struct, in_dests,
519 destination_eswitch_owner_vhca_id,
520 dst->dest_attr.vport.vhca_id);
0fd79b1e
EB
521 if (extended_dest &&
522 dst->dest_attr.vport.pkt_reformat) {
a2c6162b
EB
523 MLX5_SET(dest_format_struct, in_dests,
524 packet_reformat,
525 !!(dst->dest_attr.vport.flags &
526 MLX5_FLOW_DEST_VPORT_REFORMAT_ID));
527 MLX5_SET(extended_dest_format, in_dests,
528 packet_reformat_id,
2b688ea5 529 dst->dest_attr.vport.pkt_reformat->id);
a2c6162b 530 }
664000b6 531 break;
38730630
CM
532 case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER:
533 id = dst->dest_attr.sampler_id;
534 break;
664000b6 535 default:
60ab4584
AV
536 id = dst->dest_attr.tir_num;
537 }
664000b6
YH
538
539 MLX5_SET(dest_format_struct, in_dests, destination_type,
540 type);
60ab4584 541 MLX5_SET(dest_format_struct, in_dests, destination_id, id);
a2c6162b 542 in_dests += dst_cnt_size;
bd5251db
AV
543 list_size++;
544 }
545
546 MLX5_SET(flow_context, in_flow_context, destination_list_size,
547 list_size);
548 }
549
d2ec6a35 550 if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
16f1c5bb
RS
551 int max_list_size = BIT(MLX5_CAP_FLOWTABLE_TYPE(dev,
552 log_max_flow_counter,
553 ft->type));
bd5251db
AV
554 int list_size = 0;
555
556 list_for_each_entry(dst, &fte->node.children, node.list) {
557 if (dst->dest_attr.type !=
558 MLX5_FLOW_DESTINATION_TYPE_COUNTER)
559 continue;
560
561 MLX5_SET(flow_counter_list, in_dests, flow_counter_id,
171c7625 562 dst->dest_attr.counter_id);
a2c6162b 563 in_dests += dst_cnt_size;
bd5251db 564 list_size++;
60ab4584 565 }
16f1c5bb
RS
566 if (list_size > max_list_size) {
567 err = -EINVAL;
568 goto err_out;
569 }
bd5251db
AV
570
571 MLX5_SET(flow_context, in_flow_context, flow_counter_list_size,
572 list_size);
26a81453 573 }
bd5251db 574
c4f287c4 575 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
16f1c5bb 576err_out:
26a81453 577 kvfree(in);
26a81453
MG
578 return err;
579}
580
ae288a48 581static int mlx5_cmd_create_fte(struct mlx5_flow_root_namespace *ns,
af76c501
MB
582 struct mlx5_flow_table *ft,
583 struct mlx5_flow_group *group,
584 struct fs_fte *fte)
26a81453 585{
ae288a48 586 struct mlx5_core_dev *dev = ns->dev;
af76c501
MB
587 unsigned int group_id = group->id;
588
c4f287c4 589 return mlx5_cmd_set_fte(dev, 0, 0, ft, group_id, fte);
26a81453
MG
590}
591
ae288a48 592static int mlx5_cmd_update_fte(struct mlx5_flow_root_namespace *ns,
af76c501 593 struct mlx5_flow_table *ft,
ae288a48 594 struct mlx5_flow_group *fg,
af76c501
MB
595 int modify_mask,
596 struct fs_fte *fte)
26a81453
MG
597{
598 int opmod;
ae288a48 599 struct mlx5_core_dev *dev = ns->dev;
26a81453
MG
600 int atomic_mod_cap = MLX5_CAP_FLOWTABLE(dev,
601 flow_table_properties_nic_receive.
602 flow_modify_en);
603 if (!atomic_mod_cap)
9eb78923 604 return -EOPNOTSUPP;
26a81453 605 opmod = 1;
26a81453 606
ae288a48 607 return mlx5_cmd_set_fte(dev, opmod, modify_mask, ft, fg->id, fte);
26a81453
MG
608}
609
ae288a48 610static int mlx5_cmd_delete_fte(struct mlx5_flow_root_namespace *ns,
af76c501 611 struct mlx5_flow_table *ft,
e810bf5e 612 struct fs_fte *fte)
26a81453 613{
31a0956e 614 u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {};
ae288a48 615 struct mlx5_core_dev *dev = ns->dev;
26a81453
MG
616
617 MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY);
618 MLX5_SET(delete_fte_in, in, table_type, ft->type);
619 MLX5_SET(delete_fte_in, in, table_id, ft->id);
e810bf5e 620 MLX5_SET(delete_fte_in, in, flow_index, fte->index);
617b860c
PP
621 MLX5_SET(delete_fte_in, in, vport_number, ft->vport);
622 MLX5_SET(delete_fte_in, in, other_vport,
623 !!(ft->flags & MLX5_FLOW_TABLE_OTHER_VPORT));
26a81453 624
31a0956e 625 return mlx5_cmd_exec_in(dev, delete_fte, in);
26a81453 626}
9dc0b289 627
8536a6bf
GT
628int mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev,
629 enum mlx5_fc_bulk_alloc_bitmask alloc_bitmask,
630 u32 *id)
9dc0b289 631{
31a0956e
LR
632 u32 out[MLX5_ST_SZ_DW(alloc_flow_counter_out)] = {};
633 u32 in[MLX5_ST_SZ_DW(alloc_flow_counter_in)] = {};
9dc0b289
AV
634 int err;
635
9dc0b289
AV
636 MLX5_SET(alloc_flow_counter_in, in, opcode,
637 MLX5_CMD_OP_ALLOC_FLOW_COUNTER);
8536a6bf 638 MLX5_SET(alloc_flow_counter_in, in, flow_counter_bulk, alloc_bitmask);
9dc0b289 639
31a0956e 640 err = mlx5_cmd_exec_inout(dev, alloc_flow_counter, in, out);
c4f287c4
SM
641 if (!err)
642 *id = MLX5_GET(alloc_flow_counter_out, out, flow_counter_id);
643 return err;
9dc0b289
AV
644}
645
8536a6bf
GT
646int mlx5_cmd_fc_alloc(struct mlx5_core_dev *dev, u32 *id)
647{
648 return mlx5_cmd_fc_bulk_alloc(dev, 0, id);
649}
650
a8ffcc74 651int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u32 id)
9dc0b289 652{
31a0956e 653 u32 in[MLX5_ST_SZ_DW(dealloc_flow_counter_in)] = {};
9dc0b289
AV
654
655 MLX5_SET(dealloc_flow_counter_in, in, opcode,
656 MLX5_CMD_OP_DEALLOC_FLOW_COUNTER);
657 MLX5_SET(dealloc_flow_counter_in, in, flow_counter_id, id);
31a0956e 658 return mlx5_cmd_exec_in(dev, dealloc_flow_counter, in);
9dc0b289
AV
659}
660
a8ffcc74 661int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u32 id,
9dc0b289
AV
662 u64 *packets, u64 *bytes)
663{
664 u32 out[MLX5_ST_SZ_BYTES(query_flow_counter_out) +
31a0956e
LR
665 MLX5_ST_SZ_BYTES(traffic_counter)] = {};
666 u32 in[MLX5_ST_SZ_DW(query_flow_counter_in)] = {};
9dc0b289
AV
667 void *stats;
668 int err = 0;
669
9dc0b289
AV
670 MLX5_SET(query_flow_counter_in, in, opcode,
671 MLX5_CMD_OP_QUERY_FLOW_COUNTER);
672 MLX5_SET(query_flow_counter_in, in, op_mod, 0);
673 MLX5_SET(query_flow_counter_in, in, flow_counter_id, id);
c4f287c4 674 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
9dc0b289
AV
675 if (err)
676 return err;
677
678 stats = MLX5_ADDR_OF(query_flow_counter_out, out, flow_statistics);
679 *packets = MLX5_GET64(traffic_counter, stats, packets);
680 *bytes = MLX5_GET64(traffic_counter, stats, octets);
9dc0b289
AV
681 return 0;
682}
a351a1b0 683
6f06e04b 684int mlx5_cmd_fc_get_bulk_query_out_len(int bulk_len)
a351a1b0 685{
6f06e04b
GT
686 return MLX5_ST_SZ_BYTES(query_flow_counter_out) +
687 MLX5_ST_SZ_BYTES(traffic_counter) * bulk_len;
a351a1b0
AV
688}
689
6f06e04b
GT
690int mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, u32 base_id, int bulk_len,
691 u32 *out)
a351a1b0 692{
6f06e04b 693 int outlen = mlx5_cmd_fc_get_bulk_query_out_len(bulk_len);
31a0956e 694 u32 in[MLX5_ST_SZ_DW(query_flow_counter_in)] = {};
a351a1b0
AV
695
696 MLX5_SET(query_flow_counter_in, in, opcode,
697 MLX5_CMD_OP_QUERY_FLOW_COUNTER);
6f06e04b
GT
698 MLX5_SET(query_flow_counter_in, in, flow_counter_id, base_id);
699 MLX5_SET(query_flow_counter_in, in, num_of_counters, bulk_len);
700 return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
a351a1b0 701}
575ddf58 702
2b688ea5
MG
703static int mlx5_cmd_packet_reformat_alloc(struct mlx5_flow_root_namespace *ns,
704 int reformat_type,
705 size_t size,
706 void *reformat_data,
707 enum mlx5_flow_namespace_type namespace,
708 struct mlx5_pkt_reformat *pkt_reformat)
575ddf58 709{
31a0956e 710 u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {};
2b688ea5 711 struct mlx5_core_dev *dev = ns->dev;
60786f09 712 void *packet_reformat_context_in;
31ca3648 713 int max_encap_size;
60786f09 714 void *reformat;
43f93839 715 int inlen;
575ddf58 716 int err;
43f93839 717 u32 *in;
575ddf58 718
31ca3648
MB
719 if (namespace == MLX5_FLOW_NAMESPACE_FDB)
720 max_encap_size = MLX5_CAP_ESW(dev, max_encap_header_size);
721 else
722 max_encap_size = MLX5_CAP_FLOWTABLE(dev, max_encap_header_size);
723
073ff3c8
OG
724 if (size > max_encap_size) {
725 mlx5_core_warn(dev, "encap size %zd too big, max supported is %d\n",
726 size, max_encap_size);
575ddf58 727 return -EINVAL;
073ff3c8 728 }
575ddf58 729
60786f09 730 in = kzalloc(MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in) + size,
43f93839
HHZ
731 GFP_KERNEL);
732 if (!in)
733 return -ENOMEM;
734
60786f09
MB
735 packet_reformat_context_in = MLX5_ADDR_OF(alloc_packet_reformat_context_in,
736 in, packet_reformat_context);
737 reformat = MLX5_ADDR_OF(packet_reformat_context_in,
738 packet_reformat_context_in,
739 reformat_data);
740 inlen = reformat - (void *)in + size;
43f93839 741
60786f09
MB
742 MLX5_SET(alloc_packet_reformat_context_in, in, opcode,
743 MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT);
744 MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
745 reformat_data_size, size);
746 MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
747 reformat_type, reformat_type);
748 memcpy(reformat, reformat_data, size);
575ddf58 749
575ddf58
IL
750 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
751
2b688ea5
MG
752 pkt_reformat->id = MLX5_GET(alloc_packet_reformat_context_out,
753 out, packet_reformat_id);
43f93839 754 kfree(in);
575ddf58
IL
755 return err;
756}
757
2b688ea5
MG
758static void mlx5_cmd_packet_reformat_dealloc(struct mlx5_flow_root_namespace *ns,
759 struct mlx5_pkt_reformat *pkt_reformat)
575ddf58 760{
31a0956e 761 u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {};
2b688ea5 762 struct mlx5_core_dev *dev = ns->dev;
575ddf58 763
60786f09
MB
764 MLX5_SET(dealloc_packet_reformat_context_in, in, opcode,
765 MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT);
766 MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id,
2b688ea5 767 pkt_reformat->id);
575ddf58 768
31a0956e 769 mlx5_cmd_exec_in(dev, dealloc_packet_reformat_context, in);
575ddf58 770}
2de24fed 771
2b688ea5
MG
772static int mlx5_cmd_modify_header_alloc(struct mlx5_flow_root_namespace *ns,
773 u8 namespace, u8 num_actions,
774 void *modify_actions,
775 struct mlx5_modify_hdr *modify_hdr)
2de24fed 776{
31a0956e 777 u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {};
2de24fed 778 int max_actions, actions_size, inlen, err;
2b688ea5 779 struct mlx5_core_dev *dev = ns->dev;
2de24fed
OG
780 void *actions_in;
781 u8 table_type;
782 u32 *in;
783
784 switch (namespace) {
785 case MLX5_FLOW_NAMESPACE_FDB:
786 max_actions = MLX5_CAP_ESW_FLOWTABLE_FDB(dev, max_modify_header_actions);
787 table_type = FS_FT_FDB;
788 break;
789 case MLX5_FLOW_NAMESPACE_KERNEL:
c3c062f8 790 case MLX5_FLOW_NAMESPACE_BYPASS:
2de24fed
OG
791 max_actions = MLX5_CAP_FLOWTABLE_NIC_RX(dev, max_modify_header_actions);
792 table_type = FS_FT_NIC_RX;
793 break;
c3c062f8 794 case MLX5_FLOW_NAMESPACE_EGRESS:
ee92e4f1
HN
795#ifdef CONFIG_MLX5_IPSEC
796 case MLX5_FLOW_NAMESPACE_EGRESS_KERNEL:
797#endif
c3c062f8
MB
798 max_actions = MLX5_CAP_FLOWTABLE_NIC_TX(dev, max_modify_header_actions);
799 table_type = FS_FT_NIC_TX;
800 break;
84b0d6a7
JL
801 case MLX5_FLOW_NAMESPACE_ESW_INGRESS:
802 max_actions = MLX5_CAP_ESW_INGRESS_ACL(dev, max_modify_header_actions);
803 table_type = FS_FT_ESW_INGRESS_ACL;
804 break;
ecf814e0
MG
805 case MLX5_FLOW_NAMESPACE_RDMA_TX:
806 max_actions = MLX5_CAP_FLOWTABLE_RDMA_TX(dev, max_modify_header_actions);
807 table_type = FS_FT_RDMA_TX;
808 break;
2de24fed
OG
809 default:
810 return -EOPNOTSUPP;
811 }
812
813 if (num_actions > max_actions) {
814 mlx5_core_warn(dev, "too many modify header actions %d, max supported %d\n",
815 num_actions, max_actions);
816 return -EOPNOTSUPP;
817 }
818
d65dbedf 819 actions_size = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) * num_actions;
2de24fed
OG
820 inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) + actions_size;
821
822 in = kzalloc(inlen, GFP_KERNEL);
823 if (!in)
824 return -ENOMEM;
825
826 MLX5_SET(alloc_modify_header_context_in, in, opcode,
827 MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT);
828 MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type);
829 MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_actions);
830
831 actions_in = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions);
832 memcpy(actions_in, modify_actions, actions_size);
833
2de24fed
OG
834 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
835
2b688ea5 836 modify_hdr->id = MLX5_GET(alloc_modify_header_context_out, out, modify_header_id);
2de24fed
OG
837 kfree(in);
838 return err;
839}
840
2b688ea5
MG
841static void mlx5_cmd_modify_header_dealloc(struct mlx5_flow_root_namespace *ns,
842 struct mlx5_modify_hdr *modify_hdr)
2de24fed 843{
31a0956e 844 u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {};
2b688ea5 845 struct mlx5_core_dev *dev = ns->dev;
2de24fed 846
2de24fed
OG
847 MLX5_SET(dealloc_modify_header_context_in, in, opcode,
848 MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT);
849 MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id,
2b688ea5 850 modify_hdr->id);
2de24fed 851
31a0956e 852 mlx5_cmd_exec_in(dev, dealloc_modify_header_context, in);
2de24fed 853}
af76c501
MB
854
855static const struct mlx5_flow_cmds mlx5_flow_cmds = {
856 .create_flow_table = mlx5_cmd_create_flow_table,
857 .destroy_flow_table = mlx5_cmd_destroy_flow_table,
858 .modify_flow_table = mlx5_cmd_modify_flow_table,
859 .create_flow_group = mlx5_cmd_create_flow_group,
860 .destroy_flow_group = mlx5_cmd_destroy_flow_group,
861 .create_fte = mlx5_cmd_create_fte,
862 .update_fte = mlx5_cmd_update_fte,
863 .delete_fte = mlx5_cmd_delete_fte,
864 .update_root_ft = mlx5_cmd_update_root_ft,
2b688ea5
MG
865 .packet_reformat_alloc = mlx5_cmd_packet_reformat_alloc,
866 .packet_reformat_dealloc = mlx5_cmd_packet_reformat_dealloc,
867 .modify_header_alloc = mlx5_cmd_modify_header_alloc,
6a48faee
MG
868 .modify_header_dealloc = mlx5_cmd_modify_header_dealloc,
869 .set_peer = mlx5_cmd_stub_set_peer,
870 .create_ns = mlx5_cmd_stub_create_ns,
871 .destroy_ns = mlx5_cmd_stub_destroy_ns,
af76c501
MB
872};
873
874static const struct mlx5_flow_cmds mlx5_flow_cmd_stubs = {
875 .create_flow_table = mlx5_cmd_stub_create_flow_table,
876 .destroy_flow_table = mlx5_cmd_stub_destroy_flow_table,
877 .modify_flow_table = mlx5_cmd_stub_modify_flow_table,
878 .create_flow_group = mlx5_cmd_stub_create_flow_group,
879 .destroy_flow_group = mlx5_cmd_stub_destroy_flow_group,
880 .create_fte = mlx5_cmd_stub_create_fte,
881 .update_fte = mlx5_cmd_stub_update_fte,
882 .delete_fte = mlx5_cmd_stub_delete_fte,
883 .update_root_ft = mlx5_cmd_stub_update_root_ft,
2b688ea5
MG
884 .packet_reformat_alloc = mlx5_cmd_stub_packet_reformat_alloc,
885 .packet_reformat_dealloc = mlx5_cmd_stub_packet_reformat_dealloc,
886 .modify_header_alloc = mlx5_cmd_stub_modify_header_alloc,
6a48faee
MG
887 .modify_header_dealloc = mlx5_cmd_stub_modify_header_dealloc,
888 .set_peer = mlx5_cmd_stub_set_peer,
889 .create_ns = mlx5_cmd_stub_create_ns,
890 .destroy_ns = mlx5_cmd_stub_destroy_ns,
af76c501
MB
891};
892
6a48faee 893const struct mlx5_flow_cmds *mlx5_fs_cmd_get_fw_cmds(void)
af76c501
MB
894{
895 return &mlx5_flow_cmds;
896}
897
898static const struct mlx5_flow_cmds *mlx5_fs_cmd_get_stub_cmds(void)
899{
900 return &mlx5_flow_cmd_stubs;
901}
902
903const struct mlx5_flow_cmds *mlx5_fs_cmd_get_default(enum fs_flow_table_type type)
904{
905 switch (type) {
906 case FS_FT_NIC_RX:
907 case FS_FT_ESW_EGRESS_ACL:
908 case FS_FT_ESW_INGRESS_ACL:
909 case FS_FT_FDB:
910 case FS_FT_SNIFFER_RX:
911 case FS_FT_SNIFFER_TX:
5f418378 912 case FS_FT_NIC_TX:
d83eb50e 913 case FS_FT_RDMA_RX:
24670b1a 914 case FS_FT_RDMA_TX:
8ce78257 915 return mlx5_fs_cmd_get_fw_cmds();
af76c501
MB
916 default:
917 return mlx5_fs_cmd_get_stub_cmds();
918 }
919}