Merge tag 'linux-watchdog-4.16-rc1' of git://www.linux-watchdog.org/linux-watchdog
[sfrench/cifs-2.6.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch_offloads.c
1 /*
2  * Copyright (c) 2016, 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/etherdevice.h>
34 #include <linux/mlx5/driver.h>
35 #include <linux/mlx5/mlx5_ifc.h>
36 #include <linux/mlx5/vport.h>
37 #include <linux/mlx5/fs.h>
38 #include "mlx5_core.h"
39 #include "eswitch.h"
40
41 enum {
42         FDB_FAST_PATH = 0,
43         FDB_SLOW_PATH
44 };
45
46 struct mlx5_flow_handle *
47 mlx5_eswitch_add_offloaded_rule(struct mlx5_eswitch *esw,
48                                 struct mlx5_flow_spec *spec,
49                                 struct mlx5_esw_flow_attr *attr)
50 {
51         struct mlx5_flow_destination dest[2] = {};
52         struct mlx5_flow_act flow_act = {0};
53         struct mlx5_fc *counter = NULL;
54         struct mlx5_flow_handle *rule;
55         void *misc;
56         int i = 0;
57
58         if (esw->mode != SRIOV_OFFLOADS)
59                 return ERR_PTR(-EOPNOTSUPP);
60
61         /* per flow vlan pop/push is emulated, don't set that into the firmware */
62         flow_act.action = attr->action & ~(MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH | MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
63
64         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST) {
65                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
66                 dest[i].vport_num = attr->out_rep->vport;
67                 i++;
68         }
69         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_COUNT) {
70                 counter = mlx5_fc_create(esw->dev, true);
71                 if (IS_ERR(counter)) {
72                         rule = ERR_CAST(counter);
73                         goto err_counter_alloc;
74                 }
75                 dest[i].type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
76                 dest[i].counter = counter;
77                 i++;
78         }
79
80         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
81         MLX5_SET(fte_match_set_misc, misc, source_port, attr->in_rep->vport);
82
83         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
84         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
85
86         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS |
87                                       MLX5_MATCH_MISC_PARAMETERS;
88         if (flow_act.action & MLX5_FLOW_CONTEXT_ACTION_DECAP)
89                 spec->match_criteria_enable |= MLX5_MATCH_INNER_HEADERS;
90
91         if (attr->action & MLX5_FLOW_CONTEXT_ACTION_MOD_HDR)
92                 flow_act.modify_id = attr->mod_hdr_id;
93
94         if (attr->action & MLX5_FLOW_CONTEXT_ACTION_ENCAP)
95                 flow_act.encap_id = attr->encap_id;
96
97         rule = mlx5_add_flow_rules((struct mlx5_flow_table *)esw->fdb_table.fdb,
98                                    spec, &flow_act, dest, i);
99         if (IS_ERR(rule))
100                 goto err_add_rule;
101         else
102                 esw->offloads.num_flows++;
103
104         return rule;
105
106 err_add_rule:
107         mlx5_fc_destroy(esw->dev, counter);
108 err_counter_alloc:
109         return rule;
110 }
111
112 void
113 mlx5_eswitch_del_offloaded_rule(struct mlx5_eswitch *esw,
114                                 struct mlx5_flow_handle *rule,
115                                 struct mlx5_esw_flow_attr *attr)
116 {
117         struct mlx5_fc *counter = NULL;
118
119         counter = mlx5_flow_rule_counter(rule);
120         mlx5_del_flow_rules(rule);
121         mlx5_fc_destroy(esw->dev, counter);
122         esw->offloads.num_flows--;
123 }
124
125 static int esw_set_global_vlan_pop(struct mlx5_eswitch *esw, u8 val)
126 {
127         struct mlx5_eswitch_rep *rep;
128         int vf_vport, err = 0;
129
130         esw_debug(esw->dev, "%s applying global %s policy\n", __func__, val ? "pop" : "none");
131         for (vf_vport = 1; vf_vport < esw->enabled_vports; vf_vport++) {
132                 rep = &esw->offloads.vport_reps[vf_vport];
133                 if (!rep->rep_if[REP_ETH].valid)
134                         continue;
135
136                 err = __mlx5_eswitch_set_vport_vlan(esw, rep->vport, 0, 0, val);
137                 if (err)
138                         goto out;
139         }
140
141 out:
142         return err;
143 }
144
145 static struct mlx5_eswitch_rep *
146 esw_vlan_action_get_vport(struct mlx5_esw_flow_attr *attr, bool push, bool pop)
147 {
148         struct mlx5_eswitch_rep *in_rep, *out_rep, *vport = NULL;
149
150         in_rep  = attr->in_rep;
151         out_rep = attr->out_rep;
152
153         if (push)
154                 vport = in_rep;
155         else if (pop)
156                 vport = out_rep;
157         else
158                 vport = in_rep;
159
160         return vport;
161 }
162
163 static int esw_add_vlan_action_check(struct mlx5_esw_flow_attr *attr,
164                                      bool push, bool pop, bool fwd)
165 {
166         struct mlx5_eswitch_rep *in_rep, *out_rep;
167
168         if ((push || pop) && !fwd)
169                 goto out_notsupp;
170
171         in_rep  = attr->in_rep;
172         out_rep = attr->out_rep;
173
174         if (push && in_rep->vport == FDB_UPLINK_VPORT)
175                 goto out_notsupp;
176
177         if (pop && out_rep->vport == FDB_UPLINK_VPORT)
178                 goto out_notsupp;
179
180         /* vport has vlan push configured, can't offload VF --> wire rules w.o it */
181         if (!push && !pop && fwd)
182                 if (in_rep->vlan && out_rep->vport == FDB_UPLINK_VPORT)
183                         goto out_notsupp;
184
185         /* protects against (1) setting rules with different vlans to push and
186          * (2) setting rules w.o vlans (attr->vlan = 0) && w. vlans to push (!= 0)
187          */
188         if (push && in_rep->vlan_refcount && (in_rep->vlan != attr->vlan))
189                 goto out_notsupp;
190
191         return 0;
192
193 out_notsupp:
194         return -EOPNOTSUPP;
195 }
196
197 int mlx5_eswitch_add_vlan_action(struct mlx5_eswitch *esw,
198                                  struct mlx5_esw_flow_attr *attr)
199 {
200         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
201         struct mlx5_eswitch_rep *vport = NULL;
202         bool push, pop, fwd;
203         int err = 0;
204
205         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
206         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
207         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
208
209         err = esw_add_vlan_action_check(attr, push, pop, fwd);
210         if (err)
211                 return err;
212
213         attr->vlan_handled = false;
214
215         vport = esw_vlan_action_get_vport(attr, push, pop);
216
217         if (!push && !pop && fwd) {
218                 /* tracks VF --> wire rules without vlan push action */
219                 if (attr->out_rep->vport == FDB_UPLINK_VPORT) {
220                         vport->vlan_refcount++;
221                         attr->vlan_handled = true;
222                 }
223
224                 return 0;
225         }
226
227         if (!push && !pop)
228                 return 0;
229
230         if (!(offloads->vlan_push_pop_refcount)) {
231                 /* it's the 1st vlan rule, apply global vlan pop policy */
232                 err = esw_set_global_vlan_pop(esw, SET_VLAN_STRIP);
233                 if (err)
234                         goto out;
235         }
236         offloads->vlan_push_pop_refcount++;
237
238         if (push) {
239                 if (vport->vlan_refcount)
240                         goto skip_set_push;
241
242                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport, attr->vlan, 0,
243                                                     SET_VLAN_INSERT | SET_VLAN_STRIP);
244                 if (err)
245                         goto out;
246                 vport->vlan = attr->vlan;
247 skip_set_push:
248                 vport->vlan_refcount++;
249         }
250 out:
251         if (!err)
252                 attr->vlan_handled = true;
253         return err;
254 }
255
256 int mlx5_eswitch_del_vlan_action(struct mlx5_eswitch *esw,
257                                  struct mlx5_esw_flow_attr *attr)
258 {
259         struct offloads_fdb *offloads = &esw->fdb_table.offloads;
260         struct mlx5_eswitch_rep *vport = NULL;
261         bool push, pop, fwd;
262         int err = 0;
263
264         if (!attr->vlan_handled)
265                 return 0;
266
267         push = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_PUSH);
268         pop  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_VLAN_POP);
269         fwd  = !!(attr->action & MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
270
271         vport = esw_vlan_action_get_vport(attr, push, pop);
272
273         if (!push && !pop && fwd) {
274                 /* tracks VF --> wire rules without vlan push action */
275                 if (attr->out_rep->vport == FDB_UPLINK_VPORT)
276                         vport->vlan_refcount--;
277
278                 return 0;
279         }
280
281         if (push) {
282                 vport->vlan_refcount--;
283                 if (vport->vlan_refcount)
284                         goto skip_unset_push;
285
286                 vport->vlan = 0;
287                 err = __mlx5_eswitch_set_vport_vlan(esw, vport->vport,
288                                                     0, 0, SET_VLAN_STRIP);
289                 if (err)
290                         goto out;
291         }
292
293 skip_unset_push:
294         offloads->vlan_push_pop_refcount--;
295         if (offloads->vlan_push_pop_refcount)
296                 return 0;
297
298         /* no more vlan rules, stop global vlan pop policy */
299         err = esw_set_global_vlan_pop(esw, 0);
300
301 out:
302         return err;
303 }
304
305 struct mlx5_flow_handle *
306 mlx5_eswitch_add_send_to_vport_rule(struct mlx5_eswitch *esw, int vport, u32 sqn)
307 {
308         struct mlx5_flow_act flow_act = {0};
309         struct mlx5_flow_destination dest = {};
310         struct mlx5_flow_handle *flow_rule;
311         struct mlx5_flow_spec *spec;
312         void *misc;
313
314         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
315         if (!spec) {
316                 flow_rule = ERR_PTR(-ENOMEM);
317                 goto out;
318         }
319
320         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
321         MLX5_SET(fte_match_set_misc, misc, source_sqn, sqn);
322         MLX5_SET(fte_match_set_misc, misc, source_port, 0x0); /* source vport is 0 */
323
324         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
325         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_sqn);
326         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
327
328         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
329         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
330         dest.vport_num = vport;
331         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
332
333         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fdb, spec,
334                                         &flow_act, &dest, 1);
335         if (IS_ERR(flow_rule))
336                 esw_warn(esw->dev, "FDB: Failed to add send to vport rule err %ld\n", PTR_ERR(flow_rule));
337 out:
338         kvfree(spec);
339         return flow_rule;
340 }
341
342 void mlx5_eswitch_del_send_to_vport_rule(struct mlx5_flow_handle *rule)
343 {
344         mlx5_del_flow_rules(rule);
345 }
346
347 static int esw_add_fdb_miss_rule(struct mlx5_eswitch *esw)
348 {
349         struct mlx5_flow_act flow_act = {0};
350         struct mlx5_flow_destination dest = {};
351         struct mlx5_flow_handle *flow_rule = NULL;
352         struct mlx5_flow_spec *spec;
353         int err = 0;
354
355         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
356         if (!spec) {
357                 err = -ENOMEM;
358                 goto out;
359         }
360
361         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
362         dest.vport_num = 0;
363         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
364
365         flow_rule = mlx5_add_flow_rules(esw->fdb_table.offloads.fdb, spec,
366                                         &flow_act, &dest, 1);
367         if (IS_ERR(flow_rule)) {
368                 err = PTR_ERR(flow_rule);
369                 esw_warn(esw->dev,  "FDB: Failed to add miss flow rule err %d\n", err);
370                 goto out;
371         }
372
373         esw->fdb_table.offloads.miss_rule = flow_rule;
374 out:
375         kvfree(spec);
376         return err;
377 }
378
379 #define ESW_OFFLOADS_NUM_GROUPS  4
380
381 static int esw_create_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
382 {
383         struct mlx5_core_dev *dev = esw->dev;
384         struct mlx5_flow_namespace *root_ns;
385         struct mlx5_flow_table *fdb = NULL;
386         int esw_size, err = 0;
387         u32 flags = 0;
388         u32 max_flow_counter = (MLX5_CAP_GEN(dev, max_flow_counter_31_16) << 16) |
389                                 MLX5_CAP_GEN(dev, max_flow_counter_15_0);
390
391         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
392         if (!root_ns) {
393                 esw_warn(dev, "Failed to get FDB flow namespace\n");
394                 err = -EOPNOTSUPP;
395                 goto out;
396         }
397
398         esw_debug(dev, "Create offloads FDB table, min (max esw size(2^%d), max counters(%d)*groups(%d))\n",
399                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size),
400                   max_flow_counter, ESW_OFFLOADS_NUM_GROUPS);
401
402         esw_size = min_t(int, max_flow_counter * ESW_OFFLOADS_NUM_GROUPS,
403                          1 << MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
404
405         if (esw->offloads.encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE)
406                 flags |= MLX5_FLOW_TABLE_TUNNEL_EN;
407
408         fdb = mlx5_create_auto_grouped_flow_table(root_ns, FDB_FAST_PATH,
409                                                   esw_size,
410                                                   ESW_OFFLOADS_NUM_GROUPS, 0,
411                                                   flags);
412         if (IS_ERR(fdb)) {
413                 err = PTR_ERR(fdb);
414                 esw_warn(dev, "Failed to create Fast path FDB Table err %d\n", err);
415                 goto out;
416         }
417         esw->fdb_table.fdb = fdb;
418
419 out:
420         return err;
421 }
422
423 static void esw_destroy_offloads_fast_fdb_table(struct mlx5_eswitch *esw)
424 {
425         mlx5_destroy_flow_table(esw->fdb_table.fdb);
426 }
427
428 #define MAX_PF_SQ 256
429
430 static int esw_create_offloads_fdb_tables(struct mlx5_eswitch *esw, int nvports)
431 {
432         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
433         struct mlx5_flow_table_attr ft_attr = {};
434         struct mlx5_core_dev *dev = esw->dev;
435         struct mlx5_flow_namespace *root_ns;
436         struct mlx5_flow_table *fdb = NULL;
437         int table_size, ix, err = 0;
438         struct mlx5_flow_group *g;
439         void *match_criteria;
440         u32 *flow_group_in;
441
442         esw_debug(esw->dev, "Create offloads FDB Tables\n");
443         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
444         if (!flow_group_in)
445                 return -ENOMEM;
446
447         root_ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_FDB);
448         if (!root_ns) {
449                 esw_warn(dev, "Failed to get FDB flow namespace\n");
450                 err = -EOPNOTSUPP;
451                 goto ns_err;
452         }
453
454         err = esw_create_offloads_fast_fdb_table(esw);
455         if (err)
456                 goto fast_fdb_err;
457
458         table_size = nvports + MAX_PF_SQ + 1;
459
460         ft_attr.max_fte = table_size;
461         ft_attr.prio = FDB_SLOW_PATH;
462
463         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
464         if (IS_ERR(fdb)) {
465                 err = PTR_ERR(fdb);
466                 esw_warn(dev, "Failed to create slow path FDB Table err %d\n", err);
467                 goto slow_fdb_err;
468         }
469         esw->fdb_table.offloads.fdb = fdb;
470
471         /* create send-to-vport group */
472         memset(flow_group_in, 0, inlen);
473         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
474                  MLX5_MATCH_MISC_PARAMETERS);
475
476         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
477
478         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_sqn);
479         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
480
481         ix = nvports + MAX_PF_SQ;
482         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
483         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix - 1);
484
485         g = mlx5_create_flow_group(fdb, flow_group_in);
486         if (IS_ERR(g)) {
487                 err = PTR_ERR(g);
488                 esw_warn(dev, "Failed to create send-to-vport flow group err(%d)\n", err);
489                 goto send_vport_err;
490         }
491         esw->fdb_table.offloads.send_to_vport_grp = g;
492
493         /* create miss group */
494         memset(flow_group_in, 0, inlen);
495         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, 0);
496
497         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, ix);
498         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, ix + 1);
499
500         g = mlx5_create_flow_group(fdb, flow_group_in);
501         if (IS_ERR(g)) {
502                 err = PTR_ERR(g);
503                 esw_warn(dev, "Failed to create miss flow group err(%d)\n", err);
504                 goto miss_err;
505         }
506         esw->fdb_table.offloads.miss_grp = g;
507
508         err = esw_add_fdb_miss_rule(esw);
509         if (err)
510                 goto miss_rule_err;
511
512         return 0;
513
514 miss_rule_err:
515         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
516 miss_err:
517         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
518 send_vport_err:
519         mlx5_destroy_flow_table(esw->fdb_table.offloads.fdb);
520 slow_fdb_err:
521         mlx5_destroy_flow_table(esw->fdb_table.fdb);
522 fast_fdb_err:
523 ns_err:
524         kvfree(flow_group_in);
525         return err;
526 }
527
528 static void esw_destroy_offloads_fdb_tables(struct mlx5_eswitch *esw)
529 {
530         if (!esw->fdb_table.fdb)
531                 return;
532
533         esw_debug(esw->dev, "Destroy offloads FDB Tables\n");
534         mlx5_del_flow_rules(esw->fdb_table.offloads.miss_rule);
535         mlx5_destroy_flow_group(esw->fdb_table.offloads.send_to_vport_grp);
536         mlx5_destroy_flow_group(esw->fdb_table.offloads.miss_grp);
537
538         mlx5_destroy_flow_table(esw->fdb_table.offloads.fdb);
539         esw_destroy_offloads_fast_fdb_table(esw);
540 }
541
542 static int esw_create_offloads_table(struct mlx5_eswitch *esw)
543 {
544         struct mlx5_flow_table_attr ft_attr = {};
545         struct mlx5_core_dev *dev = esw->dev;
546         struct mlx5_flow_table *ft_offloads;
547         struct mlx5_flow_namespace *ns;
548         int err = 0;
549
550         ns = mlx5_get_flow_namespace(dev, MLX5_FLOW_NAMESPACE_OFFLOADS);
551         if (!ns) {
552                 esw_warn(esw->dev, "Failed to get offloads flow namespace\n");
553                 return -EOPNOTSUPP;
554         }
555
556         ft_attr.max_fte = dev->priv.sriov.num_vfs + 2;
557
558         ft_offloads = mlx5_create_flow_table(ns, &ft_attr);
559         if (IS_ERR(ft_offloads)) {
560                 err = PTR_ERR(ft_offloads);
561                 esw_warn(esw->dev, "Failed to create offloads table, err %d\n", err);
562                 return err;
563         }
564
565         esw->offloads.ft_offloads = ft_offloads;
566         return 0;
567 }
568
569 static void esw_destroy_offloads_table(struct mlx5_eswitch *esw)
570 {
571         struct mlx5_esw_offload *offloads = &esw->offloads;
572
573         mlx5_destroy_flow_table(offloads->ft_offloads);
574 }
575
576 static int esw_create_vport_rx_group(struct mlx5_eswitch *esw)
577 {
578         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
579         struct mlx5_flow_group *g;
580         struct mlx5_priv *priv = &esw->dev->priv;
581         u32 *flow_group_in;
582         void *match_criteria, *misc;
583         int err = 0;
584         int nvports = priv->sriov.num_vfs + 2;
585
586         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
587         if (!flow_group_in)
588                 return -ENOMEM;
589
590         /* create vport rx group */
591         memset(flow_group_in, 0, inlen);
592         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
593                  MLX5_MATCH_MISC_PARAMETERS);
594
595         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
596         misc = MLX5_ADDR_OF(fte_match_param, match_criteria, misc_parameters);
597         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
598
599         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
600         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, nvports - 1);
601
602         g = mlx5_create_flow_group(esw->offloads.ft_offloads, flow_group_in);
603
604         if (IS_ERR(g)) {
605                 err = PTR_ERR(g);
606                 mlx5_core_warn(esw->dev, "Failed to create vport rx group err %d\n", err);
607                 goto out;
608         }
609
610         esw->offloads.vport_rx_group = g;
611 out:
612         kfree(flow_group_in);
613         return err;
614 }
615
616 static void esw_destroy_vport_rx_group(struct mlx5_eswitch *esw)
617 {
618         mlx5_destroy_flow_group(esw->offloads.vport_rx_group);
619 }
620
621 struct mlx5_flow_handle *
622 mlx5_eswitch_create_vport_rx_rule(struct mlx5_eswitch *esw, int vport, u32 tirn)
623 {
624         struct mlx5_flow_act flow_act = {0};
625         struct mlx5_flow_destination dest = {};
626         struct mlx5_flow_handle *flow_rule;
627         struct mlx5_flow_spec *spec;
628         void *misc;
629
630         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
631         if (!spec) {
632                 flow_rule = ERR_PTR(-ENOMEM);
633                 goto out;
634         }
635
636         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
637         MLX5_SET(fte_match_set_misc, misc, source_port, vport);
638
639         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
640         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
641
642         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
643         dest.type = MLX5_FLOW_DESTINATION_TYPE_TIR;
644         dest.tir_num = tirn;
645
646         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
647         flow_rule = mlx5_add_flow_rules(esw->offloads.ft_offloads, spec,
648                                         &flow_act, &dest, 1);
649         if (IS_ERR(flow_rule)) {
650                 esw_warn(esw->dev, "fs offloads: Failed to add vport rx rule err %ld\n", PTR_ERR(flow_rule));
651                 goto out;
652         }
653
654 out:
655         kvfree(spec);
656         return flow_rule;
657 }
658
659 static int esw_offloads_start(struct mlx5_eswitch *esw)
660 {
661         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
662
663         if (esw->mode != SRIOV_LEGACY) {
664                 esw_warn(esw->dev, "Can't set offloads mode, SRIOV legacy not enabled\n");
665                 return -EINVAL;
666         }
667
668         mlx5_eswitch_disable_sriov(esw);
669         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
670         if (err) {
671                 esw_warn(esw->dev, "Failed setting eswitch to offloads, err %d\n", err);
672                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
673                 if (err1)
674                         esw_warn(esw->dev, "Failed setting eswitch back to legacy, err %d\n", err1);
675         }
676         if (esw->offloads.inline_mode == MLX5_INLINE_MODE_NONE) {
677                 if (mlx5_eswitch_inline_mode_get(esw,
678                                                  num_vfs,
679                                                  &esw->offloads.inline_mode)) {
680                         esw->offloads.inline_mode = MLX5_INLINE_MODE_L2;
681                         esw_warn(esw->dev, "Inline mode is different between vports\n");
682                 }
683         }
684         return err;
685 }
686
687 void esw_offloads_cleanup_reps(struct mlx5_eswitch *esw)
688 {
689         kfree(esw->offloads.vport_reps);
690 }
691
692 int esw_offloads_init_reps(struct mlx5_eswitch *esw)
693 {
694         int total_vfs = MLX5_TOTAL_VPORTS(esw->dev);
695         struct mlx5_core_dev *dev = esw->dev;
696         struct mlx5_esw_offload *offloads;
697         struct mlx5_eswitch_rep *rep;
698         u8 hw_id[ETH_ALEN];
699         int vport;
700
701         esw->offloads.vport_reps = kcalloc(total_vfs,
702                                            sizeof(struct mlx5_eswitch_rep),
703                                            GFP_KERNEL);
704         if (!esw->offloads.vport_reps)
705                 return -ENOMEM;
706
707         offloads = &esw->offloads;
708         mlx5_query_nic_vport_mac_address(dev, 0, hw_id);
709
710         for (vport = 0; vport < total_vfs; vport++) {
711                 rep = &offloads->vport_reps[vport];
712
713                 rep->vport = vport;
714                 ether_addr_copy(rep->hw_id, hw_id);
715         }
716
717         offloads->vport_reps[0].vport = FDB_UPLINK_VPORT;
718
719         return 0;
720 }
721
722 static void esw_offloads_unload_reps_type(struct mlx5_eswitch *esw, int nvports,
723                                           u8 rep_type)
724 {
725         struct mlx5_eswitch_rep *rep;
726         int vport;
727
728         for (vport = nvports - 1; vport >= 0; vport--) {
729                 rep = &esw->offloads.vport_reps[vport];
730                 if (!rep->rep_if[rep_type].valid)
731                         continue;
732
733                 rep->rep_if[rep_type].unload(rep);
734         }
735 }
736
737 static void esw_offloads_unload_reps(struct mlx5_eswitch *esw, int nvports)
738 {
739         u8 rep_type = NUM_REP_TYPES;
740
741         while (rep_type-- > 0)
742                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
743 }
744
745 static int esw_offloads_load_reps_type(struct mlx5_eswitch *esw, int nvports,
746                                        u8 rep_type)
747 {
748         struct mlx5_eswitch_rep *rep;
749         int vport;
750         int err;
751
752         for (vport = 0; vport < nvports; vport++) {
753                 rep = &esw->offloads.vport_reps[vport];
754                 if (!rep->rep_if[rep_type].valid)
755                         continue;
756
757                 err = rep->rep_if[rep_type].load(esw->dev, rep);
758                 if (err)
759                         goto err_reps;
760         }
761
762         return 0;
763
764 err_reps:
765         esw_offloads_unload_reps_type(esw, vport, rep_type);
766         return err;
767 }
768
769 static int esw_offloads_load_reps(struct mlx5_eswitch *esw, int nvports)
770 {
771         u8 rep_type = 0;
772         int err;
773
774         for (rep_type = 0; rep_type < NUM_REP_TYPES; rep_type++) {
775                 err = esw_offloads_load_reps_type(esw, nvports, rep_type);
776                 if (err)
777                         goto err_reps;
778         }
779
780         return err;
781
782 err_reps:
783         while (rep_type-- > 0)
784                 esw_offloads_unload_reps_type(esw, nvports, rep_type);
785         return err;
786 }
787
788 int esw_offloads_init(struct mlx5_eswitch *esw, int nvports)
789 {
790         int err;
791
792         /* disable PF RoCE so missed packets don't go through RoCE steering */
793         mlx5_dev_list_lock();
794         mlx5_remove_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
795         mlx5_dev_list_unlock();
796
797         err = esw_create_offloads_fdb_tables(esw, nvports);
798         if (err)
799                 goto create_fdb_err;
800
801         err = esw_create_offloads_table(esw);
802         if (err)
803                 goto create_ft_err;
804
805         err = esw_create_vport_rx_group(esw);
806         if (err)
807                 goto create_fg_err;
808
809         err = esw_offloads_load_reps(esw, nvports);
810         if (err)
811                 goto err_reps;
812
813         return 0;
814
815 err_reps:
816         esw_destroy_vport_rx_group(esw);
817
818 create_fg_err:
819         esw_destroy_offloads_table(esw);
820
821 create_ft_err:
822         esw_destroy_offloads_fdb_tables(esw);
823
824 create_fdb_err:
825         /* enable back PF RoCE */
826         mlx5_dev_list_lock();
827         mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
828         mlx5_dev_list_unlock();
829
830         return err;
831 }
832
833 static int esw_offloads_stop(struct mlx5_eswitch *esw)
834 {
835         int err, err1, num_vfs = esw->dev->priv.sriov.num_vfs;
836
837         mlx5_eswitch_disable_sriov(esw);
838         err = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_LEGACY);
839         if (err) {
840                 esw_warn(esw->dev, "Failed setting eswitch to legacy, err %d\n", err);
841                 err1 = mlx5_eswitch_enable_sriov(esw, num_vfs, SRIOV_OFFLOADS);
842                 if (err1)
843                         esw_warn(esw->dev, "Failed setting eswitch back to offloads, err %d\n", err);
844         }
845
846         /* enable back PF RoCE */
847         mlx5_dev_list_lock();
848         mlx5_add_dev_by_protocol(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
849         mlx5_dev_list_unlock();
850
851         return err;
852 }
853
854 void esw_offloads_cleanup(struct mlx5_eswitch *esw, int nvports)
855 {
856         esw_offloads_unload_reps(esw, nvports);
857         esw_destroy_vport_rx_group(esw);
858         esw_destroy_offloads_table(esw);
859         esw_destroy_offloads_fdb_tables(esw);
860 }
861
862 static int esw_mode_from_devlink(u16 mode, u16 *mlx5_mode)
863 {
864         switch (mode) {
865         case DEVLINK_ESWITCH_MODE_LEGACY:
866                 *mlx5_mode = SRIOV_LEGACY;
867                 break;
868         case DEVLINK_ESWITCH_MODE_SWITCHDEV:
869                 *mlx5_mode = SRIOV_OFFLOADS;
870                 break;
871         default:
872                 return -EINVAL;
873         }
874
875         return 0;
876 }
877
878 static int esw_mode_to_devlink(u16 mlx5_mode, u16 *mode)
879 {
880         switch (mlx5_mode) {
881         case SRIOV_LEGACY:
882                 *mode = DEVLINK_ESWITCH_MODE_LEGACY;
883                 break;
884         case SRIOV_OFFLOADS:
885                 *mode = DEVLINK_ESWITCH_MODE_SWITCHDEV;
886                 break;
887         default:
888                 return -EINVAL;
889         }
890
891         return 0;
892 }
893
894 static int esw_inline_mode_from_devlink(u8 mode, u8 *mlx5_mode)
895 {
896         switch (mode) {
897         case DEVLINK_ESWITCH_INLINE_MODE_NONE:
898                 *mlx5_mode = MLX5_INLINE_MODE_NONE;
899                 break;
900         case DEVLINK_ESWITCH_INLINE_MODE_LINK:
901                 *mlx5_mode = MLX5_INLINE_MODE_L2;
902                 break;
903         case DEVLINK_ESWITCH_INLINE_MODE_NETWORK:
904                 *mlx5_mode = MLX5_INLINE_MODE_IP;
905                 break;
906         case DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT:
907                 *mlx5_mode = MLX5_INLINE_MODE_TCP_UDP;
908                 break;
909         default:
910                 return -EINVAL;
911         }
912
913         return 0;
914 }
915
916 static int esw_inline_mode_to_devlink(u8 mlx5_mode, u8 *mode)
917 {
918         switch (mlx5_mode) {
919         case MLX5_INLINE_MODE_NONE:
920                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NONE;
921                 break;
922         case MLX5_INLINE_MODE_L2:
923                 *mode = DEVLINK_ESWITCH_INLINE_MODE_LINK;
924                 break;
925         case MLX5_INLINE_MODE_IP:
926                 *mode = DEVLINK_ESWITCH_INLINE_MODE_NETWORK;
927                 break;
928         case MLX5_INLINE_MODE_TCP_UDP:
929                 *mode = DEVLINK_ESWITCH_INLINE_MODE_TRANSPORT;
930                 break;
931         default:
932                 return -EINVAL;
933         }
934
935         return 0;
936 }
937
938 static int mlx5_devlink_eswitch_check(struct devlink *devlink)
939 {
940         struct mlx5_core_dev *dev = devlink_priv(devlink);
941
942         if (MLX5_CAP_GEN(dev, port_type) != MLX5_CAP_PORT_TYPE_ETH)
943                 return -EOPNOTSUPP;
944
945         if (!MLX5_CAP_GEN(dev, vport_group_manager))
946                 return -EOPNOTSUPP;
947
948         if (dev->priv.eswitch->mode == SRIOV_NONE)
949                 return -EOPNOTSUPP;
950
951         return 0;
952 }
953
954 int mlx5_devlink_eswitch_mode_set(struct devlink *devlink, u16 mode)
955 {
956         struct mlx5_core_dev *dev = devlink_priv(devlink);
957         u16 cur_mlx5_mode, mlx5_mode = 0;
958         int err;
959
960         err = mlx5_devlink_eswitch_check(devlink);
961         if (err)
962                 return err;
963
964         cur_mlx5_mode = dev->priv.eswitch->mode;
965
966         if (esw_mode_from_devlink(mode, &mlx5_mode))
967                 return -EINVAL;
968
969         if (cur_mlx5_mode == mlx5_mode)
970                 return 0;
971
972         if (mode == DEVLINK_ESWITCH_MODE_SWITCHDEV)
973                 return esw_offloads_start(dev->priv.eswitch);
974         else if (mode == DEVLINK_ESWITCH_MODE_LEGACY)
975                 return esw_offloads_stop(dev->priv.eswitch);
976         else
977                 return -EINVAL;
978 }
979
980 int mlx5_devlink_eswitch_mode_get(struct devlink *devlink, u16 *mode)
981 {
982         struct mlx5_core_dev *dev = devlink_priv(devlink);
983         int err;
984
985         err = mlx5_devlink_eswitch_check(devlink);
986         if (err)
987                 return err;
988
989         return esw_mode_to_devlink(dev->priv.eswitch->mode, mode);
990 }
991
992 int mlx5_devlink_eswitch_inline_mode_set(struct devlink *devlink, u8 mode)
993 {
994         struct mlx5_core_dev *dev = devlink_priv(devlink);
995         struct mlx5_eswitch *esw = dev->priv.eswitch;
996         int err, vport;
997         u8 mlx5_mode;
998
999         err = mlx5_devlink_eswitch_check(devlink);
1000         if (err)
1001                 return err;
1002
1003         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1004         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1005                 if (mode == DEVLINK_ESWITCH_INLINE_MODE_NONE)
1006                         return 0;
1007                 /* fall through */
1008         case MLX5_CAP_INLINE_MODE_L2:
1009                 esw_warn(dev, "Inline mode can't be set\n");
1010                 return -EOPNOTSUPP;
1011         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1012                 break;
1013         }
1014
1015         if (esw->offloads.num_flows > 0) {
1016                 esw_warn(dev, "Can't set inline mode when flows are configured\n");
1017                 return -EOPNOTSUPP;
1018         }
1019
1020         err = esw_inline_mode_from_devlink(mode, &mlx5_mode);
1021         if (err)
1022                 goto out;
1023
1024         for (vport = 1; vport < esw->enabled_vports; vport++) {
1025                 err = mlx5_modify_nic_vport_min_inline(dev, vport, mlx5_mode);
1026                 if (err) {
1027                         esw_warn(dev, "Failed to set min inline on vport %d\n",
1028                                  vport);
1029                         goto revert_inline_mode;
1030                 }
1031         }
1032
1033         esw->offloads.inline_mode = mlx5_mode;
1034         return 0;
1035
1036 revert_inline_mode:
1037         while (--vport > 0)
1038                 mlx5_modify_nic_vport_min_inline(dev,
1039                                                  vport,
1040                                                  esw->offloads.inline_mode);
1041 out:
1042         return err;
1043 }
1044
1045 int mlx5_devlink_eswitch_inline_mode_get(struct devlink *devlink, u8 *mode)
1046 {
1047         struct mlx5_core_dev *dev = devlink_priv(devlink);
1048         struct mlx5_eswitch *esw = dev->priv.eswitch;
1049         int err;
1050
1051         err = mlx5_devlink_eswitch_check(devlink);
1052         if (err)
1053                 return err;
1054
1055         return esw_inline_mode_to_devlink(esw->offloads.inline_mode, mode);
1056 }
1057
1058 int mlx5_eswitch_inline_mode_get(struct mlx5_eswitch *esw, int nvfs, u8 *mode)
1059 {
1060         u8 prev_mlx5_mode, mlx5_mode = MLX5_INLINE_MODE_L2;
1061         struct mlx5_core_dev *dev = esw->dev;
1062         int vport;
1063
1064         if (!MLX5_CAP_GEN(dev, vport_group_manager))
1065                 return -EOPNOTSUPP;
1066
1067         if (esw->mode == SRIOV_NONE)
1068                 return -EOPNOTSUPP;
1069
1070         switch (MLX5_CAP_ETH(dev, wqe_inline_mode)) {
1071         case MLX5_CAP_INLINE_MODE_NOT_REQUIRED:
1072                 mlx5_mode = MLX5_INLINE_MODE_NONE;
1073                 goto out;
1074         case MLX5_CAP_INLINE_MODE_L2:
1075                 mlx5_mode = MLX5_INLINE_MODE_L2;
1076                 goto out;
1077         case MLX5_CAP_INLINE_MODE_VPORT_CONTEXT:
1078                 goto query_vports;
1079         }
1080
1081 query_vports:
1082         for (vport = 1; vport <= nvfs; vport++) {
1083                 mlx5_query_nic_vport_min_inline(dev, vport, &mlx5_mode);
1084                 if (vport > 1 && prev_mlx5_mode != mlx5_mode)
1085                         return -EINVAL;
1086                 prev_mlx5_mode = mlx5_mode;
1087         }
1088
1089 out:
1090         *mode = mlx5_mode;
1091         return 0;
1092 }
1093
1094 int mlx5_devlink_eswitch_encap_mode_set(struct devlink *devlink, u8 encap)
1095 {
1096         struct mlx5_core_dev *dev = devlink_priv(devlink);
1097         struct mlx5_eswitch *esw = dev->priv.eswitch;
1098         int err;
1099
1100         err = mlx5_devlink_eswitch_check(devlink);
1101         if (err)
1102                 return err;
1103
1104         if (encap != DEVLINK_ESWITCH_ENCAP_MODE_NONE &&
1105             (!MLX5_CAP_ESW_FLOWTABLE_FDB(dev, encap) ||
1106              !MLX5_CAP_ESW_FLOWTABLE_FDB(dev, decap)))
1107                 return -EOPNOTSUPP;
1108
1109         if (encap && encap != DEVLINK_ESWITCH_ENCAP_MODE_BASIC)
1110                 return -EOPNOTSUPP;
1111
1112         if (esw->mode == SRIOV_LEGACY) {
1113                 esw->offloads.encap = encap;
1114                 return 0;
1115         }
1116
1117         if (esw->offloads.encap == encap)
1118                 return 0;
1119
1120         if (esw->offloads.num_flows > 0) {
1121                 esw_warn(dev, "Can't set encapsulation when flows are configured\n");
1122                 return -EOPNOTSUPP;
1123         }
1124
1125         esw_destroy_offloads_fast_fdb_table(esw);
1126
1127         esw->offloads.encap = encap;
1128         err = esw_create_offloads_fast_fdb_table(esw);
1129         if (err) {
1130                 esw_warn(esw->dev, "Failed re-creating fast FDB table, err %d\n", err);
1131                 esw->offloads.encap = !encap;
1132                 (void)esw_create_offloads_fast_fdb_table(esw);
1133         }
1134         return err;
1135 }
1136
1137 int mlx5_devlink_eswitch_encap_mode_get(struct devlink *devlink, u8 *encap)
1138 {
1139         struct mlx5_core_dev *dev = devlink_priv(devlink);
1140         struct mlx5_eswitch *esw = dev->priv.eswitch;
1141         int err;
1142
1143         err = mlx5_devlink_eswitch_check(devlink);
1144         if (err)
1145                 return err;
1146
1147         *encap = esw->offloads.encap;
1148         return 0;
1149 }
1150
1151 void mlx5_eswitch_register_vport_rep(struct mlx5_eswitch *esw,
1152                                      int vport_index,
1153                                      struct mlx5_eswitch_rep_if *__rep_if,
1154                                      u8 rep_type)
1155 {
1156         struct mlx5_esw_offload *offloads = &esw->offloads;
1157         struct mlx5_eswitch_rep_if *rep_if;
1158
1159         rep_if = &offloads->vport_reps[vport_index].rep_if[rep_type];
1160
1161         rep_if->load   = __rep_if->load;
1162         rep_if->unload = __rep_if->unload;
1163         rep_if->priv = __rep_if->priv;
1164
1165         rep_if->valid = true;
1166 }
1167
1168 void mlx5_eswitch_unregister_vport_rep(struct mlx5_eswitch *esw,
1169                                        int vport_index, u8 rep_type)
1170 {
1171         struct mlx5_esw_offload *offloads = &esw->offloads;
1172         struct mlx5_eswitch_rep *rep;
1173
1174         rep = &offloads->vport_reps[vport_index];
1175
1176         if (esw->mode == SRIOV_OFFLOADS && esw->vports[vport_index].enabled)
1177                 rep->rep_if[rep_type].unload(rep);
1178
1179         rep->rep_if[rep_type].valid = false;
1180 }
1181
1182 void *mlx5_eswitch_get_uplink_priv(struct mlx5_eswitch *esw, u8 rep_type)
1183 {
1184 #define UPLINK_REP_INDEX 0
1185         struct mlx5_esw_offload *offloads = &esw->offloads;
1186         struct mlx5_eswitch_rep *rep;
1187
1188         rep = &offloads->vport_reps[UPLINK_REP_INDEX];
1189         return rep->rep_if[rep_type].priv;
1190 }