]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/net/ethernet/mellanox/mlx5/core/fs_cmd.c
net/mlx5: Introduce alloc_encap and dealloc_encap commands
[karo-tx-linux.git] / drivers / net / ethernet / mellanox / mlx5 / core / fs_cmd.c
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"
39 #include "mlx5_core.h"
40
41 int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev,
42                             struct mlx5_flow_table *ft)
43 {
44         u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)]   = {0};
45         u32 out[MLX5_ST_SZ_DW(set_flow_table_root_out)] = {0};
46
47         MLX5_SET(set_flow_table_root_in, in, opcode,
48                  MLX5_CMD_OP_SET_FLOW_TABLE_ROOT);
49         MLX5_SET(set_flow_table_root_in, in, table_type, ft->type);
50         MLX5_SET(set_flow_table_root_in, in, table_id, ft->id);
51         if (ft->vport) {
52                 MLX5_SET(set_flow_table_root_in, in, vport_number, ft->vport);
53                 MLX5_SET(set_flow_table_root_in, in, other_vport, 1);
54         }
55
56         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
57 }
58
59 int mlx5_cmd_create_flow_table(struct mlx5_core_dev *dev,
60                                u16 vport,
61                                enum fs_flow_table_type type, unsigned int level,
62                                unsigned int log_size, struct mlx5_flow_table
63                                *next_ft, unsigned int *table_id)
64 {
65         u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0};
66         u32 in[MLX5_ST_SZ_DW(create_flow_table_in)]   = {0};
67         int err;
68
69         MLX5_SET(create_flow_table_in, in, opcode,
70                  MLX5_CMD_OP_CREATE_FLOW_TABLE);
71
72         if (next_ft) {
73                 MLX5_SET(create_flow_table_in, in, table_miss_mode, 1);
74                 MLX5_SET(create_flow_table_in, in, table_miss_id, next_ft->id);
75         }
76         MLX5_SET(create_flow_table_in, in, table_type, type);
77         MLX5_SET(create_flow_table_in, in, level, level);
78         MLX5_SET(create_flow_table_in, in, log_size, log_size);
79         if (vport) {
80                 MLX5_SET(create_flow_table_in, in, vport_number, vport);
81                 MLX5_SET(create_flow_table_in, in, other_vport, 1);
82         }
83
84         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
85         if (!err)
86                 *table_id = MLX5_GET(create_flow_table_out, out,
87                                      table_id);
88         return err;
89 }
90
91 int mlx5_cmd_destroy_flow_table(struct mlx5_core_dev *dev,
92                                 struct mlx5_flow_table *ft)
93 {
94         u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)]   = {0};
95         u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)] = {0};
96
97         MLX5_SET(destroy_flow_table_in, in, opcode,
98                  MLX5_CMD_OP_DESTROY_FLOW_TABLE);
99         MLX5_SET(destroy_flow_table_in, in, table_type, ft->type);
100         MLX5_SET(destroy_flow_table_in, in, table_id, ft->id);
101         if (ft->vport) {
102                 MLX5_SET(destroy_flow_table_in, in, vport_number, ft->vport);
103                 MLX5_SET(destroy_flow_table_in, in, other_vport, 1);
104         }
105
106         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
107 }
108
109 int mlx5_cmd_modify_flow_table(struct mlx5_core_dev *dev,
110                                struct mlx5_flow_table *ft,
111                                struct mlx5_flow_table *next_ft)
112 {
113         u32 in[MLX5_ST_SZ_DW(modify_flow_table_in)]   = {0};
114         u32 out[MLX5_ST_SZ_DW(modify_flow_table_out)] = {0};
115
116         MLX5_SET(modify_flow_table_in, in, opcode,
117                  MLX5_CMD_OP_MODIFY_FLOW_TABLE);
118         MLX5_SET(modify_flow_table_in, in, table_type, ft->type);
119         MLX5_SET(modify_flow_table_in, in, table_id, ft->id);
120         if (ft->vport) {
121                 MLX5_SET(modify_flow_table_in, in, vport_number, ft->vport);
122                 MLX5_SET(modify_flow_table_in, in, other_vport, 1);
123         }
124         MLX5_SET(modify_flow_table_in, in, modify_field_select,
125                  MLX5_MODIFY_FLOW_TABLE_MISS_TABLE_ID);
126         if (next_ft) {
127                 MLX5_SET(modify_flow_table_in, in, table_miss_mode, 1);
128                 MLX5_SET(modify_flow_table_in, in, table_miss_id, next_ft->id);
129         } else {
130                 MLX5_SET(modify_flow_table_in, in, table_miss_mode, 0);
131         }
132
133         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
134 }
135
136 int mlx5_cmd_create_flow_group(struct mlx5_core_dev *dev,
137                                struct mlx5_flow_table *ft,
138                                u32 *in,
139                                unsigned int *group_id)
140 {
141         u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {0};
142         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
143         int err;
144
145         MLX5_SET(create_flow_group_in, in, opcode,
146                  MLX5_CMD_OP_CREATE_FLOW_GROUP);
147         MLX5_SET(create_flow_group_in, in, table_type, ft->type);
148         MLX5_SET(create_flow_group_in, in, table_id, ft->id);
149         if (ft->vport) {
150                 MLX5_SET(create_flow_group_in, in, vport_number, ft->vport);
151                 MLX5_SET(create_flow_group_in, in, other_vport, 1);
152         }
153
154         err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
155         if (!err)
156                 *group_id = MLX5_GET(create_flow_group_out, out,
157                                      group_id);
158         return err;
159 }
160
161 int mlx5_cmd_destroy_flow_group(struct mlx5_core_dev *dev,
162                                 struct mlx5_flow_table *ft,
163                                 unsigned int group_id)
164 {
165         u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)] = {0};
166         u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)]   = {0};
167
168         MLX5_SET(destroy_flow_group_in, in, opcode,
169                  MLX5_CMD_OP_DESTROY_FLOW_GROUP);
170         MLX5_SET(destroy_flow_group_in, in, table_type, ft->type);
171         MLX5_SET(destroy_flow_group_in, in, table_id, ft->id);
172         MLX5_SET(destroy_flow_group_in, in, group_id, group_id);
173         if (ft->vport) {
174                 MLX5_SET(destroy_flow_group_in, in, vport_number, ft->vport);
175                 MLX5_SET(destroy_flow_group_in, in, other_vport, 1);
176         }
177
178         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
179 }
180
181 static int mlx5_cmd_set_fte(struct mlx5_core_dev *dev,
182                             int opmod, int modify_mask,
183                             struct mlx5_flow_table *ft,
184                             unsigned group_id,
185                             struct fs_fte *fte)
186 {
187         unsigned int inlen = MLX5_ST_SZ_BYTES(set_fte_in) +
188                 fte->dests_size * MLX5_ST_SZ_BYTES(dest_format_struct);
189         u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {0};
190         struct mlx5_flow_rule *dst;
191         void *in_flow_context;
192         void *in_match_value;
193         void *in_dests;
194         u32 *in;
195         int err;
196
197         in = mlx5_vzalloc(inlen);
198         if (!in) {
199                 mlx5_core_warn(dev, "failed to allocate inbox\n");
200                 return -ENOMEM;
201         }
202
203         MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY);
204         MLX5_SET(set_fte_in, in, op_mod, opmod);
205         MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask);
206         MLX5_SET(set_fte_in, in, table_type, ft->type);
207         MLX5_SET(set_fte_in, in, table_id,   ft->id);
208         MLX5_SET(set_fte_in, in, flow_index, fte->index);
209         if (ft->vport) {
210                 MLX5_SET(set_fte_in, in, vport_number, ft->vport);
211                 MLX5_SET(set_fte_in, in, other_vport, 1);
212         }
213
214         in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
215         MLX5_SET(flow_context, in_flow_context, group_id, group_id);
216         MLX5_SET(flow_context, in_flow_context, flow_tag, fte->flow_tag);
217         MLX5_SET(flow_context, in_flow_context, action, fte->action);
218         in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context,
219                                       match_value);
220         memcpy(in_match_value, &fte->val, MLX5_ST_SZ_BYTES(fte_match_param));
221
222         in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
223         if (fte->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
224                 int list_size = 0;
225
226                 list_for_each_entry(dst, &fte->node.children, node.list) {
227                         unsigned int id;
228
229                         if (dst->dest_attr.type == MLX5_FLOW_DESTINATION_TYPE_COUNTER)
230                                 continue;
231
232                         MLX5_SET(dest_format_struct, in_dests, destination_type,
233                                  dst->dest_attr.type);
234                         if (dst->dest_attr.type ==
235                             MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE) {
236                                 id = dst->dest_attr.ft->id;
237                         } else {
238                                 id = dst->dest_attr.tir_num;
239                         }
240                         MLX5_SET(dest_format_struct, in_dests, destination_id, id);
241                         in_dests += MLX5_ST_SZ_BYTES(dest_format_struct);
242                         list_size++;
243                 }
244
245                 MLX5_SET(flow_context, in_flow_context, destination_list_size,
246                          list_size);
247         }
248
249         if (fte->action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
250                 int list_size = 0;
251
252                 list_for_each_entry(dst, &fte->node.children, node.list) {
253                         if (dst->dest_attr.type !=
254                             MLX5_FLOW_DESTINATION_TYPE_COUNTER)
255                                 continue;
256
257                         MLX5_SET(flow_counter_list, in_dests, flow_counter_id,
258                                  dst->dest_attr.counter->id);
259                         in_dests += MLX5_ST_SZ_BYTES(dest_format_struct);
260                         list_size++;
261                 }
262
263                 MLX5_SET(flow_context, in_flow_context, flow_counter_list_size,
264                          list_size);
265         }
266
267         err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
268         kvfree(in);
269         return err;
270 }
271
272 int mlx5_cmd_create_fte(struct mlx5_core_dev *dev,
273                         struct mlx5_flow_table *ft,
274                         unsigned group_id,
275                         struct fs_fte *fte)
276 {
277         return mlx5_cmd_set_fte(dev, 0, 0, ft, group_id, fte);
278 }
279
280 int mlx5_cmd_update_fte(struct mlx5_core_dev *dev,
281                         struct mlx5_flow_table *ft,
282                         unsigned group_id,
283                         int modify_mask,
284                         struct fs_fte *fte)
285 {
286         int opmod;
287         int atomic_mod_cap = MLX5_CAP_FLOWTABLE(dev,
288                                                 flow_table_properties_nic_receive.
289                                                 flow_modify_en);
290         if (!atomic_mod_cap)
291                 return -ENOTSUPP;
292         opmod = 1;
293
294         return  mlx5_cmd_set_fte(dev, opmod, modify_mask, ft, group_id, fte);
295 }
296
297 int mlx5_cmd_delete_fte(struct mlx5_core_dev *dev,
298                         struct mlx5_flow_table *ft,
299                         unsigned int index)
300 {
301         u32 out[MLX5_ST_SZ_DW(delete_fte_out)] = {0};
302         u32 in[MLX5_ST_SZ_DW(delete_fte_in)]   = {0};
303
304         MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY);
305         MLX5_SET(delete_fte_in, in, table_type, ft->type);
306         MLX5_SET(delete_fte_in, in, table_id, ft->id);
307         MLX5_SET(delete_fte_in, in, flow_index, index);
308         if (ft->vport) {
309                 MLX5_SET(delete_fte_in, in, vport_number, ft->vport);
310                 MLX5_SET(delete_fte_in, in, other_vport, 1);
311         }
312
313         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
314 }
315
316 int mlx5_cmd_fc_alloc(struct mlx5_core_dev *dev, u16 *id)
317 {
318         u32 in[MLX5_ST_SZ_DW(alloc_flow_counter_in)]   = {0};
319         u32 out[MLX5_ST_SZ_DW(alloc_flow_counter_out)] = {0};
320         int err;
321
322         MLX5_SET(alloc_flow_counter_in, in, opcode,
323                  MLX5_CMD_OP_ALLOC_FLOW_COUNTER);
324
325         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
326         if (!err)
327                 *id = MLX5_GET(alloc_flow_counter_out, out, flow_counter_id);
328         return err;
329 }
330
331 int mlx5_cmd_fc_free(struct mlx5_core_dev *dev, u16 id)
332 {
333         u32 in[MLX5_ST_SZ_DW(dealloc_flow_counter_in)]   = {0};
334         u32 out[MLX5_ST_SZ_DW(dealloc_flow_counter_out)] = {0};
335
336         MLX5_SET(dealloc_flow_counter_in, in, opcode,
337                  MLX5_CMD_OP_DEALLOC_FLOW_COUNTER);
338         MLX5_SET(dealloc_flow_counter_in, in, flow_counter_id, id);
339         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
340 }
341
342 int mlx5_cmd_fc_query(struct mlx5_core_dev *dev, u16 id,
343                       u64 *packets, u64 *bytes)
344 {
345         u32 out[MLX5_ST_SZ_BYTES(query_flow_counter_out) +
346                 MLX5_ST_SZ_BYTES(traffic_counter)]   = {0};
347         u32 in[MLX5_ST_SZ_DW(query_flow_counter_in)] = {0};
348         void *stats;
349         int err = 0;
350
351         MLX5_SET(query_flow_counter_in, in, opcode,
352                  MLX5_CMD_OP_QUERY_FLOW_COUNTER);
353         MLX5_SET(query_flow_counter_in, in, op_mod, 0);
354         MLX5_SET(query_flow_counter_in, in, flow_counter_id, id);
355         err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
356         if (err)
357                 return err;
358
359         stats = MLX5_ADDR_OF(query_flow_counter_out, out, flow_statistics);
360         *packets = MLX5_GET64(traffic_counter, stats, packets);
361         *bytes = MLX5_GET64(traffic_counter, stats, octets);
362         return 0;
363 }
364
365 struct mlx5_cmd_fc_bulk {
366         u16 id;
367         int num;
368         int outlen;
369         u32 out[0];
370 };
371
372 struct mlx5_cmd_fc_bulk *
373 mlx5_cmd_fc_bulk_alloc(struct mlx5_core_dev *dev, u16 id, int num)
374 {
375         struct mlx5_cmd_fc_bulk *b;
376         int outlen = sizeof(*b) +
377                 MLX5_ST_SZ_BYTES(query_flow_counter_out) +
378                 MLX5_ST_SZ_BYTES(traffic_counter) * num;
379
380         b = kzalloc(outlen, GFP_KERNEL);
381         if (!b)
382                 return NULL;
383
384         b->id = id;
385         b->num = num;
386         b->outlen = outlen;
387
388         return b;
389 }
390
391 void mlx5_cmd_fc_bulk_free(struct mlx5_cmd_fc_bulk *b)
392 {
393         kfree(b);
394 }
395
396 int
397 mlx5_cmd_fc_bulk_query(struct mlx5_core_dev *dev, struct mlx5_cmd_fc_bulk *b)
398 {
399         u32 in[MLX5_ST_SZ_DW(query_flow_counter_in)] = {0};
400
401         MLX5_SET(query_flow_counter_in, in, opcode,
402                  MLX5_CMD_OP_QUERY_FLOW_COUNTER);
403         MLX5_SET(query_flow_counter_in, in, op_mod, 0);
404         MLX5_SET(query_flow_counter_in, in, flow_counter_id, b->id);
405         MLX5_SET(query_flow_counter_in, in, num_of_counters, b->num);
406         return mlx5_cmd_exec(dev, in, sizeof(in), b->out, b->outlen);
407 }
408
409 void mlx5_cmd_fc_bulk_get(struct mlx5_core_dev *dev,
410                           struct mlx5_cmd_fc_bulk *b, u16 id,
411                           u64 *packets, u64 *bytes)
412 {
413         int index = id - b->id;
414         void *stats;
415
416         if (index < 0 || index >= b->num) {
417                 mlx5_core_warn(dev, "Flow counter id (0x%x) out of range (0x%x..0x%x). Counter ignored.\n",
418                                id, b->id, b->id + b->num - 1);
419                 return;
420         }
421
422         stats = MLX5_ADDR_OF(query_flow_counter_out, b->out,
423                              flow_statistics[index]);
424         *packets = MLX5_GET64(traffic_counter, stats, packets);
425         *bytes = MLX5_GET64(traffic_counter, stats, octets);
426 }
427
428 #define MAX_ENCAP_SIZE (128)
429
430 int mlx5_cmd_alloc_encap(struct mlx5_core_dev *dev,
431                          int header_type,
432                          size_t size,
433                          void *encap_header,
434                          u32 *encap_id)
435 {
436         u32 out[MLX5_ST_SZ_DW(alloc_encap_header_out)];
437         u32 in[MLX5_ST_SZ_DW(alloc_encap_header_in) +
438               (MAX_ENCAP_SIZE / sizeof(u32))];
439         void *encap_header_in = MLX5_ADDR_OF(alloc_encap_header_in, in,
440                                              encap_header);
441         void *header = MLX5_ADDR_OF(encap_header_in, encap_header_in,
442                                     encap_header);
443         int inlen = header - (void *)in  + size;
444         int err;
445
446         if (size > MAX_ENCAP_SIZE)
447                 return -EINVAL;
448
449         memset(in, 0, inlen);
450         MLX5_SET(alloc_encap_header_in, in, opcode,
451                  MLX5_CMD_OP_ALLOC_ENCAP_HEADER);
452         MLX5_SET(encap_header_in, encap_header_in, encap_header_size, size);
453         MLX5_SET(encap_header_in, encap_header_in, header_type, header_type);
454         memcpy(header, encap_header, size);
455
456         memset(out, 0, sizeof(out));
457         err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
458
459         *encap_id = MLX5_GET(alloc_encap_header_out, out, encap_id);
460         return err;
461 }
462
463 void mlx5_cmd_dealloc_encap(struct mlx5_core_dev *dev, u32 encap_id)
464 {
465         u32 in[MLX5_ST_SZ_DW(dealloc_encap_header_in)];
466         u32 out[MLX5_ST_SZ_DW(dealloc_encap_header_out)];
467
468         memset(in, 0, sizeof(in));
469         MLX5_SET(dealloc_encap_header_in, in, opcode,
470                  MLX5_CMD_OP_DEALLOC_ENCAP_HEADER);
471         MLX5_SET(dealloc_encap_header_in, in, encap_id, encap_id);
472
473         mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
474 }