Linux-libre 5.4.48-gnu
[librecmc/linux-libre.git] / 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(mdev, in, sizeof(in), out, sizeof(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(mdev, in, sizeof(in), out, out_size);
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 =
82                 MLX5_CAP_ESW_FLOWTABLE_FDB(mdev,
83                                            sw_owner);
84
85         return 0;
86 }
87
88 int mlx5dr_cmd_query_device(struct mlx5_core_dev *mdev,
89                             struct mlx5dr_cmd_caps *caps)
90 {
91         caps->prio_tag_required = MLX5_CAP_GEN(mdev, prio_tag_required);
92         caps->eswitch_manager   = MLX5_CAP_GEN(mdev, eswitch_manager);
93         caps->gvmi              = MLX5_CAP_GEN(mdev, vhca_id);
94         caps->flex_protocols    = MLX5_CAP_GEN(mdev, flex_parser_protocols);
95
96         if (mlx5dr_matcher_supp_flex_parser_icmp_v4(caps)) {
97                 caps->flex_parser_id_icmp_dw0 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw0);
98                 caps->flex_parser_id_icmp_dw1 = MLX5_CAP_GEN(mdev, flex_parser_id_icmp_dw1);
99         }
100
101         if (mlx5dr_matcher_supp_flex_parser_icmp_v6(caps)) {
102                 caps->flex_parser_id_icmpv6_dw0 =
103                         MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw0);
104                 caps->flex_parser_id_icmpv6_dw1 =
105                         MLX5_CAP_GEN(mdev, flex_parser_id_icmpv6_dw1);
106         }
107
108         caps->nic_rx_drop_address =
109                 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_rx_action_drop_icm_address);
110         caps->nic_tx_drop_address =
111                 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_drop_icm_address);
112         caps->nic_tx_allow_address =
113                 MLX5_CAP64_FLOWTABLE(mdev, sw_steering_nic_tx_action_allow_icm_address);
114
115         caps->rx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, sw_owner);
116         caps->max_ft_level = MLX5_CAP_FLOWTABLE_NIC_RX(mdev, max_ft_level);
117
118         caps->tx_sw_owner = MLX5_CAP_FLOWTABLE_NIC_TX(mdev, sw_owner);
119
120         caps->log_icm_size = MLX5_CAP_DEV_MEM(mdev, log_steering_sw_icm_size);
121         caps->hdr_modify_icm_addr =
122                 MLX5_CAP64_DEV_MEM(mdev, header_modify_sw_icm_start_address);
123
124         caps->roce_min_src_udp = MLX5_CAP_ROCE(mdev, r_roce_min_src_udp_port);
125
126         return 0;
127 }
128
129 int mlx5dr_cmd_query_flow_table(struct mlx5_core_dev *dev,
130                                 enum fs_flow_table_type type,
131                                 u32 table_id,
132                                 struct mlx5dr_cmd_query_flow_table_details *output)
133 {
134         u32 out[MLX5_ST_SZ_DW(query_flow_table_out)] = {};
135         u32 in[MLX5_ST_SZ_DW(query_flow_table_in)] = {};
136         int err;
137
138         MLX5_SET(query_flow_table_in, in, opcode,
139                  MLX5_CMD_OP_QUERY_FLOW_TABLE);
140
141         MLX5_SET(query_flow_table_in, in, table_type, type);
142         MLX5_SET(query_flow_table_in, in, table_id, table_id);
143
144         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
145         if (err)
146                 return err;
147
148         output->status = MLX5_GET(query_flow_table_out, out, status);
149         output->level = MLX5_GET(query_flow_table_out, out, flow_table_context.level);
150
151         output->sw_owner_icm_root_1 = MLX5_GET64(query_flow_table_out, out,
152                                                  flow_table_context.sw_owner_icm_root_1);
153         output->sw_owner_icm_root_0 = MLX5_GET64(query_flow_table_out, out,
154                                                  flow_table_context.sw_owner_icm_root_0);
155
156         return 0;
157 }
158
159 int mlx5dr_cmd_sync_steering(struct mlx5_core_dev *mdev)
160 {
161         u32 out[MLX5_ST_SZ_DW(sync_steering_out)] = {};
162         u32 in[MLX5_ST_SZ_DW(sync_steering_in)] = {};
163
164         MLX5_SET(sync_steering_in, in, opcode, MLX5_CMD_OP_SYNC_STEERING);
165
166         return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
167 }
168
169 int mlx5dr_cmd_set_fte_modify_and_vport(struct mlx5_core_dev *mdev,
170                                         u32 table_type,
171                                         u32 table_id,
172                                         u32 group_id,
173                                         u32 modify_header_id,
174                                         u32 vport_id)
175 {
176         u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {};
177         void *in_flow_context;
178         unsigned int inlen;
179         void *in_dests;
180         u32 *in;
181         int err;
182
183         inlen = MLX5_ST_SZ_BYTES(set_fte_in) +
184                 1 * MLX5_ST_SZ_BYTES(dest_format_struct); /* One destination only */
185
186         in = kvzalloc(inlen, GFP_KERNEL);
187         if (!in)
188                 return -ENOMEM;
189
190         MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY);
191         MLX5_SET(set_fte_in, in, table_type, table_type);
192         MLX5_SET(set_fte_in, in, table_id, table_id);
193
194         in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
195         MLX5_SET(flow_context, in_flow_context, group_id, group_id);
196         MLX5_SET(flow_context, in_flow_context, modify_header_id, modify_header_id);
197         MLX5_SET(flow_context, in_flow_context, destination_list_size, 1);
198         MLX5_SET(flow_context, in_flow_context, action,
199                  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST |
200                  MLX5_FLOW_CONTEXT_ACTION_MOD_HDR);
201
202         in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
203         MLX5_SET(dest_format_struct, in_dests, destination_type,
204                  MLX5_FLOW_DESTINATION_TYPE_VPORT);
205         MLX5_SET(dest_format_struct, in_dests, destination_id, vport_id);
206
207         err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
208         kvfree(in);
209
210         return err;
211 }
212
213 int mlx5dr_cmd_del_flow_table_entry(struct mlx5_core_dev *mdev,
214                                     u32 table_type,
215                                     u32 table_id)
216 {
217         u32 out[MLX5_ST_SZ_DW(delete_fte_out)] = {};
218         u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {};
219
220         MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY);
221         MLX5_SET(delete_fte_in, in, table_type, table_type);
222         MLX5_SET(delete_fte_in, in, table_id, table_id);
223
224         return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
225 }
226
227 int mlx5dr_cmd_alloc_modify_header(struct mlx5_core_dev *mdev,
228                                    u32 table_type,
229                                    u8 num_of_actions,
230                                    u64 *actions,
231                                    u32 *modify_header_id)
232 {
233         u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {};
234         void *p_actions;
235         u32 inlen;
236         u32 *in;
237         int err;
238
239         inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) +
240                  num_of_actions * sizeof(u64);
241         in = kvzalloc(inlen, GFP_KERNEL);
242         if (!in)
243                 return -ENOMEM;
244
245         MLX5_SET(alloc_modify_header_context_in, in, opcode,
246                  MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT);
247         MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type);
248         MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_of_actions);
249         p_actions = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions);
250         memcpy(p_actions, actions, num_of_actions * sizeof(u64));
251
252         err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
253         if (err)
254                 goto out;
255
256         *modify_header_id = MLX5_GET(alloc_modify_header_context_out, out,
257                                      modify_header_id);
258 out:
259         kvfree(in);
260         return err;
261 }
262
263 int mlx5dr_cmd_dealloc_modify_header(struct mlx5_core_dev *mdev,
264                                      u32 modify_header_id)
265 {
266         u32 out[MLX5_ST_SZ_DW(dealloc_modify_header_context_out)] = {};
267         u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {};
268
269         MLX5_SET(dealloc_modify_header_context_in, in, opcode,
270                  MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT);
271         MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id,
272                  modify_header_id);
273
274         return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
275 }
276
277 int mlx5dr_cmd_create_empty_flow_group(struct mlx5_core_dev *mdev,
278                                        u32 table_type,
279                                        u32 table_id,
280                                        u32 *group_id)
281 {
282         u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {};
283         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
284         u32 *in;
285         int err;
286
287         in = kzalloc(inlen, GFP_KERNEL);
288         if (!in)
289                 return -ENOMEM;
290
291         MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_GROUP);
292         MLX5_SET(create_flow_group_in, in, table_type, table_type);
293         MLX5_SET(create_flow_group_in, in, table_id, table_id);
294
295         err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
296         if (err)
297                 goto out;
298
299         *group_id = MLX5_GET(create_flow_group_out, out, group_id);
300
301 out:
302         kfree(in);
303         return err;
304 }
305
306 int mlx5dr_cmd_destroy_flow_group(struct mlx5_core_dev *mdev,
307                                   u32 table_type,
308                                   u32 table_id,
309                                   u32 group_id)
310 {
311         u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {};
312         u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)] = {};
313
314         MLX5_SET(create_flow_group_in, in, opcode, MLX5_CMD_OP_DESTROY_FLOW_GROUP);
315         MLX5_SET(destroy_flow_group_in, in, table_type, table_type);
316         MLX5_SET(destroy_flow_group_in, in, table_id, table_id);
317         MLX5_SET(destroy_flow_group_in, in, group_id, group_id);
318
319         return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
320 }
321
322 int mlx5dr_cmd_create_flow_table(struct mlx5_core_dev *mdev,
323                                  u32 table_type,
324                                  u64 icm_addr_rx,
325                                  u64 icm_addr_tx,
326                                  u8 level,
327                                  bool sw_owner,
328                                  bool term_tbl,
329                                  u64 *fdb_rx_icm_addr,
330                                  u32 *table_id)
331 {
332         u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {};
333         u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {};
334         void *ft_mdev;
335         int err;
336
337         MLX5_SET(create_flow_table_in, in, opcode, MLX5_CMD_OP_CREATE_FLOW_TABLE);
338         MLX5_SET(create_flow_table_in, in, table_type, table_type);
339
340         ft_mdev = MLX5_ADDR_OF(create_flow_table_in, in, flow_table_context);
341         MLX5_SET(flow_table_context, ft_mdev, termination_table, term_tbl);
342         MLX5_SET(flow_table_context, ft_mdev, sw_owner, sw_owner);
343         MLX5_SET(flow_table_context, ft_mdev, level, level);
344
345         if (sw_owner) {
346                 /* icm_addr_0 used for FDB RX / NIC TX / NIC_RX
347                  * icm_addr_1 used for FDB TX
348                  */
349                 if (table_type == MLX5_FLOW_TABLE_TYPE_NIC_RX) {
350                         MLX5_SET64(flow_table_context, ft_mdev,
351                                    sw_owner_icm_root_0, icm_addr_rx);
352                 } else if (table_type == MLX5_FLOW_TABLE_TYPE_NIC_TX) {
353                         MLX5_SET64(flow_table_context, ft_mdev,
354                                    sw_owner_icm_root_0, icm_addr_tx);
355                 } else if (table_type == MLX5_FLOW_TABLE_TYPE_FDB) {
356                         MLX5_SET64(flow_table_context, ft_mdev,
357                                    sw_owner_icm_root_0, icm_addr_rx);
358                         MLX5_SET64(flow_table_context, ft_mdev,
359                                    sw_owner_icm_root_1, icm_addr_tx);
360                 }
361         }
362
363         err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
364         if (err)
365                 return err;
366
367         *table_id = MLX5_GET(create_flow_table_out, out, table_id);
368         if (!sw_owner && table_type == MLX5_FLOW_TABLE_TYPE_FDB)
369                 *fdb_rx_icm_addr =
370                 (u64)MLX5_GET(create_flow_table_out, out, icm_address_31_0) |
371                 (u64)MLX5_GET(create_flow_table_out, out, icm_address_39_32) << 32 |
372                 (u64)MLX5_GET(create_flow_table_out, out, icm_address_63_40) << 40;
373
374         return 0;
375 }
376
377 int mlx5dr_cmd_destroy_flow_table(struct mlx5_core_dev *mdev,
378                                   u32 table_id,
379                                   u32 table_type)
380 {
381         u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)] = {};
382         u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {};
383
384         MLX5_SET(destroy_flow_table_in, in, opcode,
385                  MLX5_CMD_OP_DESTROY_FLOW_TABLE);
386         MLX5_SET(destroy_flow_table_in, in, table_type, table_type);
387         MLX5_SET(destroy_flow_table_in, in, table_id, table_id);
388
389         return mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
390 }
391
392 int mlx5dr_cmd_create_reformat_ctx(struct mlx5_core_dev *mdev,
393                                    enum mlx5_reformat_ctx_type rt,
394                                    size_t reformat_size,
395                                    void *reformat_data,
396                                    u32 *reformat_id)
397 {
398         u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {};
399         size_t inlen, cmd_data_sz, cmd_total_sz;
400         void *prctx;
401         void *pdata;
402         void *in;
403         int err;
404
405         cmd_total_sz = MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in);
406         cmd_data_sz = MLX5_FLD_SZ_BYTES(alloc_packet_reformat_context_in,
407                                         packet_reformat_context.reformat_data);
408         inlen = ALIGN(cmd_total_sz + reformat_size - cmd_data_sz, 4);
409         in = kvzalloc(inlen, GFP_KERNEL);
410         if (!in)
411                 return -ENOMEM;
412
413         MLX5_SET(alloc_packet_reformat_context_in, in, opcode,
414                  MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT);
415
416         prctx = MLX5_ADDR_OF(alloc_packet_reformat_context_in, in, packet_reformat_context);
417         pdata = MLX5_ADDR_OF(packet_reformat_context_in, prctx, reformat_data);
418
419         MLX5_SET(packet_reformat_context_in, prctx, reformat_type, rt);
420         MLX5_SET(packet_reformat_context_in, prctx, reformat_data_size, reformat_size);
421         memcpy(pdata, reformat_data, reformat_size);
422
423         err = mlx5_cmd_exec(mdev, in, inlen, out, sizeof(out));
424         if (err)
425                 return err;
426
427         *reformat_id = MLX5_GET(alloc_packet_reformat_context_out, out, packet_reformat_id);
428         kvfree(in);
429
430         return err;
431 }
432
433 void mlx5dr_cmd_destroy_reformat_ctx(struct mlx5_core_dev *mdev,
434                                      u32 reformat_id)
435 {
436         u32 out[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_out)] = {};
437         u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {};
438
439         MLX5_SET(dealloc_packet_reformat_context_in, in, opcode,
440                  MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT);
441         MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id,
442                  reformat_id);
443
444         mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
445 }
446
447 int mlx5dr_cmd_query_gid(struct mlx5_core_dev *mdev, u8 vhca_port_num,
448                          u16 index, struct mlx5dr_cmd_gid_attr *attr)
449 {
450         u32 out[MLX5_ST_SZ_DW(query_roce_address_out)] = {};
451         u32 in[MLX5_ST_SZ_DW(query_roce_address_in)] = {};
452         int err;
453
454         MLX5_SET(query_roce_address_in, in, opcode,
455                  MLX5_CMD_OP_QUERY_ROCE_ADDRESS);
456
457         MLX5_SET(query_roce_address_in, in, roce_address_index, index);
458         MLX5_SET(query_roce_address_in, in, vhca_port_num, vhca_port_num);
459
460         err = mlx5_cmd_exec(mdev, in, sizeof(in), out, sizeof(out));
461         if (err)
462                 return err;
463
464         memcpy(&attr->gid,
465                MLX5_ADDR_OF(query_roce_address_out,
466                             out, roce_address.source_l3_address),
467                sizeof(attr->gid));
468         memcpy(attr->mac,
469                MLX5_ADDR_OF(query_roce_address_out, out,
470                             roce_address.source_mac_47_32),
471                sizeof(attr->mac));
472
473         if (MLX5_GET(query_roce_address_out, out,
474                      roce_address.roce_version) == MLX5_ROCE_VERSION_2)
475                 attr->roce_ver = MLX5_ROCE_VERSION_2;
476         else
477                 attr->roce_ver = MLX5_ROCE_VERSION_1;
478
479         return 0;
480 }