]> git.itanic.dy.fi Git - linux-stable/blob - drivers/net/ethernet/mellanox/mlx5/core/steering/dr_cmd.c
07b6a6dcb92f06be3f5fcc48fe9760f2c022e9af
[linux-stable] / drivers / net / ethernet / mellanox / mlx5 / core / steering / dr_cmd.c
1 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
2 /* Copyright (c) 2019 Mellanox Technologies. */
3
4 #include "dr_types.h"
5
6 int mlx5dr_cmd_query_esw_vport_context(struct mlx5_core_dev *mdev,
7                                        bool other_vport,
8                                        u16 vport_number,
9                                        u64 *icm_address_rx,
10                                        u64 *icm_address_tx)
11 {
12         u32 out[MLX5_ST_SZ_DW(query_esw_vport_context_out)] = {};
13         u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {};
14         int err;
15
16         MLX5_SET(query_esw_vport_context_in, in, opcode,
17                  MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
18         MLX5_SET(query_esw_vport_context_in, in, other_vport, other_vport);
19         MLX5_SET(query_esw_vport_context_in, in, vport_number, vport_number);
20
21         err = mlx5_cmd_exec_inout(mdev, query_esw_vport_context, in, out);
22         if (err)
23                 return err;
24
25         *icm_address_rx =
26                 MLX5_GET64(query_esw_vport_context_out, out,
27                            esw_vport_context.sw_steering_vport_icm_address_rx);
28         *icm_address_tx =
29                 MLX5_GET64(query_esw_vport_context_out, out,
30                            esw_vport_context.sw_steering_vport_icm_address_tx);
31         return 0;
32 }
33
34 int mlx5dr_cmd_query_gvmi(struct mlx5_core_dev *mdev, bool other_vport,
35                           u16 vport_number, u16 *gvmi)
36 {
37         u32 in[MLX5_ST_SZ_DW(query_hca_cap_in)] = {};
38         int out_size;
39         void *out;
40         int err;
41
42         out_size = MLX5_ST_SZ_BYTES(query_hca_cap_out);
43         out = kzalloc(out_size, GFP_KERNEL);
44         if (!out)
45                 return -ENOMEM;
46
47         MLX5_SET(query_hca_cap_in, in, opcode, MLX5_CMD_OP_QUERY_HCA_CAP);
48         MLX5_SET(query_hca_cap_in, in, other_function, other_vport);
49         MLX5_SET(query_hca_cap_in, in, function_id, vport_number);
50         MLX5_SET(query_hca_cap_in, in, op_mod,
51                  MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE << 1 |
52                  HCA_CAP_OPMOD_GET_CUR);
53
54         err = mlx5_cmd_exec_inout(mdev, query_hca_cap, in, out);
55         if (err) {
56                 kfree(out);
57                 return err;
58         }
59
60         *gvmi = MLX5_GET(query_hca_cap_out, out, capability.cmd_hca_cap.vhca_id);
61
62         kfree(out);
63         return 0;
64 }
65
66 int mlx5dr_cmd_query_esw_caps(struct mlx5_core_dev *mdev,
67                               struct mlx5dr_esw_caps *caps)
68 {
69         caps->drop_icm_address_rx =
70                 MLX5_CAP64_ESW_FLOWTABLE(mdev,
71                                          sw_steering_fdb_action_drop_icm_address_rx);
72         caps->drop_icm_address_tx =
73                 MLX5_CAP64_ESW_FLOWTABLE(mdev,
74                                          sw_steering_fdb_action_drop_icm_address_tx);
75         caps->uplink_icm_address_rx =
76                 MLX5_CAP64_ESW_FLOWTABLE(mdev,
77                                          sw_steering_uplink_icm_address_rx);
78         caps->uplink_icm_address_tx =
79                 MLX5_CAP64_ESW_FLOWTABLE(mdev,
80                                          sw_steering_uplink_icm_address_tx);
81         caps->sw_owner_v2 = MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner_v2);
82         if (!caps->sw_owner_v2)
83                 caps->sw_owner = MLX5_CAP_ESW_FLOWTABLE_FDB(mdev, sw_owner);
84
85         return 0;
86 }
87
88 static int dr_cmd_query_nic_vport_roce_en(struct mlx5_core_dev *mdev,
89                                           u16 vport, bool *roce_en)
90 {
91         u32 out[MLX5_ST_SZ_DW(query_nic_vport_context_out)] = {};
92         u32 in[MLX5_ST_SZ_DW(query_nic_vport_context_in)] = {};
93         int err;
94
95         MLX5_SET(query_nic_vport_context_in, in, opcode,
96                  MLX5_CMD_OP_QUERY_NIC_VPORT_CONTEXT);
97         MLX5_SET(query_nic_vport_context_in, in, vport_number, vport);
98         MLX5_SET(query_nic_vport_context_in, in, other_vport, !!vport);
99
100         err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
101         if (err)
102                 return err;
103
104         *roce_en = MLX5_GET(query_nic_vport_context_out, out,
105                             nic_vport_context.roce_en);
106         return 0;
107 }
108
109 int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev,
110                             struct mlx5dr_cmd_caps *caps)
111 {
112         bool roce_en;
113         int err;
114
115         caps->prio_tag_required = MLX5_CAP_GEN(mdev, prio_tag_required);
116         caps->eswitch_manager   = MLX5_CAP_GEN(mdev, eswitch_manager);
117         caps->gvmi              = MLX5_CAP_GEN(mdev, vhca_id);
118         caps->flex_protocols    = MLX5_CAP_GEN(mdev, flex_parser_protocols);
119         caps->sw_format_ver     = MLX5_CAP_GEN(mdev, steering_format_version);
120
121         if (MLX5_CAP_GEN(mdev, roce)) {
122                 err = dr_cmd_query_nic_vport_roce_en(mdev, 0, &roce_en);
123                 if (err)
124                         return err;
125
126                 caps->roce_caps.roce_en = roce_en;
127                 caps->roce_caps.fl_rc_qp_when_roce_disabled =
128                         MLX5_CAP_ROCE(mdev, fl_rc_qp_when_roce_disabled);
129                 caps->roce_caps.fl_rc_qp_when_roce_enabled =
130                         MLX5_CAP_ROCE(mdev, fl_rc_qp_when_roce_enabled);
131         }
132
133         caps->isolate_vl_tc = MLX5_CAP_GEN(mdev, isolate_vl_tc_new);
134
135         /* geneve_tlv_option_0_exist is the indication of
136          * STE support for lookup type flex_parser_ok
137          */
138         caps->flex_parser_ok_bits_supp =
139                 MLX5_CAP_FLOWTABLE(mdev,
140                                    flow_table_properties_nic_receive.ft_field_support.geneve_tlv_option_0_exist);
141
142         if (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V4_ENABLED) {
143                 caps->flex_parser_id_icmp_dw0 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw0);
144                 caps->flex_parser_id_icmp_dw1 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw1);
145         }
146
147         if (caps->flex_protocols & MLX5_FLEX_PARSER_ICMP_V6_ENABLED) {
148                 caps->flex_parser_id_icmpv6_dw0 =
149                         MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw0);
150                 caps->flex_parser_id_icmpv6_dw1 =
151                         MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw1);
152         }
153
154         if (caps->flex_protocols & MLX5_FLEX_PARSER_GENEVE_TLV_OPTION_0_ENABLED)
155                 caps->flex_parser_id_geneve_tlv_option_0 =
156                         MLX5_CAP_GEN(mdev, flex_parser_id_geneve_tlv_option_0);
157
158         if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_GRE_ENABLED)
159                 caps->flex_parser_id_mpls_over_gre =
160                         MLX5_CAP_GEN(mdev, flex_parser_id_outer_first_mpls_over_gre);
161
162         if (caps->flex_protocols & MLX5_FLEX_PARSER_MPLS_OVER_UDP_ENABLED)
163                 caps->flex_parser_id_mpls_over_udp =
164                         MLX5_CAP_GEN(mdev, flex_parser_id_outer_first_mpls_over_udp_label);
165
166         if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_0_ENABLED)
167                 caps->flex_parser_id_gtpu_dw_0 =
168                         MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_dw_0);
169
170         if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_TEID_ENABLED)
171                 caps->flex_parser_id_gtpu_teid =
172                         MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_teid);
173
174         if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_DW_2_ENABLED)
175                 caps->flex_parser_id_gtpu_dw_2 =
176                         MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_dw_2);
177
178         if (caps->flex_protocols & MLX5_FLEX_PARSER_GTPU_FIRST_EXT_DW_0_ENABLED)
179                 caps->flex_parser_id_gtpu_first_ext_dw_0 =
180                         MLX5_CAP_GEN(mdev, flex_parser_id_gtpu_first_ext_dw_0);
181
182         caps->nic_rx_drop_address =
183                 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_rx_action_drop_icm_address);
184         caps->nic_tx_drop_address =
185                 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_drop_icm_address);
186         caps->nic_tx_allow_address =
187                 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_allow_icm_address);
188
189         caps->rx_sw_owner_v2 = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner_v2);
190         caps->tx_sw_owner_v2 = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner_v2);
191
192         if (!caps->rx_sw_owner_v2)
193                 caps->rx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner);
194         if (!caps->tx_sw_owner_v2)
195                 caps->tx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner);
196
197         caps->max_ft_level = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, max_ft_level);
198
199         caps->log_icm_size = MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size);
200         caps->hdr_modify_icm_addr =
201                 MLX5_CAP64_DEV_MEM(mdev, header_modify_sw_icm_start_address);
202
203         caps->roce_min_src_udp = MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port);
204
205         caps->is_ecpf = mlx5_core_is_ecpf_esw_manager(mdev);
206
207         return 0;
208 }
209
210 int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev,
211                                 enum fs_flow_table_type type,
212                                 u32 table_id,
213                                 struct mlx5dr_cmd_query_flow_table_details *output)
214 {
215         u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {};
216         u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {};
217         int err;
218
219         MLX5_SET(query_flow_table_in, in, opcode,
220                  MLX5_CMD_OP_QUERY_FLOW_TABLE);
221
222         MLX5_SET(query_flow_table_in, in, table_type, type);
223         MLX5_SET(query_flow_table_in, in, table_id, table_id);
224
225         err = mlx5_cmd_exec_inout(dev, query_flow_table, in, out);
226         if (err)
227                 return err;
228
229         output->status = MLX5_GET(query_flow_table_out, out, status);
230         output->level = MLX5_GET(query_flow_table_out, out, flow_table_context.level);
231
232         output->sw_owner_icm_root_1 = MLX5_GET64(query_flow_table_out, out,
233                                                  flow_table_context.sw_owner_icm_root_1);
234         output->sw_owner_icm_root_0 = MLX5_GET64(query_flow_table_out, out,
235                                                  flow_table_context.sw_owner_icm_root_0);
236
237         return 0;
238 }
239
240 int mlx5dr_cmd_query_flow_sampler(struct mlx5_core_dev *dev,
241                                   u32 sampler_id,
242                                   u64 *rx_icm_addr,
243                                   u64 *tx_icm_addr)
244 {
245         u32 out[MLX5_ST_SZ_DW(query_sampler_obj_out)] = {};
246         u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
247         void *attr;
248         int ret;
249
250         MLX5_SET(general_obj_in_cmd_hdr, in, opcode,
251                  MLX5_CMD_OP_QUERY_GENERAL_OBJECT);
252         MLX5_SET(general_obj_in_cmd_hdr, in, obj_type,
253                  MLX5_GENERAL_OBJECT_TYPES_SAMPLER);
254         MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, sampler_id);
255
256         ret = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
257         if (ret)
258                 return ret;
259
260         attr = MLX5_ADDR_OF(query_sampler_obj_out, out, sampler_object);
261
262         *rx_icm_addr = MLX5_GET64(sampler_obj, attr,
263                                   sw_steering_icm_address_rx);
264         *tx_icm_addr = MLX5_GET64(sampler_obj, attr,
265                                   sw_steering_icm_address_tx);
266
267         return 0;
268 }
269
270 int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev)
271 {
272         u32 in[MLX5_ST_SZ_DW(sync_steering_in)] = {};
273
274         /* Skip SYNC in case the device is internal error state.
275          * Besides a device error, this also happens when we're
276          * in fast teardown
277          */
278         if (mdev->state == MLX5_DEVICE_STATE_INTERNAL_ERROR)
279                 return 0;
280
281         MLX5_SET(sync_steering_in, in, opcode, MLX5_CMD_OP_SYNC_STEERING);
282
283         return mlx5_cmd_exec_in(mdev, sync_steering, in);
284 }
285
286 int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev,
287                                         u32 table_type,
288                                         u32 table_id,
289                                         u32 group_id,
290                                         u32 modify_header_id,
291                                         u16 vport)
292 {
293         u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {};
294         void *in_flow_context;
295         unsigned int inlen;
296         void *in_dests;
297         u32 *in;
298         int err;
299
300         inlen = MLX5_ST_SZ_BYTES(set_fte_in) +
301                 1 * MLX5_ST_SZ_BYTES(dest_format_struct); /* One destination only */
302
303         in = kvzalloc(inlen, GFP_KERNEL);
304         if (!in)
305                 return -ENOMEM;
306
307         MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY);
308         MLX5_SET(set_fte_in, in, table_type, table_type);
309         MLX5_SET(set_fte_in, in, table_id, table_id);
310
311         in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
312         MLX5_SET(flow_context, in_flow_context, group_id, group_id);
313         MLX5_SET(flow_context, in_flow_context, modify_header_id, modify_header_id);
314         MLX5_SET(flow_context, in_flow_context, destination_list_size, 1);
315         MLX5_SET(flow_context, in_flow_context, action,
316                  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
317                  MLX5_FLOW_CONTEXT_ACTION_MOD_HDR);
318
319         in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
320         MLX5_SET(dest_format_struct, in_dests, destination_type,
321                  MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT);
322         MLX5_SET(dest_format_struct, in_dests, destination_id, vport);
323
324         err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
325         kvfree(in);
326
327         return err;
328 }
329
330 int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev,
331                                     u32 table_type,
332                                     u32 table_id)
333 {
334         u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {};
335
336         MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY);
337         MLX5_SET(delete_fte_in, in, table_type, table_type);
338         MLX5_SET(delete_fte_in, in, table_id, table_id);
339
340         return mlx5_cmd_exec_in(mdev, delete_fte, in);
341 }
342
343 int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev,
344                                    u32 table_type,
345                                    u8 num_of_actions,
346                                    u64 *actions,
347                                    u32 *modify_header_id)
348 {
349         u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {};
350         void *p_actions;
351         u32 inlen;
352         u32 *in;
353         int err;
354
355         inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) +
356                  num_of_actions * sizeof(u64);
357         in = kvzalloc(inlen, GFP_KERNEL);
358         if (!in)
359                 return -ENOMEM;
360
361         MLX5_SET(alloc_modify_header_context_in, in, opcode,
362                  MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT);
363         MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type);
364         MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_of_actions);
365         p_actions = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions);
366         memcpy(p_actions, actions, num_of_actions * sizeof(u64));
367
368         err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
369         if (err)
370                 goto out;
371
372         *modify_header_id = MLX5_GET(alloc_modify_header_context_out, out,
373                                      modify_header_id);
374 out:
375         kvfree(in);
376         return err;
377 }
378
379 int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev,
380                                      u32 modify_header_id)
381 {
382         u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {};
383
384         MLX5_SET(dealloc_modify_header_context_in, in, opcode,
385                  MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT);
386         MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id,
387                  modify_header_id);
388
389         return mlx5_cmd_exec_in(mdev, dealloc_modify_header_context, in);
390 }
391
392 int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev,
393                                        u32 table_type,
394                                        u32 table_id,
395                                        u32 *group_id)
396 {
397         u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {};
398         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
399         u32 *in;
400         int err;
401
402         in = kvzalloc(inlen, GFP_KERNEL);
403         if (!in)
404                 return -ENOMEM;
405
406         MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP);
407         MLX5_SET(create_flow_group_in, in, table_type, table_type);
408         MLX5_SET(create_flow_group_in, in, table_id, table_id);
409
410         err = mlx5_cmd_exec_inout(mdev, create_flow_group, in, out);
411         if (err)
412                 goto out;
413
414         *group_id = MLX5_GET(create_flow_group_out, out, group_id);
415
416 out:
417         kvfree(in);
418         return err;
419 }
420
421 int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev,
422                                   u32 table_type,
423                                   u32 table_id,
424                                   u32 group_id)
425 {
426         u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {};
427
428         MLX5_SET(destroy_flow_group_in, in, opcode,
429                  MLX5_CMD_OP_DESTROY_FLOW_GROUP);
430         MLX5_SET(destroy_flow_group_in, in, table_type, table_type);
431         MLX5_SET(destroy_flow_group_in, in, table_id, table_id);
432         MLX5_SET(destroy_flow_group_in, in, group_id, group_id);
433
434         return mlx5_cmd_exec_in(mdev, destroy_flow_group, in);
435 }
436
437 int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev,
438                                  struct mlx5dr_cmd_create_flow_table_attr *attr,
439                                  u64 *fdb_rx_icm_addr,
440                                  u32 *table_id)
441 {
442         u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {};
443         u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {};
444         void *ft_mdev;
445         int err;
446
447         MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE);
448         MLX5_SET(create_flow_table_in, in, table_type, attr->table_type);
449         MLX5_SET(create_flow_table_in, in, uid, attr->uid);
450
451         ft_mdev = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context);
452         MLX5_SET(flow_table_context, ft_mdev, termination_table, attr->term_tbl);
453         MLX5_SET(flow_table_context, ft_mdev, sw_owner, attr->sw_owner);
454         MLX5_SET(flow_table_context, ft_mdev, level, attr->level);
455
456         if (attr->sw_owner) {
457                 /* icm_addr_0 used for FDB RX / NIC TX / NIC_RX
458                  * icm_addr_1 used for FDB TX
459                  */
460                 if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_RX) {
461                         MLX5_SET64(flow_table_context, ft_mdev,
462                                    sw_owner_icm_root_0, attr->icm_addr_rx);
463                 } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_NIC_TX) {
464                         MLX5_SET64(flow_table_context, ft_mdev,
465                                    sw_owner_icm_root_0, attr->icm_addr_tx);
466                 } else if (attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB) {
467                         MLX5_SET64(flow_table_context, ft_mdev,
468                                    sw_owner_icm_root_0, attr->icm_addr_rx);
469                         MLX5_SET64(flow_table_context, ft_mdev,
470                                    sw_owner_icm_root_1, attr->icm_addr_tx);
471                 }
472         }
473
474         MLX5_SET(create_flow_table_in, in, flow_table_context.decap_en,
475                  attr->decap_en);
476         MLX5_SET(create_flow_table_in, in, flow_table_context.reformat_en,
477                  attr->reformat_en);
478
479         err = mlx5_cmd_exec_inout(mdev, create_flow_table, in, out);
480         if (err)
481                 return err;
482
483         *table_id = MLX5_GET(create_flow_table_out, out, table_id);
484         if (!attr->sw_owner && attr->table_type == MLX5_FLOW_TABLE_TYPE_FDB &&
485             fdb_rx_icm_addr)
486                 *fdb_rx_icm_addr =
487                 (u64)MLX5_GET(create_flow_table_out, out, icm_address_31_0) |
488                 (u64)MLX5_GET(create_flow_table_out, out, icm_address_39_32) << 32 |
489                 (u64)MLX5_GET(create_flow_table_out, out, icm_address_63_40) << 40;
490
491         return 0;
492 }
493
494 int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev,
495                                   u32 table_id,
496                                   u32 table_type)
497 {
498         u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {};
499
500         MLX5_SET(destroy_flow_table_in, in, opcode,
501                  MLX5_CMD_OP_DESTROY_FLOW_TABLE);
502         MLX5_SET(destroy_flow_table_in, in, table_type, table_type);
503         MLX5_SET(destroy_flow_table_in, in, table_id, table_id);
504
505         return mlx5_cmd_exec_in(mdev, destroy_flow_table, in);
506 }
507
508 int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev,
509                                    enum mlx5_reformat_ctx_type rt,
510                                    u8 reformat_param_0,
511                                    u8 reformat_param_1,
512                                    size_t reformat_size,
513                                    void *reformat_data,
514                                    u32 *reformat_id)
515 {
516         u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {};
517         size_t inlen, cmd_data_sz, cmd_total_sz;
518         void *prctx;
519         void *pdata;
520         void *in;
521         int err;
522
523         cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in);
524         cmd_data_sz = MLX5_FLD_SZ_BYTES(alloc_packet_reformat_context_in,
525                                         packet_reformat_context.reformat_data);
526         inlen = ALIGN(cmd_total_sz + reformat_size - cmd_data_sz, 4);
527         in = kvzalloc(inlen, GFP_KERNEL);
528         if (!in)
529                 return -ENOMEM;
530
531         MLX5_SET(alloc_packet_reformat_context_in, in, opcode,
532                  MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT);
533
534         prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, packet_reformat_context);
535         pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data);
536
537         MLX5_SET(packet_reformat_context_in, prctx, reformat_type, rt);
538         MLX5_SET(packet_reformat_context_in, prctx, reformat_param_0, reformat_param_0);
539         MLX5_SET(packet_reformat_context_in, prctx, reformat_param_1, reformat_param_1);
540         MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, reformat_size);
541         if (reformat_data && reformat_size)
542                 memcpy(pdata, reformat_data, reformat_size);
543
544         err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
545         if (err)
546                 return err;
547
548         *reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id);
549         kvfree(in);
550
551         return err;
552 }
553
554 void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev,
555                                      u32 reformat_id)
556 {
557         u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {};
558
559         MLX5_SET(dealloc_packet_reformat_context_in, in, opcode,
560                  MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT);
561         MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id,
562                  reformat_id);
563
564         mlx5_cmd_exec_in(mdev, dealloc_packet_reformat_context, in);
565 }
566
567 static void dr_cmd_set_definer_format(void *ptr, u16 format_id,
568                                       u8 *dw_selectors,
569                                       u8 *byte_selectors)
570 {
571         if (format_id != MLX5_IFC_DEFINER_FORMAT_ID_SELECT)
572                 return;
573
574         MLX5_SET(match_definer, ptr, format_select_dw0, dw_selectors[0]);
575         MLX5_SET(match_definer, ptr, format_select_dw1, dw_selectors[1]);
576         MLX5_SET(match_definer, ptr, format_select_dw2, dw_selectors[2]);
577         MLX5_SET(match_definer, ptr, format_select_dw3, dw_selectors[3]);
578         MLX5_SET(match_definer, ptr, format_select_dw4, dw_selectors[4]);
579         MLX5_SET(match_definer, ptr, format_select_dw5, dw_selectors[5]);
580         MLX5_SET(match_definer, ptr, format_select_dw6, dw_selectors[6]);
581         MLX5_SET(match_definer, ptr, format_select_dw7, dw_selectors[7]);
582         MLX5_SET(match_definer, ptr, format_select_dw8, dw_selectors[8]);
583
584         MLX5_SET(match_definer, ptr, format_select_byte0, byte_selectors[0]);
585         MLX5_SET(match_definer, ptr, format_select_byte1, byte_selectors[1]);
586         MLX5_SET(match_definer, ptr, format_select_byte2, byte_selectors[2]);
587         MLX5_SET(match_definer, ptr, format_select_byte3, byte_selectors[3]);
588         MLX5_SET(match_definer, ptr, format_select_byte4, byte_selectors[4]);
589         MLX5_SET(match_definer, ptr, format_select_byte5, byte_selectors[5]);
590         MLX5_SET(match_definer, ptr, format_select_byte6, byte_selectors[6]);
591         MLX5_SET(match_definer, ptr, format_select_byte7, byte_selectors[7]);
592 }
593
594 int mlx5dr_cmd_create_definer(struct mlx5_core_dev *mdev,
595                               u16 format_id,
596                               u8 *dw_selectors,
597                               u8 *byte_selectors,
598                               u8 *match_mask,
599                               u32 *definer_id)
600 {
601         u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)] = {};
602         u32 in[MLX5_ST_SZ_DW(create_match_definer_in)] = {};
603         void *ptr;
604         int err;
605
606         ptr = MLX5_ADDR_OF(create_match_definer_in, in,
607                            general_obj_in_cmd_hdr);
608         MLX5_SET(general_obj_in_cmd_hdr, ptr, opcode,
609                  MLX5_CMD_OP_CREATE_GENERAL_OBJECT);
610         MLX5_SET(general_obj_in_cmd_hdr, ptr, obj_type,
611                  MLX5_OBJ_TYPE_MATCH_DEFINER);
612
613         ptr = MLX5_ADDR_OF(create_match_definer_in, in, obj_context);
614         MLX5_SET(match_definer, ptr, format_id, format_id);
615
616         dr_cmd_set_definer_format(ptr, format_id,
617                                   dw_selectors, byte_selectors);
618
619         ptr = MLX5_ADDR_OF(match_definer, ptr, match_mask);
620         memcpy(ptr, match_mask, MLX5_FLD_SZ_BYTES(match_definer, match_mask));
621
622         err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
623         if (err)
624                 return err;
625
626         *definer_id = MLX5_GET(general_obj_out_cmd_hdr, out, obj_id);
627
628         return 0;
629 }
630
631 void
632 mlx5dr_cmd_destroy_definer(struct mlx5_core_dev *mdev, u32 definer_id)
633 {
634         u32 in[MLX5_ST_SZ_DW(general_obj_in_cmd_hdr)] = {};
635         u32 out[MLX5_ST_SZ_DW(general_obj_out_cmd_hdr)];
636
637         MLX5_SET(general_obj_in_cmd_hdr, in, opcode, MLX5_CMD_OP_DESTROY_GENERAL_OBJECT);
638         MLX5_SET(general_obj_in_cmd_hdr, in, obj_type, MLX5_OBJ_TYPE_MATCH_DEFINER);
639         MLX5_SET(general_obj_in_cmd_hdr, in, obj_id, definer_id);
640
641         mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
642 }
643
644 int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num,
645                          u16 index, struct mlx5dr_cmd_gid_attr *attr)
646 {
647         u32 out[MLX5_ST_SZ_DW(query_roce_address_out)] = {};
648         u32 in[MLX5_ST_SZ_DW(query_roce_address_in)] = {};
649         int err;
650
651         MLX5_SET(query_roce_address_in, in, opcode,
652                  MLX5_CMD_OP_QUERY_ROCE_ADDRESS);
653
654         MLX5_SET(query_roce_address_in, in, roce_address_index, index);
655         MLX5_SET(query_roce_address_in, in, vhca_port_num, vhca_port_num);
656
657         err = mlx5_cmd_exec_inout(mdev, query_roce_address, in, out);
658         if (err)
659                 return err;
660
661         memcpy(&attr->gid,
662                MLX5_ADDR_OF(query_roce_address_out,
663                             out, roce_address.source_l3_address),
664                sizeof(attr->gid));
665         memcpy(attr->mac,
666                MLX5_ADDR_OF(query_roce_address_out, out,
667                             roce_address.source_mac_47_32),
668                sizeof(attr->mac));
669
670         if (MLX5_GET(query_roce_address_out, out,
671                      roce_address.roce_version) == MLX5_ROCE_VERSION_2)
672                 attr->roce_ver = MLX5_ROCE_VERSION_2;
673         else
674                 attr->roce_ver = MLX5_ROCE_VERSION_1;
675
676         return 0;
677 }
678
679 static int mlx5dr_cmd_set_extended_dest(struct mlx5_core_dev *dev,
680                                         struct mlx5dr_cmd_fte_info *fte,
681                                         bool *extended_dest)
682 {
683         int fw_log_max_fdb_encap_uplink = MLX5_CAP_ESW(dev, log_max_fdb_encap_uplink);
684         int num_fwd_destinations = 0;
685         int num_encap = 0;
686         int i;
687
688         *extended_dest = false;
689         if (!(fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST))
690                 return 0;
691         for (i = 0; i < fte->dests_size; i++) {
692                 if (fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_COUNTER ||
693                     fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_NONE)
694                         continue;
695                 if ((fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_VPORT ||
696                      fte->dest_arr[i].type == MLX5_FLOW_DESTINATION_TYPE_UPLINK) &&
697                     fte->dest_arr[i].vport.flags & MLX5_FLOW_DEST_VPORT_REFORMAT_ID)
698                         num_encap++;
699                 num_fwd_destinations++;
700         }
701
702         if (num_fwd_destinations > 1 && num_encap > 0)
703                 *extended_dest = true;
704
705         if (*extended_dest && !fw_log_max_fdb_encap_uplink) {
706                 mlx5_core_warn(dev, "FW does not support extended destination");
707                 return -EOPNOTSUPP;
708         }
709         if (num_encap > (1 << fw_log_max_fdb_encap_uplink)) {
710                 mlx5_core_warn(dev, "FW does not support more than %d encaps",
711                                1 << fw_log_max_fdb_encap_uplink);
712                 return -EOPNOTSUPP;
713         }
714
715         return 0;
716 }
717
718 int mlx5dr_cmd_set_fte(struct mlx5_core_dev *dev,
719                        int opmod, int modify_mask,
720                        struct mlx5dr_cmd_ft_info *ft,
721                        u32 group_id,
722                        struct mlx5dr_cmd_fte_info *fte)
723 {
724         u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {};
725         void *in_flow_context, *vlan;
726         bool extended_dest = false;
727         void *in_match_value;
728         unsigned int inlen;
729         int dst_cnt_size;
730         void *in_dests;
731         u32 *in;
732         int err;
733         int i;
734
735         if (mlx5dr_cmd_set_extended_dest(dev, fte, &extended_dest))
736                 return -EOPNOTSUPP;
737
738         if (!extended_dest)
739                 dst_cnt_size = MLX5_ST_SZ_BYTES(dest_format_struct);
740         else
741                 dst_cnt_size = MLX5_ST_SZ_BYTES(extended_dest_format);
742
743         inlen = MLX5_ST_SZ_BYTES(set_fte_in) + fte->dests_size * dst_cnt_size;
744         in = kvzalloc(inlen, GFP_KERNEL);
745         if (!in)
746                 return -ENOMEM;
747
748         MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY);
749         MLX5_SET(set_fte_in, in, op_mod, opmod);
750         MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask);
751         MLX5_SET(set_fte_in, in, table_type, ft->type);
752         MLX5_SET(set_fte_in, in, table_id, ft->id);
753         MLX5_SET(set_fte_in, in, flow_index, fte->index);
754         MLX5_SET(set_fte_in, in, ignore_flow_level, fte->ignore_flow_level);
755         if (ft->vport) {
756                 MLX5_SET(set_fte_in, in, vport_number, ft->vport);
757                 MLX5_SET(set_fte_in, in, other_vport, 1);
758         }
759
760         in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
761         MLX5_SET(flow_context, in_flow_context, group_id, group_id);
762
763         MLX5_SET(flow_context, in_flow_context, flow_tag,
764                  fte->flow_context.flow_tag);
765         MLX5_SET(flow_context, in_flow_context, flow_source,
766                  fte->flow_context.flow_source);
767
768         MLX5_SET(flow_context, in_flow_context, extended_destination,
769                  extended_dest);
770         if (extended_dest) {
771                 u32 action;
772
773                 action = fte->action.action &
774                         ~MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
775                 MLX5_SET(flow_context, in_flow_context, action, action);
776         } else {
777                 MLX5_SET(flow_context, in_flow_context, action,
778                          fte->action.action);
779                 if (fte->action.pkt_reformat)
780                         MLX5_SET(flow_context, in_flow_context, packet_reformat_id,
781                                  fte->action.pkt_reformat->id);
782         }
783         if (fte->action.modify_hdr)
784                 MLX5_SET(flow_context, in_flow_context, modify_header_id,
785                          fte->action.modify_hdr->id);
786
787         vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan);
788
789         MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[0].ethtype);
790         MLX5_SET(vlan, vlan, vid, fte->action.vlan[0].vid);
791         MLX5_SET(vlan, vlan, prio, fte->action.vlan[0].prio);
792
793         vlan = MLX5_ADDR_OF(flow_context, in_flow_context, push_vlan_2);
794
795         MLX5_SET(vlan, vlan, ethtype, fte->action.vlan[1].ethtype);
796         MLX5_SET(vlan, vlan, vid, fte->action.vlan[1].vid);
797         MLX5_SET(vlan, vlan, prio, fte->action.vlan[1].prio);
798
799         in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context,
800                                       match_value);
801         memcpy(in_match_value, fte->val, sizeof(u32) * MLX5_ST_SZ_DW_MATCH_PARAM);
802
803         in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
804         if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
805                 int list_size = 0;
806
807                 for (i = 0; i < fte->dests_size; i++) {
808                         enum mlx5_flow_destination_type type = fte->dest_arr[i].type;
809                         enum mlx5_ifc_flow_destination_type ifc_type;
810                         unsigned int id;
811
812                         if (type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
813                                 continue;
814
815                         switch (type) {
816                         case MLX5_FLOW_DESTINATION_TYPE_NONE:
817                                 continue;
818                         case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE_NUM:
819                                 id = fte->dest_arr[i].ft_num;
820                                 ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE;
821                                 break;
822                         case MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE:
823                                 id = fte->dest_arr[i].ft_id;
824                                 ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_TABLE;
825
826                                 break;
827                         case MLX5_FLOW_DESTINATION_TYPE_UPLINK:
828                         case MLX5_FLOW_DESTINATION_TYPE_VPORT:
829                                 if (type == MLX5_FLOW_DESTINATION_TYPE_VPORT) {
830                                         id = fte->dest_arr[i].vport.num;
831                                         MLX5_SET(dest_format_struct, in_dests,
832                                                  destination_eswitch_owner_vhca_id_valid,
833                                                  !!(fte->dest_arr[i].vport.flags &
834                                                     MLX5_FLOW_DEST_VPORT_VHCA_ID));
835                                         ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_VPORT;
836                                 } else {
837                                         id = 0;
838                                         ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_UPLINK;
839                                         MLX5_SET(dest_format_struct, in_dests,
840                                                  destination_eswitch_owner_vhca_id_valid, 1);
841                                 }
842                                 MLX5_SET(dest_format_struct, in_dests,
843                                          destination_eswitch_owner_vhca_id,
844                                          fte->dest_arr[i].vport.vhca_id);
845                                 if (extended_dest && (fte->dest_arr[i].vport.flags &
846                                                     MLX5_FLOW_DEST_VPORT_REFORMAT_ID)) {
847                                         MLX5_SET(dest_format_struct, in_dests,
848                                                  packet_reformat,
849                                                  !!(fte->dest_arr[i].vport.flags &
850                                                     MLX5_FLOW_DEST_VPORT_REFORMAT_ID));
851                                         MLX5_SET(extended_dest_format, in_dests,
852                                                  packet_reformat_id,
853                                                  fte->dest_arr[i].vport.reformat_id);
854                                 }
855                                 break;
856                         case MLX5_FLOW_DESTINATION_TYPE_FLOW_SAMPLER:
857                                 id = fte->dest_arr[i].sampler_id;
858                                 ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_FLOW_SAMPLER;
859                                 break;
860                         default:
861                                 id = fte->dest_arr[i].tir_num;
862                                 ifc_type = MLX5_IFC_FLOW_DESTINATION_TYPE_TIR;
863                         }
864
865                         MLX5_SET(dest_format_struct, in_dests, destination_type,
866                                  ifc_type);
867                         MLX5_SET(dest_format_struct, in_dests, destination_id, id);
868                         in_dests += dst_cnt_size;
869                         list_size++;
870                 }
871
872                 MLX5_SET(flow_context, in_flow_context, destination_list_size,
873                          list_size);
874         }
875
876         if (fte->action.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
877                 int max_list_size = BIT(MLX5_CAP_FLOWTABLE_TYPE(dev,
878                                         log_max_flow_counter,
879                                         ft->type));
880                 int list_size = 0;
881
882                 for (i = 0; i < fte->dests_size; i++) {
883                         if (fte->dest_arr[i].type !=
884                             MLX5_FLOW_DESTINATION_TYPE_COUNTER)
885                                 continue;
886
887                         MLX5_SET(flow_counter_list, in_dests, flow_counter_id,
888                                  fte->dest_arr[i].counter_id);
889                         in_dests += dst_cnt_size;
890                         list_size++;
891                 }
892                 if (list_size > max_list_size) {
893                         err = -EINVAL;
894                         goto err_out;
895                 }
896
897                 MLX5_SET(flow_context, in_flow_context, flow_counter_list_size,
898                          list_size);
899         }
900
901         err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
902 err_out:
903         kvfree(in);
904         return err;
905 }