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