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