1 /*-
2 * Copyright (c) 2013-2017, Mellanox Technologies, Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include "opt_rss.h"
27 #include "opt_ratelimit.h"
28
29 #include <linux/types.h>
30 #include <linux/module.h>
31 #include <dev/mlx5/mlx5_ifc.h>
32 #include <dev/mlx5/device.h>
33 #include <dev/mlx5/fs.h>
34
35 #include <dev/mlx5/mlx5_core/fs_core.h>
36 #include <dev/mlx5/mlx5_core/mlx5_core.h>
37
mlx5_cmd_update_root_ft(struct mlx5_core_dev * dev,enum fs_ft_type type,unsigned int id)38 int mlx5_cmd_update_root_ft(struct mlx5_core_dev *dev,
39 enum fs_ft_type type,
40 unsigned int id)
41 {
42 u32 in[MLX5_ST_SZ_DW(set_flow_table_root_in)] = {0};
43 u32 out[MLX5_ST_SZ_DW(set_flow_table_root_out)] = {0};
44
45 if (!dev)
46 return -EINVAL;
47
48 MLX5_SET(set_flow_table_root_in, in, opcode,
49 MLX5_CMD_OP_SET_FLOW_TABLE_ROOT);
50 MLX5_SET(set_flow_table_root_in, in, table_type, type);
51 MLX5_SET(set_flow_table_root_in, in, table_id, id);
52
53 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
54 }
55
mlx5_cmd_fs_create_ft(struct mlx5_core_dev * dev,u16 vport,enum fs_ft_type type,unsigned int level,unsigned int log_size,const char * name,unsigned int * table_id)56 int mlx5_cmd_fs_create_ft(struct mlx5_core_dev *dev,
57 u16 vport, enum fs_ft_type type, unsigned int level,
58 unsigned int log_size, const char *name, unsigned int *table_id)
59 {
60 u32 in[MLX5_ST_SZ_DW(create_flow_table_in)] = {0};
61 u32 out[MLX5_ST_SZ_DW(create_flow_table_out)] = {0};
62 int err;
63
64 if (!dev)
65 return -EINVAL;
66
67 MLX5_SET(create_flow_table_in, in, opcode,
68 MLX5_CMD_OP_CREATE_FLOW_TABLE);
69
70 MLX5_SET(create_flow_table_in, in, table_type, type);
71 MLX5_SET(create_flow_table_in, in, flow_table_context.level, level);
72 MLX5_SET(create_flow_table_in, in, flow_table_context.log_size,
73 log_size);
74 if (strstr(name, FS_REFORMAT_KEYWORD) != NULL)
75 MLX5_SET(create_flow_table_in, in,
76 flow_table_context.reformat_en, 1);
77 if (vport) {
78 MLX5_SET(create_flow_table_in, in, vport_number, vport);
79 MLX5_SET(create_flow_table_in, in, other_vport, 1);
80 }
81
82 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
83 if (!err)
84 *table_id = MLX5_GET(create_flow_table_out, out, table_id);
85
86 return err;
87 }
88
mlx5_cmd_fs_destroy_ft(struct mlx5_core_dev * dev,u16 vport,enum fs_ft_type type,unsigned int table_id)89 int mlx5_cmd_fs_destroy_ft(struct mlx5_core_dev *dev,
90 u16 vport,
91 enum fs_ft_type type, unsigned int table_id)
92 {
93 u32 in[MLX5_ST_SZ_DW(destroy_flow_table_in)] = {0};
94 u32 out[MLX5_ST_SZ_DW(destroy_flow_table_out)] = {0};
95
96 if (!dev)
97 return -EINVAL;
98
99 MLX5_SET(destroy_flow_table_in, in, opcode,
100 MLX5_CMD_OP_DESTROY_FLOW_TABLE);
101 MLX5_SET(destroy_flow_table_in, in, table_type, type);
102 MLX5_SET(destroy_flow_table_in, in, table_id, table_id);
103 if (vport) {
104 MLX5_SET(destroy_flow_table_in, in, vport_number, vport);
105 MLX5_SET(destroy_flow_table_in, in, other_vport, 1);
106 }
107
108 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
109 }
110
mlx5_cmd_fs_create_fg(struct mlx5_core_dev * dev,u32 * in,u16 vport,enum fs_ft_type type,unsigned int table_id,unsigned int * group_id)111 int mlx5_cmd_fs_create_fg(struct mlx5_core_dev *dev,
112 u32 *in,
113 u16 vport,
114 enum fs_ft_type type, unsigned int table_id,
115 unsigned int *group_id)
116 {
117 u32 out[MLX5_ST_SZ_DW(create_flow_group_out)] = {0};
118 int err;
119 int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
120 if (!dev)
121 return -EINVAL;
122
123 MLX5_SET(create_flow_group_in, in, opcode,
124 MLX5_CMD_OP_CREATE_FLOW_GROUP);
125 MLX5_SET(create_flow_group_in, in, table_type, type);
126 MLX5_SET(create_flow_group_in, in, table_id, table_id);
127 if (vport) {
128 MLX5_SET(create_flow_group_in, in, vport_number, vport);
129 MLX5_SET(create_flow_group_in, in, other_vport, 1);
130 }
131
132 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
133 if (!err)
134 *group_id = MLX5_GET(create_flow_group_out, out, group_id);
135
136 return err;
137 }
138
mlx5_cmd_fs_destroy_fg(struct mlx5_core_dev * dev,u16 vport,enum fs_ft_type type,unsigned int table_id,unsigned int group_id)139 int mlx5_cmd_fs_destroy_fg(struct mlx5_core_dev *dev,
140 u16 vport,
141 enum fs_ft_type type, unsigned int table_id,
142 unsigned int group_id)
143 {
144 u32 in[MLX5_ST_SZ_DW(destroy_flow_group_in)] = {0};
145 u32 out[MLX5_ST_SZ_DW(destroy_flow_group_out)] = {0};
146
147 if (!dev)
148 return -EINVAL;
149
150 MLX5_SET(destroy_flow_group_in, in, opcode,
151 MLX5_CMD_OP_DESTROY_FLOW_GROUP);
152 MLX5_SET(destroy_flow_group_in, in, table_type, type);
153 MLX5_SET(destroy_flow_group_in, in, table_id, table_id);
154 MLX5_SET(destroy_flow_group_in, in, group_id, group_id);
155 if (vport) {
156 MLX5_SET(destroy_flow_group_in, in, vport_number, vport);
157 MLX5_SET(destroy_flow_group_in, in, other_vport, 1);
158 }
159
160 return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
161 }
162
mlx5_cmd_fs_set_fte(struct mlx5_core_dev * dev,u16 vport,enum fs_fte_status * fte_status,u32 * match_val,enum fs_ft_type type,unsigned int table_id,unsigned int index,unsigned int group_id,struct mlx5_flow_act * flow_act,u32 sw_action,int dest_size,struct list_head * dests)163 int mlx5_cmd_fs_set_fte(struct mlx5_core_dev *dev,
164 u16 vport,
165 enum fs_fte_status *fte_status,
166 u32 *match_val,
167 enum fs_ft_type type, unsigned int table_id,
168 unsigned int index, unsigned int group_id,
169 struct mlx5_flow_act *flow_act,
170 u32 sw_action, int dest_size,
171 struct list_head *dests) /* mlx5_flow_desination */
172 {
173 u32 out[MLX5_ST_SZ_DW(set_fte_out)] = {0};
174 u32 *in;
175 unsigned int inlen;
176 struct mlx5_flow_rule *dst;
177 void *in_flow_context;
178 void *in_match_value;
179 void *in_dests;
180 int err;
181 int opmod = 0;
182 int modify_mask = 0;
183 int atomic_mod_cap;
184 u32 prm_action = 0;
185 int count_list = 0;
186
187 if (sw_action != MLX5_FLOW_RULE_FWD_ACTION_DEST)
188 dest_size = 0;
189
190 if (sw_action & MLX5_FLOW_RULE_FWD_ACTION_ALLOW)
191 prm_action |= MLX5_FLOW_CONTEXT_ACTION_ALLOW;
192
193 if (sw_action & MLX5_FLOW_RULE_FWD_ACTION_DROP)
194 prm_action |= MLX5_FLOW_CONTEXT_ACTION_DROP;
195
196 if (sw_action & MLX5_FLOW_RULE_FWD_ACTION_DEST)
197 prm_action |= MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
198
199 if (flow_act->actions & MLX5_FLOW_ACT_ACTIONS_COUNT) {
200 prm_action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
201 count_list = 1;
202 }
203
204 inlen = MLX5_ST_SZ_BYTES(set_fte_in) +
205 (dest_size + count_list) * MLX5_ST_SZ_BYTES(dest_format_struct);
206
207 if (!dev)
208 return -EINVAL;
209
210 if (*fte_status & FS_FTE_STATUS_EXISTING) {
211 atomic_mod_cap = MLX5_CAP_FLOWTABLE(dev,
212 flow_table_properties_nic_receive.
213 flow_modify_en);
214 if (!atomic_mod_cap)
215 return -ENOTSUPP;
216 opmod = 1;
217 modify_mask = 1 <<
218 MLX5_SET_FTE_MODIFY_ENABLE_MASK_DESTINATION_LIST;
219 }
220
221 in = mlx5_vzalloc(inlen);
222 if (!in) {
223 mlx5_core_warn(dev, "failed to allocate inbox\n");
224 return -ENOMEM;
225 }
226
227 MLX5_SET(set_fte_in, in, opcode, MLX5_CMD_OP_SET_FLOW_TABLE_ENTRY);
228 MLX5_SET(set_fte_in, in, op_mod, opmod);
229 MLX5_SET(set_fte_in, in, modify_enable_mask, modify_mask);
230 MLX5_SET(set_fte_in, in, table_type, type);
231 MLX5_SET(set_fte_in, in, table_id, table_id);
232 MLX5_SET(set_fte_in, in, flow_index, index);
233 if (vport) {
234 MLX5_SET(set_fte_in, in, vport_number, vport);
235 MLX5_SET(set_fte_in, in, other_vport, 1);
236 }
237
238 in_flow_context = MLX5_ADDR_OF(set_fte_in, in, flow_context);
239 MLX5_SET(flow_context, in_flow_context, group_id, group_id);
240 if (flow_act->actions & MLX5_FLOW_ACT_ACTIONS_FLOW_TAG)
241 MLX5_SET(flow_context, in_flow_context, flow_tag, flow_act->flow_tag);
242 if (flow_act->actions & MLX5_FLOW_ACT_ACTIONS_MODIFY_HDR) {
243 MLX5_SET(flow_context, in_flow_context, modify_header_id,
244 flow_act->modify_hdr->id);
245 prm_action |= MLX5_FLOW_CONTEXT_ACTION_MOD_HDR;
246 }
247 if (flow_act->actions & MLX5_FLOW_ACT_ACTIONS_PACKET_REFORMAT) {
248 MLX5_SET(flow_context, in_flow_context, packet_reformat_id,
249 flow_act->pkt_reformat->id);
250 prm_action |= MLX5_FLOW_CONTEXT_ACTION_PACKET_REFORMAT;
251 }
252 MLX5_SET(flow_context, in_flow_context, destination_list_size,
253 dest_size);
254 in_match_value = MLX5_ADDR_OF(flow_context, in_flow_context,
255 match_value);
256 memcpy(in_match_value, match_val, MLX5_ST_SZ_BYTES(fte_match_param));
257
258 in_dests = MLX5_ADDR_OF(flow_context, in_flow_context, destination);
259
260 if (dest_size) {
261 list_for_each_entry(dst, dests, base.list) {
262 unsigned int id;
263
264 MLX5_SET(dest_format_struct, in_dests, destination_type,
265 dst->dest_attr.type);
266 if (dst->dest_attr.type ==
267 MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE)
268 id = dst->dest_attr.ft->id;
269 else
270 id = dst->dest_attr.tir_num;
271 MLX5_SET(dest_format_struct, in_dests, destination_id, id);
272 in_dests += MLX5_ST_SZ_BYTES(dest_format_struct);
273 }
274 }
275
276 if (flow_act->actions & MLX5_FLOW_ACT_ACTIONS_COUNT) {
277 MLX5_SET(dest_format_struct, in_dests, destination_id,
278 mlx5_fc_id(flow_act->counter));
279 in_dests += MLX5_ST_SZ_BYTES(dest_format_struct);
280 MLX5_SET(flow_context, in_flow_context, flow_counter_list_size, 1);
281 }
282
283 MLX5_SET(flow_context, in_flow_context, action, prm_action);
284 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
285 if (!err)
286 *fte_status |= FS_FTE_STATUS_EXISTING;
287
288 kvfree(in);
289
290 return err;
291 }
292
mlx5_cmd_fs_delete_fte(struct mlx5_core_dev * dev,u16 vport,enum fs_fte_status * fte_status,enum fs_ft_type type,unsigned int table_id,unsigned int index)293 int mlx5_cmd_fs_delete_fte(struct mlx5_core_dev *dev,
294 u16 vport,
295 enum fs_fte_status *fte_status,
296 enum fs_ft_type type, unsigned int table_id,
297 unsigned int index)
298 {
299 u32 in[MLX5_ST_SZ_DW(delete_fte_in)] = {0};
300 u32 out[MLX5_ST_SZ_DW(delete_fte_out)] = {0};
301 int err;
302
303 if (!(*fte_status & FS_FTE_STATUS_EXISTING))
304 return 0;
305
306 if (!dev)
307 return -EINVAL;
308
309 MLX5_SET(delete_fte_in, in, opcode, MLX5_CMD_OP_DELETE_FLOW_TABLE_ENTRY);
310 MLX5_SET(delete_fte_in, in, table_type, type);
311 MLX5_SET(delete_fte_in, in, table_id, table_id);
312 MLX5_SET(delete_fte_in, in, flow_index, index);
313 if (vport) {
314 MLX5_SET(delete_fte_in, in, vport_number, vport);
315 MLX5_SET(delete_fte_in, in, other_vport, 1);
316 }
317
318 err = mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
319 if (!err)
320 *fte_status = 0;
321
322 return err;
323 }
324
mlx5_cmd_modify_header_alloc(struct mlx5_core_dev * dev,enum mlx5_flow_namespace_type namespace,u8 num_actions,void * modify_actions,struct mlx5_modify_hdr * modify_hdr)325 int mlx5_cmd_modify_header_alloc(struct mlx5_core_dev *dev,
326 enum mlx5_flow_namespace_type namespace,
327 u8 num_actions,
328 void *modify_actions,
329 struct mlx5_modify_hdr *modify_hdr)
330 {
331 u32 out[MLX5_ST_SZ_DW(alloc_modify_header_context_out)] = {};
332 int max_actions, actions_size, inlen, err;
333 void *actions_in;
334 u8 table_type;
335 u32 *in;
336
337 switch (namespace) {
338 case MLX5_FLOW_NAMESPACE_FDB:
339 max_actions = MLX5_CAP_ESW_FLOWTABLE_FDB(dev, max_modify_header_actions);
340 table_type = FS_FT_FDB;
341 break;
342 case MLX5_FLOW_NAMESPACE_KERNEL:
343 case MLX5_FLOW_NAMESPACE_BYPASS:
344 max_actions = MLX5_CAP_FLOWTABLE_NIC_RX(dev, max_modify_header_actions);
345 table_type = FS_FT_NIC_RX;
346 break;
347 case MLX5_FLOW_NAMESPACE_ESW_INGRESS:
348 max_actions = MLX5_CAP_ESW_INGRESS_ACL(dev, max_modify_header_actions);
349 table_type = FS_FT_ESW_INGRESS_ACL;
350 break;
351 default:
352 return -EOPNOTSUPP;
353 }
354
355 if (num_actions > max_actions) {
356 mlx5_core_warn(dev, "too many modify header actions %d, max supported %d\n",
357 num_actions, max_actions);
358 return -EOPNOTSUPP;
359 }
360
361 actions_size = MLX5_UN_SZ_BYTES(set_add_copy_action_in_auto) * num_actions;
362 inlen = MLX5_ST_SZ_BYTES(alloc_modify_header_context_in) + actions_size;
363
364 in = kzalloc(inlen, GFP_KERNEL);
365 if (!in)
366 return -ENOMEM;
367
368 MLX5_SET(alloc_modify_header_context_in, in, opcode,
369 MLX5_CMD_OP_ALLOC_MODIFY_HEADER_CONTEXT);
370 MLX5_SET(alloc_modify_header_context_in, in, table_type, table_type);
371 MLX5_SET(alloc_modify_header_context_in, in, num_of_actions, num_actions);
372
373 actions_in = MLX5_ADDR_OF(alloc_modify_header_context_in, in, actions);
374 memcpy(actions_in, modify_actions, actions_size);
375
376 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
377
378 modify_hdr->id = MLX5_GET(alloc_modify_header_context_out, out, modify_header_id);
379 kfree(in);
380
381 return err;
382 }
383
mlx5_cmd_modify_header_dealloc(struct mlx5_core_dev * dev,struct mlx5_modify_hdr * modify_hdr)384 void mlx5_cmd_modify_header_dealloc(struct mlx5_core_dev *dev,
385 struct mlx5_modify_hdr *modify_hdr)
386 {
387 u32 out[MLX5_ST_SZ_DW(dealloc_modify_header_context_out)] = {};
388 u32 in[MLX5_ST_SZ_DW(dealloc_modify_header_context_in)] = {};
389
390 MLX5_SET(dealloc_modify_header_context_in, in, opcode,
391 MLX5_CMD_OP_DEALLOC_MODIFY_HEADER_CONTEXT);
392 MLX5_SET(dealloc_modify_header_context_in, in, modify_header_id,
393 modify_hdr->id);
394
395 mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
396 }
397
mlx5_cmd_packet_reformat_alloc(struct mlx5_core_dev * dev,struct mlx5_pkt_reformat_params * params,enum mlx5_flow_namespace_type namespace,struct mlx5_pkt_reformat * pkt_reformat)398 int mlx5_cmd_packet_reformat_alloc(struct mlx5_core_dev *dev,
399 struct mlx5_pkt_reformat_params *params,
400 enum mlx5_flow_namespace_type namespace,
401 struct mlx5_pkt_reformat *pkt_reformat)
402 {
403 u32 out[MLX5_ST_SZ_DW(alloc_packet_reformat_context_out)] = {};
404 void *packet_reformat_context_in;
405 int max_encap_size;
406 void *reformat;
407 int inlen;
408 int err;
409 u32 *in;
410
411 if (namespace == MLX5_FLOW_NAMESPACE_FDB)
412 max_encap_size = MLX5_CAP_ESW(dev, max_encap_header_size);
413 else
414 max_encap_size = MLX5_CAP_FLOWTABLE(dev, max_encap_header_size);
415
416 if (params->size > max_encap_size) {
417 mlx5_core_warn(dev, "encap size %zd too big, max supported is %d\n",
418 params->size, max_encap_size);
419 return -EINVAL;
420 }
421
422 in = kzalloc(MLX5_ST_SZ_BYTES(alloc_packet_reformat_context_in) +
423 params->size, GFP_KERNEL);
424 if (!in)
425 return -ENOMEM;
426
427 packet_reformat_context_in = MLX5_ADDR_OF(alloc_packet_reformat_context_in,
428 in, packet_reformat_context);
429 reformat = MLX5_ADDR_OF(packet_reformat_context_in,
430 packet_reformat_context_in,
431 reformat_data);
432 inlen = reformat - (void *)in + params->size;
433
434 MLX5_SET(alloc_packet_reformat_context_in, in, opcode,
435 MLX5_CMD_OP_ALLOC_PACKET_REFORMAT_CONTEXT);
436 MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
437 reformat_data_size, params->size);
438 MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
439 reformat_type, params->type);
440 MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
441 reformat_param_0, params->param_0);
442 MLX5_SET(packet_reformat_context_in, packet_reformat_context_in,
443 reformat_param_1, params->param_1);
444 if (params->data && params->size)
445 memcpy(reformat, params->data, params->size);
446
447 err = mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
448
449 pkt_reformat->id = MLX5_GET(alloc_packet_reformat_context_out,
450 out, packet_reformat_id);
451 kfree(in);
452
453 return err;
454 }
455
mlx5_cmd_packet_reformat_dealloc(struct mlx5_core_dev * dev,struct mlx5_pkt_reformat * pkt_reformat)456 void mlx5_cmd_packet_reformat_dealloc(struct mlx5_core_dev *dev,
457 struct mlx5_pkt_reformat *pkt_reformat)
458 {
459 u32 out[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_out)] = {};
460 u32 in[MLX5_ST_SZ_DW(dealloc_packet_reformat_context_in)] = {};
461
462 MLX5_SET(dealloc_packet_reformat_context_in, in, opcode,
463 MLX5_CMD_OP_DEALLOC_PACKET_REFORMAT_CONTEXT);
464 MLX5_SET(dealloc_packet_reformat_context_in, in, packet_reformat_id,
465 pkt_reformat->id);
466
467 mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
468 }
469