Merge tag 'zynqmp-soc-for-v5.7' of https://github.com/Xilinx/linux-xlnx into arm/soc
[linux-2.6-microblaze.git] / drivers / net / ethernet / mellanox / mlx5 / core / eswitch.c
1 /*
2  * Copyright (c) 2015, Mellanox Technologies. All rights reserved.
3  *
4  * This software is available to you under a choice of one of two
5  * licenses.  You may choose to be licensed under the terms of the GNU
6  * General Public License (GPL) Version 2, available from the file
7  * COPYING in the main directory of this source tree, or the
8  * OpenIB.org BSD license below:
9  *
10  *     Redistribution and use in source and binary forms, with or
11  *     without modification, are permitted provided that the following
12  *     conditions are met:
13  *
14  *      - Redistributions of source code must retain the above
15  *        copyright notice, this list of conditions and the following
16  *        disclaimer.
17  *
18  *      - Redistributions in binary form must reproduce the above
19  *        copyright notice, this list of conditions and the following
20  *        disclaimer in the documentation and/or other materials
21  *        provided with the distribution.
22  *
23  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
27  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
28  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
29  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30  * SOFTWARE.
31  */
32
33 #include <linux/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 "lib/eq.h"
40 #include "eswitch.h"
41 #include "fs_core.h"
42 #include "ecpf.h"
43
44 enum {
45         MLX5_ACTION_NONE = 0,
46         MLX5_ACTION_ADD  = 1,
47         MLX5_ACTION_DEL  = 2,
48 };
49
50 /* Vport UC/MC hash node */
51 struct vport_addr {
52         struct l2addr_node     node;
53         u8                     action;
54         u16                    vport;
55         struct mlx5_flow_handle *flow_rule;
56         bool mpfs; /* UC MAC was added to MPFs */
57         /* A flag indicating that mac was added due to mc promiscuous vport */
58         bool mc_promisc;
59 };
60
61 static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw);
62 static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw);
63
64 struct mlx5_vport *__must_check
65 mlx5_eswitch_get_vport(struct mlx5_eswitch *esw, u16 vport_num)
66 {
67         u16 idx;
68
69         if (!esw || !MLX5_CAP_GEN(esw->dev, vport_group_manager))
70                 return ERR_PTR(-EPERM);
71
72         idx = mlx5_eswitch_vport_num_to_index(esw, vport_num);
73
74         if (idx > esw->total_vports - 1) {
75                 esw_debug(esw->dev, "vport out of range: num(0x%x), idx(0x%x)\n",
76                           vport_num, idx);
77                 return ERR_PTR(-EINVAL);
78         }
79
80         return &esw->vports[idx];
81 }
82
83 static int arm_vport_context_events_cmd(struct mlx5_core_dev *dev, u16 vport,
84                                         u32 events_mask)
85 {
86         int in[MLX5_ST_SZ_DW(modify_nic_vport_context_in)]   = {0};
87         int out[MLX5_ST_SZ_DW(modify_nic_vport_context_out)] = {0};
88         void *nic_vport_ctx;
89
90         MLX5_SET(modify_nic_vport_context_in, in,
91                  opcode, MLX5_CMD_OP_MODIFY_NIC_VPORT_CONTEXT);
92         MLX5_SET(modify_nic_vport_context_in, in, field_select.change_event, 1);
93         MLX5_SET(modify_nic_vport_context_in, in, vport_number, vport);
94         MLX5_SET(modify_nic_vport_context_in, in, other_vport, 1);
95         nic_vport_ctx = MLX5_ADDR_OF(modify_nic_vport_context_in,
96                                      in, nic_vport_context);
97
98         MLX5_SET(nic_vport_context, nic_vport_ctx, arm_change_event, 1);
99
100         if (events_mask & MLX5_VPORT_UC_ADDR_CHANGE)
101                 MLX5_SET(nic_vport_context, nic_vport_ctx,
102                          event_on_uc_address_change, 1);
103         if (events_mask & MLX5_VPORT_MC_ADDR_CHANGE)
104                 MLX5_SET(nic_vport_context, nic_vport_ctx,
105                          event_on_mc_address_change, 1);
106         if (events_mask & MLX5_VPORT_PROMISC_CHANGE)
107                 MLX5_SET(nic_vport_context, nic_vport_ctx,
108                          event_on_promisc_change, 1);
109
110         return mlx5_cmd_exec(dev, in, sizeof(in), out, sizeof(out));
111 }
112
113 /* E-Switch vport context HW commands */
114 int mlx5_eswitch_modify_esw_vport_context(struct mlx5_core_dev *dev, u16 vport,
115                                           bool other_vport,
116                                           void *in, int inlen)
117 {
118         u32 out[MLX5_ST_SZ_DW(modify_esw_vport_context_out)] = {0};
119
120         MLX5_SET(modify_esw_vport_context_in, in, opcode,
121                  MLX5_CMD_OP_MODIFY_ESW_VPORT_CONTEXT);
122         MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
123         MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport);
124         return mlx5_cmd_exec(dev, in, inlen, out, sizeof(out));
125 }
126
127 int mlx5_eswitch_query_esw_vport_context(struct mlx5_core_dev *dev, u16 vport,
128                                          bool other_vport,
129                                          void *out, int outlen)
130 {
131         u32 in[MLX5_ST_SZ_DW(query_esw_vport_context_in)] = {};
132
133         MLX5_SET(query_esw_vport_context_in, in, opcode,
134                  MLX5_CMD_OP_QUERY_ESW_VPORT_CONTEXT);
135         MLX5_SET(modify_esw_vport_context_in, in, vport_number, vport);
136         MLX5_SET(modify_esw_vport_context_in, in, other_vport, other_vport);
137         return mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
138 }
139
140 static int modify_esw_vport_cvlan(struct mlx5_core_dev *dev, u16 vport,
141                                   u16 vlan, u8 qos, u8 set_flags)
142 {
143         u32 in[MLX5_ST_SZ_DW(modify_esw_vport_context_in)] = {0};
144
145         if (!MLX5_CAP_ESW(dev, vport_cvlan_strip) ||
146             !MLX5_CAP_ESW(dev, vport_cvlan_insert_if_not_exist))
147                 return -EOPNOTSUPP;
148
149         esw_debug(dev, "Set Vport[%d] VLAN %d qos %d set=%x\n",
150                   vport, vlan, qos, set_flags);
151
152         if (set_flags & SET_VLAN_STRIP)
153                 MLX5_SET(modify_esw_vport_context_in, in,
154                          esw_vport_context.vport_cvlan_strip, 1);
155
156         if (set_flags & SET_VLAN_INSERT) {
157                 /* insert only if no vlan in packet */
158                 MLX5_SET(modify_esw_vport_context_in, in,
159                          esw_vport_context.vport_cvlan_insert, 1);
160
161                 MLX5_SET(modify_esw_vport_context_in, in,
162                          esw_vport_context.cvlan_pcp, qos);
163                 MLX5_SET(modify_esw_vport_context_in, in,
164                          esw_vport_context.cvlan_id, vlan);
165         }
166
167         MLX5_SET(modify_esw_vport_context_in, in,
168                  field_select.vport_cvlan_strip, 1);
169         MLX5_SET(modify_esw_vport_context_in, in,
170                  field_select.vport_cvlan_insert, 1);
171
172         return mlx5_eswitch_modify_esw_vport_context(dev, vport, true,
173                                                      in, sizeof(in));
174 }
175
176 /* E-Switch FDB */
177 static struct mlx5_flow_handle *
178 __esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u16 vport, bool rx_rule,
179                          u8 mac_c[ETH_ALEN], u8 mac_v[ETH_ALEN])
180 {
181         int match_header = (is_zero_ether_addr(mac_c) ? 0 :
182                             MLX5_MATCH_OUTER_HEADERS);
183         struct mlx5_flow_handle *flow_rule = NULL;
184         struct mlx5_flow_act flow_act = {0};
185         struct mlx5_flow_destination dest = {};
186         struct mlx5_flow_spec *spec;
187         void *mv_misc = NULL;
188         void *mc_misc = NULL;
189         u8 *dmac_v = NULL;
190         u8 *dmac_c = NULL;
191
192         if (rx_rule)
193                 match_header |= MLX5_MATCH_MISC_PARAMETERS;
194
195         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
196         if (!spec)
197                 return NULL;
198
199         dmac_v = MLX5_ADDR_OF(fte_match_param, spec->match_value,
200                               outer_headers.dmac_47_16);
201         dmac_c = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
202                               outer_headers.dmac_47_16);
203
204         if (match_header & MLX5_MATCH_OUTER_HEADERS) {
205                 ether_addr_copy(dmac_v, mac_v);
206                 ether_addr_copy(dmac_c, mac_c);
207         }
208
209         if (match_header & MLX5_MATCH_MISC_PARAMETERS) {
210                 mv_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_value,
211                                         misc_parameters);
212                 mc_misc  = MLX5_ADDR_OF(fte_match_param, spec->match_criteria,
213                                         misc_parameters);
214                 MLX5_SET(fte_match_set_misc, mv_misc, source_port, MLX5_VPORT_UPLINK);
215                 MLX5_SET_TO_ONES(fte_match_set_misc, mc_misc, source_port);
216         }
217
218         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
219         dest.vport.num = vport;
220
221         esw_debug(esw->dev,
222                   "\tFDB add rule dmac_v(%pM) dmac_c(%pM) -> vport(%d)\n",
223                   dmac_v, dmac_c, vport);
224         spec->match_criteria_enable = match_header;
225         flow_act.action =  MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
226         flow_rule =
227                 mlx5_add_flow_rules(esw->fdb_table.legacy.fdb, spec,
228                                     &flow_act, &dest, 1);
229         if (IS_ERR(flow_rule)) {
230                 esw_warn(esw->dev,
231                          "FDB: Failed to add flow rule: dmac_v(%pM) dmac_c(%pM) -> vport(%d), err(%ld)\n",
232                          dmac_v, dmac_c, vport, PTR_ERR(flow_rule));
233                 flow_rule = NULL;
234         }
235
236         kvfree(spec);
237         return flow_rule;
238 }
239
240 static struct mlx5_flow_handle *
241 esw_fdb_set_vport_rule(struct mlx5_eswitch *esw, u8 mac[ETH_ALEN], u16 vport)
242 {
243         u8 mac_c[ETH_ALEN];
244
245         eth_broadcast_addr(mac_c);
246         return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac);
247 }
248
249 static struct mlx5_flow_handle *
250 esw_fdb_set_vport_allmulti_rule(struct mlx5_eswitch *esw, u16 vport)
251 {
252         u8 mac_c[ETH_ALEN];
253         u8 mac_v[ETH_ALEN];
254
255         eth_zero_addr(mac_c);
256         eth_zero_addr(mac_v);
257         mac_c[0] = 0x01;
258         mac_v[0] = 0x01;
259         return __esw_fdb_set_vport_rule(esw, vport, false, mac_c, mac_v);
260 }
261
262 static struct mlx5_flow_handle *
263 esw_fdb_set_vport_promisc_rule(struct mlx5_eswitch *esw, u16 vport)
264 {
265         u8 mac_c[ETH_ALEN];
266         u8 mac_v[ETH_ALEN];
267
268         eth_zero_addr(mac_c);
269         eth_zero_addr(mac_v);
270         return __esw_fdb_set_vport_rule(esw, vport, true, mac_c, mac_v);
271 }
272
273 enum {
274         LEGACY_VEPA_PRIO = 0,
275         LEGACY_FDB_PRIO,
276 };
277
278 static int esw_create_legacy_vepa_table(struct mlx5_eswitch *esw)
279 {
280         struct mlx5_flow_table_attr ft_attr = {};
281         struct mlx5_core_dev *dev = esw->dev;
282         struct mlx5_flow_namespace *root_ns;
283         struct mlx5_flow_table *fdb;
284         int err;
285
286         root_ns = mlx5_get_fdb_sub_ns(dev, 0);
287         if (!root_ns) {
288                 esw_warn(dev, "Failed to get FDB flow namespace\n");
289                 return -EOPNOTSUPP;
290         }
291
292         /* num FTE 2, num FG 2 */
293         ft_attr.prio = LEGACY_VEPA_PRIO;
294         ft_attr.max_fte = 2;
295         ft_attr.autogroup.max_num_groups = 2;
296         fdb = mlx5_create_auto_grouped_flow_table(root_ns, &ft_attr);
297         if (IS_ERR(fdb)) {
298                 err = PTR_ERR(fdb);
299                 esw_warn(dev, "Failed to create VEPA FDB err %d\n", err);
300                 return err;
301         }
302         esw->fdb_table.legacy.vepa_fdb = fdb;
303
304         return 0;
305 }
306
307 static int esw_create_legacy_fdb_table(struct mlx5_eswitch *esw)
308 {
309         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
310         struct mlx5_flow_table_attr ft_attr = {};
311         struct mlx5_core_dev *dev = esw->dev;
312         struct mlx5_flow_namespace *root_ns;
313         struct mlx5_flow_table *fdb;
314         struct mlx5_flow_group *g;
315         void *match_criteria;
316         int table_size;
317         u32 *flow_group_in;
318         u8 *dmac;
319         int err = 0;
320
321         esw_debug(dev, "Create FDB log_max_size(%d)\n",
322                   MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
323
324         root_ns = mlx5_get_fdb_sub_ns(dev, 0);
325         if (!root_ns) {
326                 esw_warn(dev, "Failed to get FDB flow namespace\n");
327                 return -EOPNOTSUPP;
328         }
329
330         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
331         if (!flow_group_in)
332                 return -ENOMEM;
333
334         table_size = BIT(MLX5_CAP_ESW_FLOWTABLE_FDB(dev, log_max_ft_size));
335         ft_attr.max_fte = table_size;
336         ft_attr.prio = LEGACY_FDB_PRIO;
337         fdb = mlx5_create_flow_table(root_ns, &ft_attr);
338         if (IS_ERR(fdb)) {
339                 err = PTR_ERR(fdb);
340                 esw_warn(dev, "Failed to create FDB Table err %d\n", err);
341                 goto out;
342         }
343         esw->fdb_table.legacy.fdb = fdb;
344
345         /* Addresses group : Full match unicast/multicast addresses */
346         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
347                  MLX5_MATCH_OUTER_HEADERS);
348         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
349         dmac = MLX5_ADDR_OF(fte_match_param, match_criteria, outer_headers.dmac_47_16);
350         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
351         /* Preserve 2 entries for allmulti and promisc rules*/
352         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 3);
353         eth_broadcast_addr(dmac);
354         g = mlx5_create_flow_group(fdb, flow_group_in);
355         if (IS_ERR(g)) {
356                 err = PTR_ERR(g);
357                 esw_warn(dev, "Failed to create flow group err(%d)\n", err);
358                 goto out;
359         }
360         esw->fdb_table.legacy.addr_grp = g;
361
362         /* Allmulti group : One rule that forwards any mcast traffic */
363         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
364                  MLX5_MATCH_OUTER_HEADERS);
365         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, table_size - 2);
366         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 2);
367         eth_zero_addr(dmac);
368         dmac[0] = 0x01;
369         g = mlx5_create_flow_group(fdb, flow_group_in);
370         if (IS_ERR(g)) {
371                 err = PTR_ERR(g);
372                 esw_warn(dev, "Failed to create allmulti flow group err(%d)\n", err);
373                 goto out;
374         }
375         esw->fdb_table.legacy.allmulti_grp = g;
376
377         /* Promiscuous group :
378          * One rule that forward all unmatched traffic from previous groups
379          */
380         eth_zero_addr(dmac);
381         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable,
382                  MLX5_MATCH_MISC_PARAMETERS);
383         MLX5_SET_TO_ONES(fte_match_param, match_criteria, misc_parameters.source_port);
384         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, table_size - 1);
385         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, table_size - 1);
386         g = mlx5_create_flow_group(fdb, flow_group_in);
387         if (IS_ERR(g)) {
388                 err = PTR_ERR(g);
389                 esw_warn(dev, "Failed to create promisc flow group err(%d)\n", err);
390                 goto out;
391         }
392         esw->fdb_table.legacy.promisc_grp = g;
393
394 out:
395         if (err)
396                 esw_destroy_legacy_fdb_table(esw);
397
398         kvfree(flow_group_in);
399         return err;
400 }
401
402 static void esw_destroy_legacy_vepa_table(struct mlx5_eswitch *esw)
403 {
404         esw_debug(esw->dev, "Destroy VEPA Table\n");
405         if (!esw->fdb_table.legacy.vepa_fdb)
406                 return;
407
408         mlx5_destroy_flow_table(esw->fdb_table.legacy.vepa_fdb);
409         esw->fdb_table.legacy.vepa_fdb = NULL;
410 }
411
412 static void esw_destroy_legacy_fdb_table(struct mlx5_eswitch *esw)
413 {
414         esw_debug(esw->dev, "Destroy FDB Table\n");
415         if (!esw->fdb_table.legacy.fdb)
416                 return;
417
418         if (esw->fdb_table.legacy.promisc_grp)
419                 mlx5_destroy_flow_group(esw->fdb_table.legacy.promisc_grp);
420         if (esw->fdb_table.legacy.allmulti_grp)
421                 mlx5_destroy_flow_group(esw->fdb_table.legacy.allmulti_grp);
422         if (esw->fdb_table.legacy.addr_grp)
423                 mlx5_destroy_flow_group(esw->fdb_table.legacy.addr_grp);
424         mlx5_destroy_flow_table(esw->fdb_table.legacy.fdb);
425
426         esw->fdb_table.legacy.fdb = NULL;
427         esw->fdb_table.legacy.addr_grp = NULL;
428         esw->fdb_table.legacy.allmulti_grp = NULL;
429         esw->fdb_table.legacy.promisc_grp = NULL;
430 }
431
432 static int esw_create_legacy_table(struct mlx5_eswitch *esw)
433 {
434         int err;
435
436         memset(&esw->fdb_table.legacy, 0, sizeof(struct legacy_fdb));
437
438         err = esw_create_legacy_vepa_table(esw);
439         if (err)
440                 return err;
441
442         err = esw_create_legacy_fdb_table(esw);
443         if (err)
444                 esw_destroy_legacy_vepa_table(esw);
445
446         return err;
447 }
448
449 static void esw_destroy_legacy_table(struct mlx5_eswitch *esw)
450 {
451         esw_cleanup_vepa_rules(esw);
452         esw_destroy_legacy_fdb_table(esw);
453         esw_destroy_legacy_vepa_table(esw);
454 }
455
456 #define MLX5_LEGACY_SRIOV_VPORT_EVENTS (MLX5_VPORT_UC_ADDR_CHANGE | \
457                                         MLX5_VPORT_MC_ADDR_CHANGE | \
458                                         MLX5_VPORT_PROMISC_CHANGE)
459
460 static int esw_legacy_enable(struct mlx5_eswitch *esw)
461 {
462         struct mlx5_vport *vport;
463         int ret, i;
464
465         ret = esw_create_legacy_table(esw);
466         if (ret)
467                 return ret;
468
469         mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs)
470                 vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
471
472         ret = mlx5_eswitch_enable_pf_vf_vports(esw, MLX5_LEGACY_SRIOV_VPORT_EVENTS);
473         if (ret)
474                 esw_destroy_legacy_table(esw);
475         return ret;
476 }
477
478 static void esw_legacy_disable(struct mlx5_eswitch *esw)
479 {
480         struct esw_mc_addr *mc_promisc;
481
482         mlx5_eswitch_disable_pf_vf_vports(esw);
483
484         mc_promisc = &esw->mc_promisc;
485         if (mc_promisc->uplink_rule)
486                 mlx5_del_flow_rules(mc_promisc->uplink_rule);
487
488         esw_destroy_legacy_table(esw);
489 }
490
491 /* E-Switch vport UC/MC lists management */
492 typedef int (*vport_addr_action)(struct mlx5_eswitch *esw,
493                                  struct vport_addr *vaddr);
494
495 static int esw_add_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
496 {
497         u8 *mac = vaddr->node.addr;
498         u16 vport = vaddr->vport;
499         int err;
500
501         /* Skip mlx5_mpfs_add_mac for eswitch_managers,
502          * it is already done by its netdev in mlx5e_execute_l2_action
503          */
504         if (mlx5_esw_is_manager_vport(esw, vport))
505                 goto fdb_add;
506
507         err = mlx5_mpfs_add_mac(esw->dev, mac);
508         if (err) {
509                 esw_warn(esw->dev,
510                          "Failed to add L2 table mac(%pM) for vport(0x%x), err(%d)\n",
511                          mac, vport, err);
512                 return err;
513         }
514         vaddr->mpfs = true;
515
516 fdb_add:
517         /* SRIOV is enabled: Forward UC MAC to vport */
518         if (esw->fdb_table.legacy.fdb && esw->mode == MLX5_ESWITCH_LEGACY)
519                 vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
520
521         esw_debug(esw->dev, "\tADDED UC MAC: vport[%d] %pM fr(%p)\n",
522                   vport, mac, vaddr->flow_rule);
523
524         return 0;
525 }
526
527 static int esw_del_uc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
528 {
529         u8 *mac = vaddr->node.addr;
530         u16 vport = vaddr->vport;
531         int err = 0;
532
533         /* Skip mlx5_mpfs_del_mac for eswitch managers,
534          * it is already done by its netdev in mlx5e_execute_l2_action
535          */
536         if (!vaddr->mpfs || mlx5_esw_is_manager_vport(esw, vport))
537                 goto fdb_del;
538
539         err = mlx5_mpfs_del_mac(esw->dev, mac);
540         if (err)
541                 esw_warn(esw->dev,
542                          "Failed to del L2 table mac(%pM) for vport(%d), err(%d)\n",
543                          mac, vport, err);
544         vaddr->mpfs = false;
545
546 fdb_del:
547         if (vaddr->flow_rule)
548                 mlx5_del_flow_rules(vaddr->flow_rule);
549         vaddr->flow_rule = NULL;
550
551         return 0;
552 }
553
554 static void update_allmulti_vports(struct mlx5_eswitch *esw,
555                                    struct vport_addr *vaddr,
556                                    struct esw_mc_addr *esw_mc)
557 {
558         u8 *mac = vaddr->node.addr;
559         struct mlx5_vport *vport;
560         u16 i, vport_num;
561
562         mlx5_esw_for_all_vports(esw, i, vport) {
563                 struct hlist_head *vport_hash = vport->mc_list;
564                 struct vport_addr *iter_vaddr =
565                                         l2addr_hash_find(vport_hash,
566                                                          mac,
567                                                          struct vport_addr);
568                 vport_num = vport->vport;
569                 if (IS_ERR_OR_NULL(vport->allmulti_rule) ||
570                     vaddr->vport == vport_num)
571                         continue;
572                 switch (vaddr->action) {
573                 case MLX5_ACTION_ADD:
574                         if (iter_vaddr)
575                                 continue;
576                         iter_vaddr = l2addr_hash_add(vport_hash, mac,
577                                                      struct vport_addr,
578                                                      GFP_KERNEL);
579                         if (!iter_vaddr) {
580                                 esw_warn(esw->dev,
581                                          "ALL-MULTI: Failed to add MAC(%pM) to vport[%d] DB\n",
582                                          mac, vport_num);
583                                 continue;
584                         }
585                         iter_vaddr->vport = vport_num;
586                         iter_vaddr->flow_rule =
587                                         esw_fdb_set_vport_rule(esw,
588                                                                mac,
589                                                                vport_num);
590                         iter_vaddr->mc_promisc = true;
591                         break;
592                 case MLX5_ACTION_DEL:
593                         if (!iter_vaddr)
594                                 continue;
595                         mlx5_del_flow_rules(iter_vaddr->flow_rule);
596                         l2addr_hash_del(iter_vaddr);
597                         break;
598                 }
599         }
600 }
601
602 static int esw_add_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
603 {
604         struct hlist_head *hash = esw->mc_table;
605         struct esw_mc_addr *esw_mc;
606         u8 *mac = vaddr->node.addr;
607         u16 vport = vaddr->vport;
608
609         if (!esw->fdb_table.legacy.fdb)
610                 return 0;
611
612         esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
613         if (esw_mc)
614                 goto add;
615
616         esw_mc = l2addr_hash_add(hash, mac, struct esw_mc_addr, GFP_KERNEL);
617         if (!esw_mc)
618                 return -ENOMEM;
619
620         esw_mc->uplink_rule = /* Forward MC MAC to Uplink */
621                 esw_fdb_set_vport_rule(esw, mac, MLX5_VPORT_UPLINK);
622
623         /* Add this multicast mac to all the mc promiscuous vports */
624         update_allmulti_vports(esw, vaddr, esw_mc);
625
626 add:
627         /* If the multicast mac is added as a result of mc promiscuous vport,
628          * don't increment the multicast ref count
629          */
630         if (!vaddr->mc_promisc)
631                 esw_mc->refcnt++;
632
633         /* Forward MC MAC to vport */
634         vaddr->flow_rule = esw_fdb_set_vport_rule(esw, mac, vport);
635         esw_debug(esw->dev,
636                   "\tADDED MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
637                   vport, mac, vaddr->flow_rule,
638                   esw_mc->refcnt, esw_mc->uplink_rule);
639         return 0;
640 }
641
642 static int esw_del_mc_addr(struct mlx5_eswitch *esw, struct vport_addr *vaddr)
643 {
644         struct hlist_head *hash = esw->mc_table;
645         struct esw_mc_addr *esw_mc;
646         u8 *mac = vaddr->node.addr;
647         u16 vport = vaddr->vport;
648
649         if (!esw->fdb_table.legacy.fdb)
650                 return 0;
651
652         esw_mc = l2addr_hash_find(hash, mac, struct esw_mc_addr);
653         if (!esw_mc) {
654                 esw_warn(esw->dev,
655                          "Failed to find eswitch MC addr for MAC(%pM) vport(%d)",
656                          mac, vport);
657                 return -EINVAL;
658         }
659         esw_debug(esw->dev,
660                   "\tDELETE MC MAC: vport[%d] %pM fr(%p) refcnt(%d) uplinkfr(%p)\n",
661                   vport, mac, vaddr->flow_rule, esw_mc->refcnt,
662                   esw_mc->uplink_rule);
663
664         if (vaddr->flow_rule)
665                 mlx5_del_flow_rules(vaddr->flow_rule);
666         vaddr->flow_rule = NULL;
667
668         /* If the multicast mac is added as a result of mc promiscuous vport,
669          * don't decrement the multicast ref count.
670          */
671         if (vaddr->mc_promisc || (--esw_mc->refcnt > 0))
672                 return 0;
673
674         /* Remove this multicast mac from all the mc promiscuous vports */
675         update_allmulti_vports(esw, vaddr, esw_mc);
676
677         if (esw_mc->uplink_rule)
678                 mlx5_del_flow_rules(esw_mc->uplink_rule);
679
680         l2addr_hash_del(esw_mc);
681         return 0;
682 }
683
684 /* Apply vport UC/MC list to HW l2 table and FDB table */
685 static void esw_apply_vport_addr_list(struct mlx5_eswitch *esw,
686                                       struct mlx5_vport *vport, int list_type)
687 {
688         bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
689         vport_addr_action vport_addr_add;
690         vport_addr_action vport_addr_del;
691         struct vport_addr *addr;
692         struct l2addr_node *node;
693         struct hlist_head *hash;
694         struct hlist_node *tmp;
695         int hi;
696
697         vport_addr_add = is_uc ? esw_add_uc_addr :
698                                  esw_add_mc_addr;
699         vport_addr_del = is_uc ? esw_del_uc_addr :
700                                  esw_del_mc_addr;
701
702         hash = is_uc ? vport->uc_list : vport->mc_list;
703         for_each_l2hash_node(node, tmp, hash, hi) {
704                 addr = container_of(node, struct vport_addr, node);
705                 switch (addr->action) {
706                 case MLX5_ACTION_ADD:
707                         vport_addr_add(esw, addr);
708                         addr->action = MLX5_ACTION_NONE;
709                         break;
710                 case MLX5_ACTION_DEL:
711                         vport_addr_del(esw, addr);
712                         l2addr_hash_del(addr);
713                         break;
714                 }
715         }
716 }
717
718 /* Sync vport UC/MC list from vport context */
719 static void esw_update_vport_addr_list(struct mlx5_eswitch *esw,
720                                        struct mlx5_vport *vport, int list_type)
721 {
722         bool is_uc = list_type == MLX5_NVPRT_LIST_TYPE_UC;
723         u8 (*mac_list)[ETH_ALEN];
724         struct l2addr_node *node;
725         struct vport_addr *addr;
726         struct hlist_head *hash;
727         struct hlist_node *tmp;
728         int size;
729         int err;
730         int hi;
731         int i;
732
733         size = is_uc ? MLX5_MAX_UC_PER_VPORT(esw->dev) :
734                        MLX5_MAX_MC_PER_VPORT(esw->dev);
735
736         mac_list = kcalloc(size, ETH_ALEN, GFP_KERNEL);
737         if (!mac_list)
738                 return;
739
740         hash = is_uc ? vport->uc_list : vport->mc_list;
741
742         for_each_l2hash_node(node, tmp, hash, hi) {
743                 addr = container_of(node, struct vport_addr, node);
744                 addr->action = MLX5_ACTION_DEL;
745         }
746
747         if (!vport->enabled)
748                 goto out;
749
750         err = mlx5_query_nic_vport_mac_list(esw->dev, vport->vport, list_type,
751                                             mac_list, &size);
752         if (err)
753                 goto out;
754         esw_debug(esw->dev, "vport[%d] context update %s list size (%d)\n",
755                   vport->vport, is_uc ? "UC" : "MC", size);
756
757         for (i = 0; i < size; i++) {
758                 if (is_uc && !is_valid_ether_addr(mac_list[i]))
759                         continue;
760
761                 if (!is_uc && !is_multicast_ether_addr(mac_list[i]))
762                         continue;
763
764                 addr = l2addr_hash_find(hash, mac_list[i], struct vport_addr);
765                 if (addr) {
766                         addr->action = MLX5_ACTION_NONE;
767                         /* If this mac was previously added because of allmulti
768                          * promiscuous rx mode, its now converted to be original
769                          * vport mac.
770                          */
771                         if (addr->mc_promisc) {
772                                 struct esw_mc_addr *esw_mc =
773                                         l2addr_hash_find(esw->mc_table,
774                                                          mac_list[i],
775                                                          struct esw_mc_addr);
776                                 if (!esw_mc) {
777                                         esw_warn(esw->dev,
778                                                  "Failed to MAC(%pM) in mcast DB\n",
779                                                  mac_list[i]);
780                                         continue;
781                                 }
782                                 esw_mc->refcnt++;
783                                 addr->mc_promisc = false;
784                         }
785                         continue;
786                 }
787
788                 addr = l2addr_hash_add(hash, mac_list[i], struct vport_addr,
789                                        GFP_KERNEL);
790                 if (!addr) {
791                         esw_warn(esw->dev,
792                                  "Failed to add MAC(%pM) to vport[%d] DB\n",
793                                  mac_list[i], vport->vport);
794                         continue;
795                 }
796                 addr->vport = vport->vport;
797                 addr->action = MLX5_ACTION_ADD;
798         }
799 out:
800         kfree(mac_list);
801 }
802
803 /* Sync vport UC/MC list from vport context
804  * Must be called after esw_update_vport_addr_list
805  */
806 static void esw_update_vport_mc_promisc(struct mlx5_eswitch *esw,
807                                         struct mlx5_vport *vport)
808 {
809         struct l2addr_node *node;
810         struct vport_addr *addr;
811         struct hlist_head *hash;
812         struct hlist_node *tmp;
813         int hi;
814
815         hash = vport->mc_list;
816
817         for_each_l2hash_node(node, tmp, esw->mc_table, hi) {
818                 u8 *mac = node->addr;
819
820                 addr = l2addr_hash_find(hash, mac, struct vport_addr);
821                 if (addr) {
822                         if (addr->action == MLX5_ACTION_DEL)
823                                 addr->action = MLX5_ACTION_NONE;
824                         continue;
825                 }
826                 addr = l2addr_hash_add(hash, mac, struct vport_addr,
827                                        GFP_KERNEL);
828                 if (!addr) {
829                         esw_warn(esw->dev,
830                                  "Failed to add allmulti MAC(%pM) to vport[%d] DB\n",
831                                  mac, vport->vport);
832                         continue;
833                 }
834                 addr->vport = vport->vport;
835                 addr->action = MLX5_ACTION_ADD;
836                 addr->mc_promisc = true;
837         }
838 }
839
840 /* Apply vport rx mode to HW FDB table */
841 static void esw_apply_vport_rx_mode(struct mlx5_eswitch *esw,
842                                     struct mlx5_vport *vport,
843                                     bool promisc, bool mc_promisc)
844 {
845         struct esw_mc_addr *allmulti_addr = &esw->mc_promisc;
846
847         if (IS_ERR_OR_NULL(vport->allmulti_rule) != mc_promisc)
848                 goto promisc;
849
850         if (mc_promisc) {
851                 vport->allmulti_rule =
852                         esw_fdb_set_vport_allmulti_rule(esw, vport->vport);
853                 if (!allmulti_addr->uplink_rule)
854                         allmulti_addr->uplink_rule =
855                                 esw_fdb_set_vport_allmulti_rule(esw,
856                                                                 MLX5_VPORT_UPLINK);
857                 allmulti_addr->refcnt++;
858         } else if (vport->allmulti_rule) {
859                 mlx5_del_flow_rules(vport->allmulti_rule);
860                 vport->allmulti_rule = NULL;
861
862                 if (--allmulti_addr->refcnt > 0)
863                         goto promisc;
864
865                 if (allmulti_addr->uplink_rule)
866                         mlx5_del_flow_rules(allmulti_addr->uplink_rule);
867                 allmulti_addr->uplink_rule = NULL;
868         }
869
870 promisc:
871         if (IS_ERR_OR_NULL(vport->promisc_rule) != promisc)
872                 return;
873
874         if (promisc) {
875                 vport->promisc_rule =
876                         esw_fdb_set_vport_promisc_rule(esw, vport->vport);
877         } else if (vport->promisc_rule) {
878                 mlx5_del_flow_rules(vport->promisc_rule);
879                 vport->promisc_rule = NULL;
880         }
881 }
882
883 /* Sync vport rx mode from vport context */
884 static void esw_update_vport_rx_mode(struct mlx5_eswitch *esw,
885                                      struct mlx5_vport *vport)
886 {
887         int promisc_all = 0;
888         int promisc_uc = 0;
889         int promisc_mc = 0;
890         int err;
891
892         err = mlx5_query_nic_vport_promisc(esw->dev,
893                                            vport->vport,
894                                            &promisc_uc,
895                                            &promisc_mc,
896                                            &promisc_all);
897         if (err)
898                 return;
899         esw_debug(esw->dev, "vport[%d] context update rx mode promisc_all=%d, all_multi=%d\n",
900                   vport->vport, promisc_all, promisc_mc);
901
902         if (!vport->info.trusted || !vport->enabled) {
903                 promisc_uc = 0;
904                 promisc_mc = 0;
905                 promisc_all = 0;
906         }
907
908         esw_apply_vport_rx_mode(esw, vport, promisc_all,
909                                 (promisc_all || promisc_mc));
910 }
911
912 static void esw_vport_change_handle_locked(struct mlx5_vport *vport)
913 {
914         struct mlx5_core_dev *dev = vport->dev;
915         struct mlx5_eswitch *esw = dev->priv.eswitch;
916         u8 mac[ETH_ALEN];
917
918         mlx5_query_nic_vport_mac_address(dev, vport->vport, true, mac);
919         esw_debug(dev, "vport[%d] Context Changed: perm mac: %pM\n",
920                   vport->vport, mac);
921
922         if (vport->enabled_events & MLX5_VPORT_UC_ADDR_CHANGE) {
923                 esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);
924                 esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_UC);
925         }
926
927         if (vport->enabled_events & MLX5_VPORT_MC_ADDR_CHANGE)
928                 esw_update_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);
929
930         if (vport->enabled_events & MLX5_VPORT_PROMISC_CHANGE) {
931                 esw_update_vport_rx_mode(esw, vport);
932                 if (!IS_ERR_OR_NULL(vport->allmulti_rule))
933                         esw_update_vport_mc_promisc(esw, vport);
934         }
935
936         if (vport->enabled_events & (MLX5_VPORT_PROMISC_CHANGE | MLX5_VPORT_MC_ADDR_CHANGE))
937                 esw_apply_vport_addr_list(esw, vport, MLX5_NVPRT_LIST_TYPE_MC);
938
939         esw_debug(esw->dev, "vport[%d] Context Changed: Done\n", vport->vport);
940         if (vport->enabled)
941                 arm_vport_context_events_cmd(dev, vport->vport,
942                                              vport->enabled_events);
943 }
944
945 static void esw_vport_change_handler(struct work_struct *work)
946 {
947         struct mlx5_vport *vport =
948                 container_of(work, struct mlx5_vport, vport_change_handler);
949         struct mlx5_eswitch *esw = vport->dev->priv.eswitch;
950
951         mutex_lock(&esw->state_lock);
952         esw_vport_change_handle_locked(vport);
953         mutex_unlock(&esw->state_lock);
954 }
955
956 int esw_vport_enable_egress_acl(struct mlx5_eswitch *esw,
957                                 struct mlx5_vport *vport)
958 {
959         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
960         struct mlx5_flow_group *vlan_grp = NULL;
961         struct mlx5_flow_group *drop_grp = NULL;
962         struct mlx5_core_dev *dev = esw->dev;
963         struct mlx5_flow_namespace *root_ns;
964         struct mlx5_flow_table *acl;
965         void *match_criteria;
966         u32 *flow_group_in;
967         /* The egress acl table contains 2 rules:
968          * 1)Allow traffic with vlan_tag=vst_vlan_id
969          * 2)Drop all other traffic.
970          */
971         int table_size = 2;
972         int err = 0;
973
974         if (!MLX5_CAP_ESW_EGRESS_ACL(dev, ft_support))
975                 return -EOPNOTSUPP;
976
977         if (!IS_ERR_OR_NULL(vport->egress.acl))
978                 return 0;
979
980         esw_debug(dev, "Create vport[%d] egress ACL log_max_size(%d)\n",
981                   vport->vport, MLX5_CAP_ESW_EGRESS_ACL(dev, log_max_ft_size));
982
983         root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_EGRESS,
984                         mlx5_eswitch_vport_num_to_index(esw, vport->vport));
985         if (!root_ns) {
986                 esw_warn(dev, "Failed to get E-Switch egress flow namespace for vport (%d)\n", vport->vport);
987                 return -EOPNOTSUPP;
988         }
989
990         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
991         if (!flow_group_in)
992                 return -ENOMEM;
993
994         acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
995         if (IS_ERR(acl)) {
996                 err = PTR_ERR(acl);
997                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress flow Table, err(%d)\n",
998                          vport->vport, err);
999                 goto out;
1000         }
1001
1002         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1003         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1004         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
1005         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.first_vid);
1006         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1007         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
1008
1009         vlan_grp = mlx5_create_flow_group(acl, flow_group_in);
1010         if (IS_ERR(vlan_grp)) {
1011                 err = PTR_ERR(vlan_grp);
1012                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress allowed vlans flow group, err(%d)\n",
1013                          vport->vport, err);
1014                 goto out;
1015         }
1016
1017         memset(flow_group_in, 0, inlen);
1018         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
1019         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
1020         drop_grp = mlx5_create_flow_group(acl, flow_group_in);
1021         if (IS_ERR(drop_grp)) {
1022                 err = PTR_ERR(drop_grp);
1023                 esw_warn(dev, "Failed to create E-Switch vport[%d] egress drop flow group, err(%d)\n",
1024                          vport->vport, err);
1025                 goto out;
1026         }
1027
1028         vport->egress.acl = acl;
1029         vport->egress.drop_grp = drop_grp;
1030         vport->egress.allowed_vlans_grp = vlan_grp;
1031 out:
1032         kvfree(flow_group_in);
1033         if (err && !IS_ERR_OR_NULL(vlan_grp))
1034                 mlx5_destroy_flow_group(vlan_grp);
1035         if (err && !IS_ERR_OR_NULL(acl))
1036                 mlx5_destroy_flow_table(acl);
1037         return err;
1038 }
1039
1040 void esw_vport_cleanup_egress_rules(struct mlx5_eswitch *esw,
1041                                     struct mlx5_vport *vport)
1042 {
1043         if (!IS_ERR_OR_NULL(vport->egress.allowed_vlan)) {
1044                 mlx5_del_flow_rules(vport->egress.allowed_vlan);
1045                 vport->egress.allowed_vlan = NULL;
1046         }
1047
1048         if (!IS_ERR_OR_NULL(vport->egress.legacy.drop_rule)) {
1049                 mlx5_del_flow_rules(vport->egress.legacy.drop_rule);
1050                 vport->egress.legacy.drop_rule = NULL;
1051         }
1052 }
1053
1054 void esw_vport_disable_egress_acl(struct mlx5_eswitch *esw,
1055                                   struct mlx5_vport *vport)
1056 {
1057         if (IS_ERR_OR_NULL(vport->egress.acl))
1058                 return;
1059
1060         esw_debug(esw->dev, "Destroy vport[%d] E-Switch egress ACL\n", vport->vport);
1061
1062         esw_vport_cleanup_egress_rules(esw, vport);
1063         mlx5_destroy_flow_group(vport->egress.allowed_vlans_grp);
1064         mlx5_destroy_flow_group(vport->egress.drop_grp);
1065         mlx5_destroy_flow_table(vport->egress.acl);
1066         vport->egress.allowed_vlans_grp = NULL;
1067         vport->egress.drop_grp = NULL;
1068         vport->egress.acl = NULL;
1069 }
1070
1071 static int
1072 esw_vport_create_legacy_ingress_acl_groups(struct mlx5_eswitch *esw,
1073                                            struct mlx5_vport *vport)
1074 {
1075         int inlen = MLX5_ST_SZ_BYTES(create_flow_group_in);
1076         struct mlx5_core_dev *dev = esw->dev;
1077         struct mlx5_flow_group *g;
1078         void *match_criteria;
1079         u32 *flow_group_in;
1080         int err;
1081
1082         flow_group_in = kvzalloc(inlen, GFP_KERNEL);
1083         if (!flow_group_in)
1084                 return -ENOMEM;
1085
1086         match_criteria = MLX5_ADDR_OF(create_flow_group_in, flow_group_in, match_criteria);
1087
1088         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1089         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
1090         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_47_16);
1091         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_15_0);
1092         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 0);
1093         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 0);
1094
1095         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1096         if (IS_ERR(g)) {
1097                 err = PTR_ERR(g);
1098                 esw_warn(dev, "vport[%d] ingress create untagged spoofchk flow group, err(%d)\n",
1099                          vport->vport, err);
1100                 goto spoof_err;
1101         }
1102         vport->ingress.legacy.allow_untagged_spoofchk_grp = g;
1103
1104         memset(flow_group_in, 0, inlen);
1105         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1106         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.cvlan_tag);
1107         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 1);
1108         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 1);
1109
1110         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1111         if (IS_ERR(g)) {
1112                 err = PTR_ERR(g);
1113                 esw_warn(dev, "vport[%d] ingress create untagged flow group, err(%d)\n",
1114                          vport->vport, err);
1115                 goto untagged_err;
1116         }
1117         vport->ingress.legacy.allow_untagged_only_grp = g;
1118
1119         memset(flow_group_in, 0, inlen);
1120         MLX5_SET(create_flow_group_in, flow_group_in, match_criteria_enable, MLX5_MATCH_OUTER_HEADERS);
1121         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_47_16);
1122         MLX5_SET_TO_ONES(fte_match_param, match_criteria, outer_headers.smac_15_0);
1123         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 2);
1124         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 2);
1125
1126         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1127         if (IS_ERR(g)) {
1128                 err = PTR_ERR(g);
1129                 esw_warn(dev, "vport[%d] ingress create spoofchk flow group, err(%d)\n",
1130                          vport->vport, err);
1131                 goto allow_spoof_err;
1132         }
1133         vport->ingress.legacy.allow_spoofchk_only_grp = g;
1134
1135         memset(flow_group_in, 0, inlen);
1136         MLX5_SET(create_flow_group_in, flow_group_in, start_flow_index, 3);
1137         MLX5_SET(create_flow_group_in, flow_group_in, end_flow_index, 3);
1138
1139         g = mlx5_create_flow_group(vport->ingress.acl, flow_group_in);
1140         if (IS_ERR(g)) {
1141                 err = PTR_ERR(g);
1142                 esw_warn(dev, "vport[%d] ingress create drop flow group, err(%d)\n",
1143                          vport->vport, err);
1144                 goto drop_err;
1145         }
1146         vport->ingress.legacy.drop_grp = g;
1147         kvfree(flow_group_in);
1148         return 0;
1149
1150 drop_err:
1151         if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_spoofchk_only_grp)) {
1152                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp);
1153                 vport->ingress.legacy.allow_spoofchk_only_grp = NULL;
1154         }
1155 allow_spoof_err:
1156         if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_only_grp)) {
1157                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp);
1158                 vport->ingress.legacy.allow_untagged_only_grp = NULL;
1159         }
1160 untagged_err:
1161         if (!IS_ERR_OR_NULL(vport->ingress.legacy.allow_untagged_spoofchk_grp)) {
1162                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp);
1163                 vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL;
1164         }
1165 spoof_err:
1166         kvfree(flow_group_in);
1167         return err;
1168 }
1169
1170 int esw_vport_create_ingress_acl_table(struct mlx5_eswitch *esw,
1171                                        struct mlx5_vport *vport, int table_size)
1172 {
1173         struct mlx5_core_dev *dev = esw->dev;
1174         struct mlx5_flow_namespace *root_ns;
1175         struct mlx5_flow_table *acl;
1176         int vport_index;
1177         int err;
1178
1179         if (!MLX5_CAP_ESW_INGRESS_ACL(dev, ft_support))
1180                 return -EOPNOTSUPP;
1181
1182         esw_debug(dev, "Create vport[%d] ingress ACL log_max_size(%d)\n",
1183                   vport->vport, MLX5_CAP_ESW_INGRESS_ACL(dev, log_max_ft_size));
1184
1185         vport_index = mlx5_eswitch_vport_num_to_index(esw, vport->vport);
1186         root_ns = mlx5_get_flow_vport_acl_namespace(dev, MLX5_FLOW_NAMESPACE_ESW_INGRESS,
1187                                                     vport_index);
1188         if (!root_ns) {
1189                 esw_warn(dev, "Failed to get E-Switch ingress flow namespace for vport (%d)\n",
1190                          vport->vport);
1191                 return -EOPNOTSUPP;
1192         }
1193
1194         acl = mlx5_create_vport_flow_table(root_ns, 0, table_size, 0, vport->vport);
1195         if (IS_ERR(acl)) {
1196                 err = PTR_ERR(acl);
1197                 esw_warn(dev, "vport[%d] ingress create flow Table, err(%d)\n",
1198                          vport->vport, err);
1199                 return err;
1200         }
1201         vport->ingress.acl = acl;
1202         return 0;
1203 }
1204
1205 void esw_vport_destroy_ingress_acl_table(struct mlx5_vport *vport)
1206 {
1207         if (!vport->ingress.acl)
1208                 return;
1209
1210         mlx5_destroy_flow_table(vport->ingress.acl);
1211         vport->ingress.acl = NULL;
1212 }
1213
1214 void esw_vport_cleanup_ingress_rules(struct mlx5_eswitch *esw,
1215                                      struct mlx5_vport *vport)
1216 {
1217         if (vport->ingress.legacy.drop_rule) {
1218                 mlx5_del_flow_rules(vport->ingress.legacy.drop_rule);
1219                 vport->ingress.legacy.drop_rule = NULL;
1220         }
1221
1222         if (vport->ingress.allow_rule) {
1223                 mlx5_del_flow_rules(vport->ingress.allow_rule);
1224                 vport->ingress.allow_rule = NULL;
1225         }
1226 }
1227
1228 static void esw_vport_disable_legacy_ingress_acl(struct mlx5_eswitch *esw,
1229                                                  struct mlx5_vport *vport)
1230 {
1231         if (!vport->ingress.acl)
1232                 return;
1233
1234         esw_debug(esw->dev, "Destroy vport[%d] E-Switch ingress ACL\n", vport->vport);
1235
1236         esw_vport_cleanup_ingress_rules(esw, vport);
1237         if (vport->ingress.legacy.allow_spoofchk_only_grp) {
1238                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_spoofchk_only_grp);
1239                 vport->ingress.legacy.allow_spoofchk_only_grp = NULL;
1240         }
1241         if (vport->ingress.legacy.allow_untagged_only_grp) {
1242                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_only_grp);
1243                 vport->ingress.legacy.allow_untagged_only_grp = NULL;
1244         }
1245         if (vport->ingress.legacy.allow_untagged_spoofchk_grp) {
1246                 mlx5_destroy_flow_group(vport->ingress.legacy.allow_untagged_spoofchk_grp);
1247                 vport->ingress.legacy.allow_untagged_spoofchk_grp = NULL;
1248         }
1249         if (vport->ingress.legacy.drop_grp) {
1250                 mlx5_destroy_flow_group(vport->ingress.legacy.drop_grp);
1251                 vport->ingress.legacy.drop_grp = NULL;
1252         }
1253         esw_vport_destroy_ingress_acl_table(vport);
1254 }
1255
1256 static int esw_vport_ingress_config(struct mlx5_eswitch *esw,
1257                                     struct mlx5_vport *vport)
1258 {
1259         struct mlx5_fc *counter = vport->ingress.legacy.drop_counter;
1260         struct mlx5_flow_destination drop_ctr_dst = {0};
1261         struct mlx5_flow_destination *dst = NULL;
1262         struct mlx5_flow_act flow_act = {0};
1263         struct mlx5_flow_spec *spec = NULL;
1264         int dest_num = 0;
1265         int err = 0;
1266         u8 *smac_v;
1267
1268         /* The ingress acl table contains 4 groups
1269          * (2 active rules at the same time -
1270          *      1 allow rule from one of the first 3 groups.
1271          *      1 drop rule from the last group):
1272          * 1)Allow untagged traffic with smac=original mac.
1273          * 2)Allow untagged traffic.
1274          * 3)Allow traffic with smac=original mac.
1275          * 4)Drop all other traffic.
1276          */
1277         int table_size = 4;
1278
1279         esw_vport_cleanup_ingress_rules(esw, vport);
1280
1281         if (!vport->info.vlan && !vport->info.qos && !vport->info.spoofchk) {
1282                 esw_vport_disable_legacy_ingress_acl(esw, vport);
1283                 return 0;
1284         }
1285
1286         if (!vport->ingress.acl) {
1287                 err = esw_vport_create_ingress_acl_table(esw, vport, table_size);
1288                 if (err) {
1289                         esw_warn(esw->dev,
1290                                  "vport[%d] enable ingress acl err (%d)\n",
1291                                  err, vport->vport);
1292                         return err;
1293                 }
1294
1295                 err = esw_vport_create_legacy_ingress_acl_groups(esw, vport);
1296                 if (err)
1297                         goto out;
1298         }
1299
1300         esw_debug(esw->dev,
1301                   "vport[%d] configure ingress rules, vlan(%d) qos(%d)\n",
1302                   vport->vport, vport->info.vlan, vport->info.qos);
1303
1304         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1305         if (!spec) {
1306                 err = -ENOMEM;
1307                 goto out;
1308         }
1309
1310         if (vport->info.vlan || vport->info.qos)
1311                 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1312
1313         if (vport->info.spoofchk) {
1314                 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_47_16);
1315                 MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.smac_15_0);
1316                 smac_v = MLX5_ADDR_OF(fte_match_param,
1317                                       spec->match_value,
1318                                       outer_headers.smac_47_16);
1319                 ether_addr_copy(smac_v, vport->info.mac);
1320         }
1321
1322         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1323         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_ALLOW;
1324         vport->ingress.allow_rule =
1325                 mlx5_add_flow_rules(vport->ingress.acl, spec,
1326                                     &flow_act, NULL, 0);
1327         if (IS_ERR(vport->ingress.allow_rule)) {
1328                 err = PTR_ERR(vport->ingress.allow_rule);
1329                 esw_warn(esw->dev,
1330                          "vport[%d] configure ingress allow rule, err(%d)\n",
1331                          vport->vport, err);
1332                 vport->ingress.allow_rule = NULL;
1333                 goto out;
1334         }
1335
1336         memset(spec, 0, sizeof(*spec));
1337         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
1338
1339         /* Attach drop flow counter */
1340         if (counter) {
1341                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
1342                 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1343                 drop_ctr_dst.counter_id = mlx5_fc_id(counter);
1344                 dst = &drop_ctr_dst;
1345                 dest_num++;
1346         }
1347         vport->ingress.legacy.drop_rule =
1348                 mlx5_add_flow_rules(vport->ingress.acl, spec,
1349                                     &flow_act, dst, dest_num);
1350         if (IS_ERR(vport->ingress.legacy.drop_rule)) {
1351                 err = PTR_ERR(vport->ingress.legacy.drop_rule);
1352                 esw_warn(esw->dev,
1353                          "vport[%d] configure ingress drop rule, err(%d)\n",
1354                          vport->vport, err);
1355                 vport->ingress.legacy.drop_rule = NULL;
1356                 goto out;
1357         }
1358         kvfree(spec);
1359         return 0;
1360
1361 out:
1362         esw_vport_disable_legacy_ingress_acl(esw, vport);
1363         kvfree(spec);
1364         return err;
1365 }
1366
1367 int mlx5_esw_create_vport_egress_acl_vlan(struct mlx5_eswitch *esw,
1368                                           struct mlx5_vport *vport,
1369                                           u16 vlan_id, u32 flow_action)
1370 {
1371         struct mlx5_flow_act flow_act = {};
1372         struct mlx5_flow_spec *spec;
1373         int err = 0;
1374
1375         if (vport->egress.allowed_vlan)
1376                 return -EEXIST;
1377
1378         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1379         if (!spec)
1380                 return -ENOMEM;
1381
1382         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.cvlan_tag);
1383         MLX5_SET_TO_ONES(fte_match_param, spec->match_value, outer_headers.cvlan_tag);
1384         MLX5_SET_TO_ONES(fte_match_param, spec->match_criteria, outer_headers.first_vid);
1385         MLX5_SET(fte_match_param, spec->match_value, outer_headers.first_vid, vlan_id);
1386
1387         spec->match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
1388         flow_act.action = flow_action;
1389         vport->egress.allowed_vlan =
1390                 mlx5_add_flow_rules(vport->egress.acl, spec,
1391                                     &flow_act, NULL, 0);
1392         if (IS_ERR(vport->egress.allowed_vlan)) {
1393                 err = PTR_ERR(vport->egress.allowed_vlan);
1394                 esw_warn(esw->dev,
1395                          "vport[%d] configure egress vlan rule failed, err(%d)\n",
1396                          vport->vport, err);
1397                 vport->egress.allowed_vlan = NULL;
1398         }
1399
1400         kvfree(spec);
1401         return err;
1402 }
1403
1404 static int esw_vport_egress_config(struct mlx5_eswitch *esw,
1405                                    struct mlx5_vport *vport)
1406 {
1407         struct mlx5_fc *counter = vport->egress.legacy.drop_counter;
1408         struct mlx5_flow_destination drop_ctr_dst = {0};
1409         struct mlx5_flow_destination *dst = NULL;
1410         struct mlx5_flow_act flow_act = {0};
1411         struct mlx5_flow_spec *spec;
1412         int dest_num = 0;
1413         int err = 0;
1414
1415         esw_vport_cleanup_egress_rules(esw, vport);
1416
1417         if (!vport->info.vlan && !vport->info.qos) {
1418                 esw_vport_disable_egress_acl(esw, vport);
1419                 return 0;
1420         }
1421
1422         err = esw_vport_enable_egress_acl(esw, vport);
1423         if (err) {
1424                 mlx5_core_warn(esw->dev,
1425                                "failed to enable egress acl (%d) on vport[%d]\n",
1426                                err, vport->vport);
1427                 return err;
1428         }
1429
1430         esw_debug(esw->dev,
1431                   "vport[%d] configure egress rules, vlan(%d) qos(%d)\n",
1432                   vport->vport, vport->info.vlan, vport->info.qos);
1433
1434         /* Allowed vlan rule */
1435         err = mlx5_esw_create_vport_egress_acl_vlan(esw, vport, vport->info.vlan,
1436                                                     MLX5_FLOW_CONTEXT_ACTION_ALLOW);
1437         if (err)
1438                 return err;
1439
1440         /* Drop others rule (star rule) */
1441         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
1442         if (!spec)
1443                 goto out;
1444
1445         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_DROP;
1446
1447         /* Attach egress drop flow counter */
1448         if (counter) {
1449                 flow_act.action |= MLX5_FLOW_CONTEXT_ACTION_COUNT;
1450                 drop_ctr_dst.type = MLX5_FLOW_DESTINATION_TYPE_COUNTER;
1451                 drop_ctr_dst.counter_id = mlx5_fc_id(counter);
1452                 dst = &drop_ctr_dst;
1453                 dest_num++;
1454         }
1455         vport->egress.legacy.drop_rule =
1456                 mlx5_add_flow_rules(vport->egress.acl, spec,
1457                                     &flow_act, dst, dest_num);
1458         if (IS_ERR(vport->egress.legacy.drop_rule)) {
1459                 err = PTR_ERR(vport->egress.legacy.drop_rule);
1460                 esw_warn(esw->dev,
1461                          "vport[%d] configure egress drop rule failed, err(%d)\n",
1462                          vport->vport, err);
1463                 vport->egress.legacy.drop_rule = NULL;
1464         }
1465 out:
1466         kvfree(spec);
1467         return err;
1468 }
1469
1470 static bool element_type_supported(struct mlx5_eswitch *esw, int type)
1471 {
1472         const struct mlx5_core_dev *dev = esw->dev;
1473
1474         switch (type) {
1475         case SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR:
1476                 return MLX5_CAP_QOS(dev, esw_element_type) &
1477                        ELEMENT_TYPE_CAP_MASK_TASR;
1478         case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT:
1479                 return MLX5_CAP_QOS(dev, esw_element_type) &
1480                        ELEMENT_TYPE_CAP_MASK_VPORT;
1481         case SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT_TC:
1482                 return MLX5_CAP_QOS(dev, esw_element_type) &
1483                        ELEMENT_TYPE_CAP_MASK_VPORT_TC;
1484         case SCHEDULING_CONTEXT_ELEMENT_TYPE_PARA_VPORT_TC:
1485                 return MLX5_CAP_QOS(dev, esw_element_type) &
1486                        ELEMENT_TYPE_CAP_MASK_PARA_VPORT_TC;
1487         }
1488         return false;
1489 }
1490
1491 /* Vport QoS management */
1492 static void esw_create_tsar(struct mlx5_eswitch *esw)
1493 {
1494         u32 tsar_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
1495         struct mlx5_core_dev *dev = esw->dev;
1496         __be32 *attr;
1497         int err;
1498
1499         if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
1500                 return;
1501
1502         if (!element_type_supported(esw, SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR))
1503                 return;
1504
1505         if (esw->qos.enabled)
1506                 return;
1507
1508         MLX5_SET(scheduling_context, tsar_ctx, element_type,
1509                  SCHEDULING_CONTEXT_ELEMENT_TYPE_TSAR);
1510
1511         attr = MLX5_ADDR_OF(scheduling_context, tsar_ctx, element_attributes);
1512         *attr = cpu_to_be32(TSAR_ELEMENT_TSAR_TYPE_DWRR << 16);
1513
1514         err = mlx5_create_scheduling_element_cmd(dev,
1515                                                  SCHEDULING_HIERARCHY_E_SWITCH,
1516                                                  tsar_ctx,
1517                                                  &esw->qos.root_tsar_id);
1518         if (err) {
1519                 esw_warn(esw->dev, "E-Switch create TSAR failed (%d)\n", err);
1520                 return;
1521         }
1522
1523         esw->qos.enabled = true;
1524 }
1525
1526 static void esw_destroy_tsar(struct mlx5_eswitch *esw)
1527 {
1528         int err;
1529
1530         if (!esw->qos.enabled)
1531                 return;
1532
1533         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
1534                                                   SCHEDULING_HIERARCHY_E_SWITCH,
1535                                                   esw->qos.root_tsar_id);
1536         if (err)
1537                 esw_warn(esw->dev, "E-Switch destroy TSAR failed (%d)\n", err);
1538
1539         esw->qos.enabled = false;
1540 }
1541
1542 static int esw_vport_enable_qos(struct mlx5_eswitch *esw,
1543                                 struct mlx5_vport *vport,
1544                                 u32 initial_max_rate, u32 initial_bw_share)
1545 {
1546         u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
1547         struct mlx5_core_dev *dev = esw->dev;
1548         void *vport_elem;
1549         int err = 0;
1550
1551         if (!esw->qos.enabled || !MLX5_CAP_GEN(dev, qos) ||
1552             !MLX5_CAP_QOS(dev, esw_scheduling))
1553                 return 0;
1554
1555         if (vport->qos.enabled)
1556                 return -EEXIST;
1557
1558         MLX5_SET(scheduling_context, sched_ctx, element_type,
1559                  SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
1560         vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx,
1561                                   element_attributes);
1562         MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
1563         MLX5_SET(scheduling_context, sched_ctx, parent_element_id,
1564                  esw->qos.root_tsar_id);
1565         MLX5_SET(scheduling_context, sched_ctx, max_average_bw,
1566                  initial_max_rate);
1567         MLX5_SET(scheduling_context, sched_ctx, bw_share, initial_bw_share);
1568
1569         err = mlx5_create_scheduling_element_cmd(dev,
1570                                                  SCHEDULING_HIERARCHY_E_SWITCH,
1571                                                  sched_ctx,
1572                                                  &vport->qos.esw_tsar_ix);
1573         if (err) {
1574                 esw_warn(esw->dev, "E-Switch create TSAR vport element failed (vport=%d,err=%d)\n",
1575                          vport->vport, err);
1576                 return err;
1577         }
1578
1579         vport->qos.enabled = true;
1580         return 0;
1581 }
1582
1583 static void esw_vport_disable_qos(struct mlx5_eswitch *esw,
1584                                   struct mlx5_vport *vport)
1585 {
1586         int err;
1587
1588         if (!vport->qos.enabled)
1589                 return;
1590
1591         err = mlx5_destroy_scheduling_element_cmd(esw->dev,
1592                                                   SCHEDULING_HIERARCHY_E_SWITCH,
1593                                                   vport->qos.esw_tsar_ix);
1594         if (err)
1595                 esw_warn(esw->dev, "E-Switch destroy TSAR vport element failed (vport=%d,err=%d)\n",
1596                          vport->vport, err);
1597
1598         vport->qos.enabled = false;
1599 }
1600
1601 static int esw_vport_qos_config(struct mlx5_eswitch *esw,
1602                                 struct mlx5_vport *vport,
1603                                 u32 max_rate, u32 bw_share)
1604 {
1605         u32 sched_ctx[MLX5_ST_SZ_DW(scheduling_context)] = {0};
1606         struct mlx5_core_dev *dev = esw->dev;
1607         void *vport_elem;
1608         u32 bitmask = 0;
1609         int err = 0;
1610
1611         if (!MLX5_CAP_GEN(dev, qos) || !MLX5_CAP_QOS(dev, esw_scheduling))
1612                 return -EOPNOTSUPP;
1613
1614         if (!vport->qos.enabled)
1615                 return -EIO;
1616
1617         MLX5_SET(scheduling_context, sched_ctx, element_type,
1618                  SCHEDULING_CONTEXT_ELEMENT_TYPE_VPORT);
1619         vport_elem = MLX5_ADDR_OF(scheduling_context, sched_ctx,
1620                                   element_attributes);
1621         MLX5_SET(vport_element, vport_elem, vport_number, vport->vport);
1622         MLX5_SET(scheduling_context, sched_ctx, parent_element_id,
1623                  esw->qos.root_tsar_id);
1624         MLX5_SET(scheduling_context, sched_ctx, max_average_bw,
1625                  max_rate);
1626         MLX5_SET(scheduling_context, sched_ctx, bw_share, bw_share);
1627         bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW;
1628         bitmask |= MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_BW_SHARE;
1629
1630         err = mlx5_modify_scheduling_element_cmd(dev,
1631                                                  SCHEDULING_HIERARCHY_E_SWITCH,
1632                                                  sched_ctx,
1633                                                  vport->qos.esw_tsar_ix,
1634                                                  bitmask);
1635         if (err) {
1636                 esw_warn(esw->dev, "E-Switch modify TSAR vport element failed (vport=%d,err=%d)\n",
1637                          vport->vport, err);
1638                 return err;
1639         }
1640
1641         return 0;
1642 }
1643
1644 int mlx5_esw_modify_vport_rate(struct mlx5_eswitch *esw, u16 vport_num,
1645                                u32 rate_mbps)
1646 {
1647         u32 ctx[MLX5_ST_SZ_DW(scheduling_context)] = {};
1648         struct mlx5_vport *vport;
1649
1650         vport = mlx5_eswitch_get_vport(esw, vport_num);
1651         MLX5_SET(scheduling_context, ctx, max_average_bw, rate_mbps);
1652
1653         return mlx5_modify_scheduling_element_cmd(esw->dev,
1654                                                   SCHEDULING_HIERARCHY_E_SWITCH,
1655                                                   ctx,
1656                                                   vport->qos.esw_tsar_ix,
1657                                                   MODIFY_SCHEDULING_ELEMENT_IN_MODIFY_BITMASK_MAX_AVERAGE_BW);
1658 }
1659
1660 static void node_guid_gen_from_mac(u64 *node_guid, u8 mac[ETH_ALEN])
1661 {
1662         ((u8 *)node_guid)[7] = mac[0];
1663         ((u8 *)node_guid)[6] = mac[1];
1664         ((u8 *)node_guid)[5] = mac[2];
1665         ((u8 *)node_guid)[4] = 0xff;
1666         ((u8 *)node_guid)[3] = 0xfe;
1667         ((u8 *)node_guid)[2] = mac[3];
1668         ((u8 *)node_guid)[1] = mac[4];
1669         ((u8 *)node_guid)[0] = mac[5];
1670 }
1671
1672 static void esw_apply_vport_conf(struct mlx5_eswitch *esw,
1673                                  struct mlx5_vport *vport)
1674 {
1675         u16 vport_num = vport->vport;
1676         int flags;
1677
1678         if (mlx5_esw_is_manager_vport(esw, vport_num))
1679                 return;
1680
1681         mlx5_modify_vport_admin_state(esw->dev,
1682                                       MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
1683                                       vport_num, 1,
1684                                       vport->info.link_state);
1685
1686         /* Host PF has its own mac/guid. */
1687         if (vport_num) {
1688                 mlx5_modify_nic_vport_mac_address(esw->dev, vport_num,
1689                                                   vport->info.mac);
1690                 mlx5_modify_nic_vport_node_guid(esw->dev, vport_num,
1691                                                 vport->info.node_guid);
1692         }
1693
1694         flags = (vport->info.vlan || vport->info.qos) ?
1695                 SET_VLAN_STRIP | SET_VLAN_INSERT : 0;
1696         modify_esw_vport_cvlan(esw->dev, vport_num, vport->info.vlan, vport->info.qos,
1697                                flags);
1698 }
1699
1700 static int esw_vport_create_legacy_acl_tables(struct mlx5_eswitch *esw,
1701                                               struct mlx5_vport *vport)
1702 {
1703         int ret;
1704
1705         /* Only non manager vports need ACL in legacy mode */
1706         if (mlx5_esw_is_manager_vport(esw, vport->vport))
1707                 return 0;
1708
1709         if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
1710             MLX5_CAP_ESW_INGRESS_ACL(esw->dev, flow_counter)) {
1711                 vport->ingress.legacy.drop_counter = mlx5_fc_create(esw->dev, false);
1712                 if (IS_ERR(vport->ingress.legacy.drop_counter)) {
1713                         esw_warn(esw->dev,
1714                                  "vport[%d] configure ingress drop rule counter failed\n",
1715                                  vport->vport);
1716                         vport->ingress.legacy.drop_counter = NULL;
1717                 }
1718         }
1719
1720         ret = esw_vport_ingress_config(esw, vport);
1721         if (ret)
1722                 goto ingress_err;
1723
1724         if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
1725             MLX5_CAP_ESW_EGRESS_ACL(esw->dev, flow_counter)) {
1726                 vport->egress.legacy.drop_counter = mlx5_fc_create(esw->dev, false);
1727                 if (IS_ERR(vport->egress.legacy.drop_counter)) {
1728                         esw_warn(esw->dev,
1729                                  "vport[%d] configure egress drop rule counter failed\n",
1730                                  vport->vport);
1731                         vport->egress.legacy.drop_counter = NULL;
1732                 }
1733         }
1734
1735         ret = esw_vport_egress_config(esw, vport);
1736         if (ret)
1737                 goto egress_err;
1738
1739         return 0;
1740
1741 egress_err:
1742         esw_vport_disable_legacy_ingress_acl(esw, vport);
1743         mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter);
1744         vport->egress.legacy.drop_counter = NULL;
1745
1746 ingress_err:
1747         mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter);
1748         vport->ingress.legacy.drop_counter = NULL;
1749         return ret;
1750 }
1751
1752 static int esw_vport_setup_acl(struct mlx5_eswitch *esw,
1753                                struct mlx5_vport *vport)
1754 {
1755         if (esw->mode == MLX5_ESWITCH_LEGACY)
1756                 return esw_vport_create_legacy_acl_tables(esw, vport);
1757         else
1758                 return esw_vport_create_offloads_acl_tables(esw, vport);
1759 }
1760
1761 static void esw_vport_destroy_legacy_acl_tables(struct mlx5_eswitch *esw,
1762                                                 struct mlx5_vport *vport)
1763
1764 {
1765         if (mlx5_esw_is_manager_vport(esw, vport->vport))
1766                 return;
1767
1768         esw_vport_disable_egress_acl(esw, vport);
1769         mlx5_fc_destroy(esw->dev, vport->egress.legacy.drop_counter);
1770         vport->egress.legacy.drop_counter = NULL;
1771
1772         esw_vport_disable_legacy_ingress_acl(esw, vport);
1773         mlx5_fc_destroy(esw->dev, vport->ingress.legacy.drop_counter);
1774         vport->ingress.legacy.drop_counter = NULL;
1775 }
1776
1777 static void esw_vport_cleanup_acl(struct mlx5_eswitch *esw,
1778                                   struct mlx5_vport *vport)
1779 {
1780         if (esw->mode == MLX5_ESWITCH_LEGACY)
1781                 esw_vport_destroy_legacy_acl_tables(esw, vport);
1782         else
1783                 esw_vport_destroy_offloads_acl_tables(esw, vport);
1784 }
1785
1786 static int esw_enable_vport(struct mlx5_eswitch *esw, struct mlx5_vport *vport,
1787                             enum mlx5_eswitch_vport_event enabled_events)
1788 {
1789         u16 vport_num = vport->vport;
1790         int ret;
1791
1792         mutex_lock(&esw->state_lock);
1793         WARN_ON(vport->enabled);
1794
1795         esw_debug(esw->dev, "Enabling VPORT(%d)\n", vport_num);
1796
1797         /* Restore old vport configuration */
1798         esw_apply_vport_conf(esw, vport);
1799
1800         ret = esw_vport_setup_acl(esw, vport);
1801         if (ret)
1802                 goto done;
1803
1804         /* Attach vport to the eswitch rate limiter */
1805         if (esw_vport_enable_qos(esw, vport, vport->info.max_rate,
1806                                  vport->qos.bw_share))
1807                 esw_warn(esw->dev, "Failed to attach vport %d to eswitch rate limiter", vport_num);
1808
1809         /* Sync with current vport context */
1810         vport->enabled_events = enabled_events;
1811         vport->enabled = true;
1812
1813         /* Esw manager is trusted by default. Host PF (vport 0) is trusted as well
1814          * in smartNIC as it's a vport group manager.
1815          */
1816         if (mlx5_esw_is_manager_vport(esw, vport_num) ||
1817             (!vport_num && mlx5_core_is_ecpf(esw->dev)))
1818                 vport->info.trusted = true;
1819
1820         esw_vport_change_handle_locked(vport);
1821
1822         esw->enabled_vports++;
1823         esw_debug(esw->dev, "Enabled VPORT(%d)\n", vport_num);
1824 done:
1825         mutex_unlock(&esw->state_lock);
1826         return ret;
1827 }
1828
1829 static void esw_disable_vport(struct mlx5_eswitch *esw,
1830                               struct mlx5_vport *vport)
1831 {
1832         u16 vport_num = vport->vport;
1833
1834         mutex_lock(&esw->state_lock);
1835         if (!vport->enabled)
1836                 goto done;
1837
1838         esw_debug(esw->dev, "Disabling vport(%d)\n", vport_num);
1839         /* Mark this vport as disabled to discard new events */
1840         vport->enabled = false;
1841
1842         /* Disable events from this vport */
1843         arm_vport_context_events_cmd(esw->dev, vport->vport, 0);
1844         /* We don't assume VFs will cleanup after themselves.
1845          * Calling vport change handler while vport is disabled will cleanup
1846          * the vport resources.
1847          */
1848         esw_vport_change_handle_locked(vport);
1849         vport->enabled_events = 0;
1850         esw_vport_disable_qos(esw, vport);
1851
1852         if (!mlx5_esw_is_manager_vport(esw, vport->vport) &&
1853             esw->mode == MLX5_ESWITCH_LEGACY)
1854                 mlx5_modify_vport_admin_state(esw->dev,
1855                                               MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
1856                                               vport_num, 1,
1857                                               MLX5_VPORT_ADMIN_STATE_DOWN);
1858
1859         esw_vport_cleanup_acl(esw, vport);
1860         esw->enabled_vports--;
1861
1862 done:
1863         mutex_unlock(&esw->state_lock);
1864 }
1865
1866 static int eswitch_vport_event(struct notifier_block *nb,
1867                                unsigned long type, void *data)
1868 {
1869         struct mlx5_eswitch *esw = mlx5_nb_cof(nb, struct mlx5_eswitch, nb);
1870         struct mlx5_eqe *eqe = data;
1871         struct mlx5_vport *vport;
1872         u16 vport_num;
1873
1874         vport_num = be16_to_cpu(eqe->data.vport_change.vport_num);
1875         vport = mlx5_eswitch_get_vport(esw, vport_num);
1876         if (!IS_ERR(vport))
1877                 queue_work(esw->work_queue, &vport->vport_change_handler);
1878         return NOTIFY_OK;
1879 }
1880
1881 /**
1882  * mlx5_esw_query_functions - Returns raw output about functions state
1883  * @dev:        Pointer to device to query
1884  *
1885  * mlx5_esw_query_functions() allocates and returns functions changed
1886  * raw output memory pointer from device on success. Otherwise returns ERR_PTR.
1887  * Caller must free the memory using kvfree() when valid pointer is returned.
1888  */
1889 const u32 *mlx5_esw_query_functions(struct mlx5_core_dev *dev)
1890 {
1891         int outlen = MLX5_ST_SZ_BYTES(query_esw_functions_out);
1892         u32 in[MLX5_ST_SZ_DW(query_esw_functions_in)] = {};
1893         u32 *out;
1894         int err;
1895
1896         out = kvzalloc(outlen, GFP_KERNEL);
1897         if (!out)
1898                 return ERR_PTR(-ENOMEM);
1899
1900         MLX5_SET(query_esw_functions_in, in, opcode,
1901                  MLX5_CMD_OP_QUERY_ESW_FUNCTIONS);
1902
1903         err = mlx5_cmd_exec(dev, in, sizeof(in), out, outlen);
1904         if (!err)
1905                 return out;
1906
1907         kvfree(out);
1908         return ERR_PTR(err);
1909 }
1910
1911 static void mlx5_eswitch_event_handlers_register(struct mlx5_eswitch *esw)
1912 {
1913         MLX5_NB_INIT(&esw->nb, eswitch_vport_event, NIC_VPORT_CHANGE);
1914         mlx5_eq_notifier_register(esw->dev, &esw->nb);
1915
1916         if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev)) {
1917                 MLX5_NB_INIT(&esw->esw_funcs.nb, mlx5_esw_funcs_changed_handler,
1918                              ESW_FUNCTIONS_CHANGED);
1919                 mlx5_eq_notifier_register(esw->dev, &esw->esw_funcs.nb);
1920         }
1921 }
1922
1923 static void mlx5_eswitch_event_handlers_unregister(struct mlx5_eswitch *esw)
1924 {
1925         if (esw->mode == MLX5_ESWITCH_OFFLOADS && mlx5_eswitch_is_funcs_handler(esw->dev))
1926                 mlx5_eq_notifier_unregister(esw->dev, &esw->esw_funcs.nb);
1927
1928         mlx5_eq_notifier_unregister(esw->dev, &esw->nb);
1929
1930         flush_workqueue(esw->work_queue);
1931 }
1932
1933 static void mlx5_eswitch_clear_vf_vports_info(struct mlx5_eswitch *esw)
1934 {
1935         struct mlx5_vport *vport;
1936         int i;
1937
1938         mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
1939                 memset(&vport->info, 0, sizeof(vport->info));
1940                 vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
1941         }
1942 }
1943
1944 /* Public E-Switch API */
1945 #define ESW_ALLOWED(esw) ((esw) && MLX5_ESWITCH_MANAGER((esw)->dev))
1946
1947 /* mlx5_eswitch_enable_pf_vf_vports() enables vports of PF, ECPF and VFs
1948  * whichever are present on the eswitch.
1949  */
1950 int
1951 mlx5_eswitch_enable_pf_vf_vports(struct mlx5_eswitch *esw,
1952                                  enum mlx5_eswitch_vport_event enabled_events)
1953 {
1954         struct mlx5_vport *vport;
1955         int num_vfs;
1956         int ret;
1957         int i;
1958
1959         /* Enable PF vport */
1960         vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1961         ret = esw_enable_vport(esw, vport, enabled_events);
1962         if (ret)
1963                 return ret;
1964
1965         /* Enable ECPF vport */
1966         if (mlx5_ecpf_vport_exists(esw->dev)) {
1967                 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1968                 ret = esw_enable_vport(esw, vport, enabled_events);
1969                 if (ret)
1970                         goto ecpf_err;
1971         }
1972
1973         /* Enable VF vports */
1974         mlx5_esw_for_each_vf_vport(esw, i, vport, esw->esw_funcs.num_vfs) {
1975                 ret = esw_enable_vport(esw, vport, enabled_events);
1976                 if (ret)
1977                         goto vf_err;
1978         }
1979         return 0;
1980
1981 vf_err:
1982         num_vfs = i - 1;
1983         mlx5_esw_for_each_vf_vport_reverse(esw, i, vport, num_vfs)
1984                 esw_disable_vport(esw, vport);
1985
1986         if (mlx5_ecpf_vport_exists(esw->dev)) {
1987                 vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_ECPF);
1988                 esw_disable_vport(esw, vport);
1989         }
1990
1991 ecpf_err:
1992         vport = mlx5_eswitch_get_vport(esw, MLX5_VPORT_PF);
1993         esw_disable_vport(esw, vport);
1994         return ret;
1995 }
1996
1997 /* mlx5_eswitch_disable_pf_vf_vports() disables vports of PF, ECPF and VFs
1998  * whichever are previously enabled on the eswitch.
1999  */
2000 void mlx5_eswitch_disable_pf_vf_vports(struct mlx5_eswitch *esw)
2001 {
2002         struct mlx5_vport *vport;
2003         int i;
2004
2005         mlx5_esw_for_all_vports_reverse(esw, i, vport)
2006                 esw_disable_vport(esw, vport);
2007 }
2008
2009 int mlx5_eswitch_enable(struct mlx5_eswitch *esw, int mode)
2010 {
2011         int err;
2012
2013         if (!ESW_ALLOWED(esw) ||
2014             !MLX5_CAP_ESW_FLOWTABLE_FDB(esw->dev, ft_support)) {
2015                 esw_warn(esw->dev, "FDB is not supported, aborting ...\n");
2016                 return -EOPNOTSUPP;
2017         }
2018
2019         if (!MLX5_CAP_ESW_INGRESS_ACL(esw->dev, ft_support))
2020                 esw_warn(esw->dev, "ingress ACL is not supported by FW\n");
2021
2022         if (!MLX5_CAP_ESW_EGRESS_ACL(esw->dev, ft_support))
2023                 esw_warn(esw->dev, "engress ACL is not supported by FW\n");
2024
2025         esw_create_tsar(esw);
2026
2027         esw->mode = mode;
2028
2029         mlx5_lag_update(esw->dev);
2030
2031         if (mode == MLX5_ESWITCH_LEGACY) {
2032                 err = esw_legacy_enable(esw);
2033         } else {
2034                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
2035                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
2036                 err = esw_offloads_enable(esw);
2037         }
2038
2039         if (err)
2040                 goto abort;
2041
2042         mlx5_eswitch_event_handlers_register(esw);
2043
2044         esw_info(esw->dev, "Enable: mode(%s), nvfs(%d), active vports(%d)\n",
2045                  mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
2046                  esw->esw_funcs.num_vfs, esw->enabled_vports);
2047
2048         return 0;
2049
2050 abort:
2051         esw->mode = MLX5_ESWITCH_NONE;
2052
2053         if (mode == MLX5_ESWITCH_OFFLOADS) {
2054                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
2055                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
2056         }
2057
2058         return err;
2059 }
2060
2061 void mlx5_eswitch_disable(struct mlx5_eswitch *esw, bool clear_vf)
2062 {
2063         int old_mode;
2064
2065         if (!ESW_ALLOWED(esw) || esw->mode == MLX5_ESWITCH_NONE)
2066                 return;
2067
2068         esw_info(esw->dev, "Disable: mode(%s), nvfs(%d), active vports(%d)\n",
2069                  esw->mode == MLX5_ESWITCH_LEGACY ? "LEGACY" : "OFFLOADS",
2070                  esw->esw_funcs.num_vfs, esw->enabled_vports);
2071
2072         mlx5_eswitch_event_handlers_unregister(esw);
2073
2074         if (esw->mode == MLX5_ESWITCH_LEGACY)
2075                 esw_legacy_disable(esw);
2076         else if (esw->mode == MLX5_ESWITCH_OFFLOADS)
2077                 esw_offloads_disable(esw);
2078
2079         esw_destroy_tsar(esw);
2080
2081         old_mode = esw->mode;
2082         esw->mode = MLX5_ESWITCH_NONE;
2083
2084         mlx5_lag_update(esw->dev);
2085
2086         if (old_mode == MLX5_ESWITCH_OFFLOADS) {
2087                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_IB);
2088                 mlx5_reload_interface(esw->dev, MLX5_INTERFACE_PROTOCOL_ETH);
2089         }
2090         if (clear_vf)
2091                 mlx5_eswitch_clear_vf_vports_info(esw);
2092 }
2093
2094 int mlx5_eswitch_init(struct mlx5_core_dev *dev)
2095 {
2096         struct mlx5_eswitch *esw;
2097         struct mlx5_vport *vport;
2098         int total_vports;
2099         int err, i;
2100
2101         if (!MLX5_VPORT_MANAGER(dev))
2102                 return 0;
2103
2104         total_vports = mlx5_eswitch_get_total_vports(dev);
2105
2106         esw_info(dev,
2107                  "Total vports %d, per vport: max uc(%d) max mc(%d)\n",
2108                  total_vports,
2109                  MLX5_MAX_UC_PER_VPORT(dev),
2110                  MLX5_MAX_MC_PER_VPORT(dev));
2111
2112         esw = kzalloc(sizeof(*esw), GFP_KERNEL);
2113         if (!esw)
2114                 return -ENOMEM;
2115
2116         esw->dev = dev;
2117         esw->manager_vport = mlx5_eswitch_manager_vport(dev);
2118         esw->first_host_vport = mlx5_eswitch_first_host_vport_num(dev);
2119
2120         esw->work_queue = create_singlethread_workqueue("mlx5_esw_wq");
2121         if (!esw->work_queue) {
2122                 err = -ENOMEM;
2123                 goto abort;
2124         }
2125
2126         esw->vports = kcalloc(total_vports, sizeof(struct mlx5_vport),
2127                               GFP_KERNEL);
2128         if (!esw->vports) {
2129                 err = -ENOMEM;
2130                 goto abort;
2131         }
2132
2133         esw->total_vports = total_vports;
2134
2135         err = esw_offloads_init_reps(esw);
2136         if (err)
2137                 goto abort;
2138
2139         mutex_init(&esw->offloads.encap_tbl_lock);
2140         hash_init(esw->offloads.encap_tbl);
2141         mutex_init(&esw->offloads.mod_hdr.lock);
2142         hash_init(esw->offloads.mod_hdr.hlist);
2143         atomic64_set(&esw->offloads.num_flows, 0);
2144         mutex_init(&esw->state_lock);
2145
2146         mlx5_esw_for_all_vports(esw, i, vport) {
2147                 vport->vport = mlx5_eswitch_index_to_vport_num(esw, i);
2148                 vport->info.link_state = MLX5_VPORT_ADMIN_STATE_AUTO;
2149                 vport->dev = dev;
2150                 INIT_WORK(&vport->vport_change_handler,
2151                           esw_vport_change_handler);
2152         }
2153
2154         esw->enabled_vports = 0;
2155         esw->mode = MLX5_ESWITCH_NONE;
2156         esw->offloads.inline_mode = MLX5_INLINE_MODE_NONE;
2157
2158         dev->priv.eswitch = esw;
2159         return 0;
2160 abort:
2161         if (esw->work_queue)
2162                 destroy_workqueue(esw->work_queue);
2163         esw_offloads_cleanup_reps(esw);
2164         kfree(esw->vports);
2165         kfree(esw);
2166         return err;
2167 }
2168
2169 void mlx5_eswitch_cleanup(struct mlx5_eswitch *esw)
2170 {
2171         if (!esw || !MLX5_VPORT_MANAGER(esw->dev))
2172                 return;
2173
2174         esw_info(esw->dev, "cleanup\n");
2175
2176         esw->dev->priv.eswitch = NULL;
2177         destroy_workqueue(esw->work_queue);
2178         esw_offloads_cleanup_reps(esw);
2179         mutex_destroy(&esw->offloads.mod_hdr.lock);
2180         mutex_destroy(&esw->offloads.encap_tbl_lock);
2181         kfree(esw->vports);
2182         kfree(esw);
2183 }
2184
2185 /* Vport Administration */
2186 int mlx5_eswitch_set_vport_mac(struct mlx5_eswitch *esw,
2187                                u16 vport, u8 mac[ETH_ALEN])
2188 {
2189         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2190         u64 node_guid;
2191         int err = 0;
2192
2193         if (IS_ERR(evport))
2194                 return PTR_ERR(evport);
2195         if (is_multicast_ether_addr(mac))
2196                 return -EINVAL;
2197
2198         mutex_lock(&esw->state_lock);
2199
2200         if (evport->info.spoofchk && !is_valid_ether_addr(mac))
2201                 mlx5_core_warn(esw->dev,
2202                                "Set invalid MAC while spoofchk is on, vport(%d)\n",
2203                                vport);
2204
2205         err = mlx5_modify_nic_vport_mac_address(esw->dev, vport, mac);
2206         if (err) {
2207                 mlx5_core_warn(esw->dev,
2208                                "Failed to mlx5_modify_nic_vport_mac vport(%d) err=(%d)\n",
2209                                vport, err);
2210                 goto unlock;
2211         }
2212
2213         node_guid_gen_from_mac(&node_guid, mac);
2214         err = mlx5_modify_nic_vport_node_guid(esw->dev, vport, node_guid);
2215         if (err)
2216                 mlx5_core_warn(esw->dev,
2217                                "Failed to set vport %d node guid, err = %d. RDMA_CM will not function properly for this VF.\n",
2218                                vport, err);
2219
2220         ether_addr_copy(evport->info.mac, mac);
2221         evport->info.node_guid = node_guid;
2222         if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
2223                 err = esw_vport_ingress_config(esw, evport);
2224
2225 unlock:
2226         mutex_unlock(&esw->state_lock);
2227         return err;
2228 }
2229
2230 int mlx5_eswitch_set_vport_state(struct mlx5_eswitch *esw,
2231                                  u16 vport, int link_state)
2232 {
2233         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2234         int err = 0;
2235
2236         if (!ESW_ALLOWED(esw))
2237                 return -EPERM;
2238         if (IS_ERR(evport))
2239                 return PTR_ERR(evport);
2240
2241         mutex_lock(&esw->state_lock);
2242
2243         err = mlx5_modify_vport_admin_state(esw->dev,
2244                                             MLX5_VPORT_STATE_OP_MOD_ESW_VPORT,
2245                                             vport, 1, link_state);
2246         if (err) {
2247                 mlx5_core_warn(esw->dev,
2248                                "Failed to set vport %d link state, err = %d",
2249                                vport, err);
2250                 goto unlock;
2251         }
2252
2253         evport->info.link_state = link_state;
2254
2255 unlock:
2256         mutex_unlock(&esw->state_lock);
2257         return err;
2258 }
2259
2260 int mlx5_eswitch_get_vport_config(struct mlx5_eswitch *esw,
2261                                   u16 vport, struct ifla_vf_info *ivi)
2262 {
2263         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2264
2265         if (IS_ERR(evport))
2266                 return PTR_ERR(evport);
2267
2268         memset(ivi, 0, sizeof(*ivi));
2269         ivi->vf = vport - 1;
2270
2271         mutex_lock(&esw->state_lock);
2272         ether_addr_copy(ivi->mac, evport->info.mac);
2273         ivi->linkstate = evport->info.link_state;
2274         ivi->vlan = evport->info.vlan;
2275         ivi->qos = evport->info.qos;
2276         ivi->spoofchk = evport->info.spoofchk;
2277         ivi->trusted = evport->info.trusted;
2278         ivi->min_tx_rate = evport->info.min_rate;
2279         ivi->max_tx_rate = evport->info.max_rate;
2280         mutex_unlock(&esw->state_lock);
2281
2282         return 0;
2283 }
2284
2285 int __mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
2286                                   u16 vport, u16 vlan, u8 qos, u8 set_flags)
2287 {
2288         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2289         int err = 0;
2290
2291         if (!ESW_ALLOWED(esw))
2292                 return -EPERM;
2293         if (IS_ERR(evport))
2294                 return PTR_ERR(evport);
2295         if (vlan > 4095 || qos > 7)
2296                 return -EINVAL;
2297
2298         err = modify_esw_vport_cvlan(esw->dev, vport, vlan, qos, set_flags);
2299         if (err)
2300                 return err;
2301
2302         evport->info.vlan = vlan;
2303         evport->info.qos = qos;
2304         if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY) {
2305                 err = esw_vport_ingress_config(esw, evport);
2306                 if (err)
2307                         return err;
2308                 err = esw_vport_egress_config(esw, evport);
2309         }
2310
2311         return err;
2312 }
2313
2314 int mlx5_eswitch_set_vport_vlan(struct mlx5_eswitch *esw,
2315                                 u16 vport, u16 vlan, u8 qos)
2316 {
2317         u8 set_flags = 0;
2318         int err;
2319
2320         if (vlan || qos)
2321                 set_flags = SET_VLAN_STRIP | SET_VLAN_INSERT;
2322
2323         mutex_lock(&esw->state_lock);
2324         err = __mlx5_eswitch_set_vport_vlan(esw, vport, vlan, qos, set_flags);
2325         mutex_unlock(&esw->state_lock);
2326
2327         return err;
2328 }
2329
2330 int mlx5_eswitch_set_vport_spoofchk(struct mlx5_eswitch *esw,
2331                                     u16 vport, bool spoofchk)
2332 {
2333         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2334         bool pschk;
2335         int err = 0;
2336
2337         if (!ESW_ALLOWED(esw))
2338                 return -EPERM;
2339         if (IS_ERR(evport))
2340                 return PTR_ERR(evport);
2341
2342         mutex_lock(&esw->state_lock);
2343         pschk = evport->info.spoofchk;
2344         evport->info.spoofchk = spoofchk;
2345         if (pschk && !is_valid_ether_addr(evport->info.mac))
2346                 mlx5_core_warn(esw->dev,
2347                                "Spoofchk in set while MAC is invalid, vport(%d)\n",
2348                                evport->vport);
2349         if (evport->enabled && esw->mode == MLX5_ESWITCH_LEGACY)
2350                 err = esw_vport_ingress_config(esw, evport);
2351         if (err)
2352                 evport->info.spoofchk = pschk;
2353         mutex_unlock(&esw->state_lock);
2354
2355         return err;
2356 }
2357
2358 static void esw_cleanup_vepa_rules(struct mlx5_eswitch *esw)
2359 {
2360         if (esw->fdb_table.legacy.vepa_uplink_rule)
2361                 mlx5_del_flow_rules(esw->fdb_table.legacy.vepa_uplink_rule);
2362
2363         if (esw->fdb_table.legacy.vepa_star_rule)
2364                 mlx5_del_flow_rules(esw->fdb_table.legacy.vepa_star_rule);
2365
2366         esw->fdb_table.legacy.vepa_uplink_rule = NULL;
2367         esw->fdb_table.legacy.vepa_star_rule = NULL;
2368 }
2369
2370 static int _mlx5_eswitch_set_vepa_locked(struct mlx5_eswitch *esw,
2371                                          u8 setting)
2372 {
2373         struct mlx5_flow_destination dest = {};
2374         struct mlx5_flow_act flow_act = {};
2375         struct mlx5_flow_handle *flow_rule;
2376         struct mlx5_flow_spec *spec;
2377         int err = 0;
2378         void *misc;
2379
2380         if (!setting) {
2381                 esw_cleanup_vepa_rules(esw);
2382                 return 0;
2383         }
2384
2385         if (esw->fdb_table.legacy.vepa_uplink_rule)
2386                 return 0;
2387
2388         spec = kvzalloc(sizeof(*spec), GFP_KERNEL);
2389         if (!spec)
2390                 return -ENOMEM;
2391
2392         /* Uplink rule forward uplink traffic to FDB */
2393         misc = MLX5_ADDR_OF(fte_match_param, spec->match_value, misc_parameters);
2394         MLX5_SET(fte_match_set_misc, misc, source_port, MLX5_VPORT_UPLINK);
2395
2396         misc = MLX5_ADDR_OF(fte_match_param, spec->match_criteria, misc_parameters);
2397         MLX5_SET_TO_ONES(fte_match_set_misc, misc, source_port);
2398
2399         spec->match_criteria_enable = MLX5_MATCH_MISC_PARAMETERS;
2400         dest.type = MLX5_FLOW_DESTINATION_TYPE_FLOW_TABLE;
2401         dest.ft = esw->fdb_table.legacy.fdb;
2402         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2403         flow_rule = mlx5_add_flow_rules(esw->fdb_table.legacy.vepa_fdb, spec,
2404                                         &flow_act, &dest, 1);
2405         if (IS_ERR(flow_rule)) {
2406                 err = PTR_ERR(flow_rule);
2407                 goto out;
2408         } else {
2409                 esw->fdb_table.legacy.vepa_uplink_rule = flow_rule;
2410         }
2411
2412         /* Star rule to forward all traffic to uplink vport */
2413         memset(spec, 0, sizeof(*spec));
2414         memset(&dest, 0, sizeof(dest));
2415         dest.type = MLX5_FLOW_DESTINATION_TYPE_VPORT;
2416         dest.vport.num = MLX5_VPORT_UPLINK;
2417         flow_act.action = MLX5_FLOW_CONTEXT_ACTION_FWD_DEST;
2418         flow_rule = mlx5_add_flow_rules(esw->fdb_table.legacy.vepa_fdb, spec,
2419                                         &flow_act, &dest, 1);
2420         if (IS_ERR(flow_rule)) {
2421                 err = PTR_ERR(flow_rule);
2422                 goto out;
2423         } else {
2424                 esw->fdb_table.legacy.vepa_star_rule = flow_rule;
2425         }
2426
2427 out:
2428         kvfree(spec);
2429         if (err)
2430                 esw_cleanup_vepa_rules(esw);
2431         return err;
2432 }
2433
2434 int mlx5_eswitch_set_vepa(struct mlx5_eswitch *esw, u8 setting)
2435 {
2436         int err = 0;
2437
2438         if (!esw)
2439                 return -EOPNOTSUPP;
2440
2441         if (!ESW_ALLOWED(esw))
2442                 return -EPERM;
2443
2444         mutex_lock(&esw->state_lock);
2445         if (esw->mode != MLX5_ESWITCH_LEGACY) {
2446                 err = -EOPNOTSUPP;
2447                 goto out;
2448         }
2449
2450         err = _mlx5_eswitch_set_vepa_locked(esw, setting);
2451
2452 out:
2453         mutex_unlock(&esw->state_lock);
2454         return err;
2455 }
2456
2457 int mlx5_eswitch_get_vepa(struct mlx5_eswitch *esw, u8 *setting)
2458 {
2459         if (!esw)
2460                 return -EOPNOTSUPP;
2461
2462         if (!ESW_ALLOWED(esw))
2463                 return -EPERM;
2464
2465         if (esw->mode != MLX5_ESWITCH_LEGACY)
2466                 return -EOPNOTSUPP;
2467
2468         *setting = esw->fdb_table.legacy.vepa_uplink_rule ? 1 : 0;
2469         return 0;
2470 }
2471
2472 int mlx5_eswitch_set_vport_trust(struct mlx5_eswitch *esw,
2473                                  u16 vport, bool setting)
2474 {
2475         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2476
2477         if (!ESW_ALLOWED(esw))
2478                 return -EPERM;
2479         if (IS_ERR(evport))
2480                 return PTR_ERR(evport);
2481
2482         mutex_lock(&esw->state_lock);
2483         evport->info.trusted = setting;
2484         if (evport->enabled)
2485                 esw_vport_change_handle_locked(evport);
2486         mutex_unlock(&esw->state_lock);
2487
2488         return 0;
2489 }
2490
2491 static u32 calculate_vports_min_rate_divider(struct mlx5_eswitch *esw)
2492 {
2493         u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
2494         struct mlx5_vport *evport;
2495         u32 max_guarantee = 0;
2496         int i;
2497
2498         mlx5_esw_for_all_vports(esw, i, evport) {
2499                 if (!evport->enabled || evport->info.min_rate < max_guarantee)
2500                         continue;
2501                 max_guarantee = evport->info.min_rate;
2502         }
2503
2504         return max_t(u32, max_guarantee / fw_max_bw_share, 1);
2505 }
2506
2507 static int normalize_vports_min_rate(struct mlx5_eswitch *esw, u32 divider)
2508 {
2509         u32 fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
2510         struct mlx5_vport *evport;
2511         u32 vport_max_rate;
2512         u32 vport_min_rate;
2513         u32 bw_share;
2514         int err;
2515         int i;
2516
2517         mlx5_esw_for_all_vports(esw, i, evport) {
2518                 if (!evport->enabled)
2519                         continue;
2520                 vport_min_rate = evport->info.min_rate;
2521                 vport_max_rate = evport->info.max_rate;
2522                 bw_share = MLX5_MIN_BW_SHARE;
2523
2524                 if (vport_min_rate)
2525                         bw_share = MLX5_RATE_TO_BW_SHARE(vport_min_rate,
2526                                                          divider,
2527                                                          fw_max_bw_share);
2528
2529                 if (bw_share == evport->qos.bw_share)
2530                         continue;
2531
2532                 err = esw_vport_qos_config(esw, evport, vport_max_rate,
2533                                            bw_share);
2534                 if (!err)
2535                         evport->qos.bw_share = bw_share;
2536                 else
2537                         return err;
2538         }
2539
2540         return 0;
2541 }
2542
2543 int mlx5_eswitch_set_vport_rate(struct mlx5_eswitch *esw, u16 vport,
2544                                 u32 max_rate, u32 min_rate)
2545 {
2546         struct mlx5_vport *evport = mlx5_eswitch_get_vport(esw, vport);
2547         u32 fw_max_bw_share;
2548         u32 previous_min_rate;
2549         u32 divider;
2550         bool min_rate_supported;
2551         bool max_rate_supported;
2552         int err = 0;
2553
2554         if (!ESW_ALLOWED(esw))
2555                 return -EPERM;
2556         if (IS_ERR(evport))
2557                 return PTR_ERR(evport);
2558
2559         fw_max_bw_share = MLX5_CAP_QOS(esw->dev, max_tsar_bw_share);
2560         min_rate_supported = MLX5_CAP_QOS(esw->dev, esw_bw_share) &&
2561                                 fw_max_bw_share >= MLX5_MIN_BW_SHARE;
2562         max_rate_supported = MLX5_CAP_QOS(esw->dev, esw_rate_limit);
2563
2564         if ((min_rate && !min_rate_supported) || (max_rate && !max_rate_supported))
2565                 return -EOPNOTSUPP;
2566
2567         mutex_lock(&esw->state_lock);
2568
2569         if (min_rate == evport->info.min_rate)
2570                 goto set_max_rate;
2571
2572         previous_min_rate = evport->info.min_rate;
2573         evport->info.min_rate = min_rate;
2574         divider = calculate_vports_min_rate_divider(esw);
2575         err = normalize_vports_min_rate(esw, divider);
2576         if (err) {
2577                 evport->info.min_rate = previous_min_rate;
2578                 goto unlock;
2579         }
2580
2581 set_max_rate:
2582         if (max_rate == evport->info.max_rate)
2583                 goto unlock;
2584
2585         err = esw_vport_qos_config(esw, evport, max_rate, evport->qos.bw_share);
2586         if (!err)
2587                 evport->info.max_rate = max_rate;
2588
2589 unlock:
2590         mutex_unlock(&esw->state_lock);
2591         return err;
2592 }
2593
2594 static int mlx5_eswitch_query_vport_drop_stats(struct mlx5_core_dev *dev,
2595                                                struct mlx5_vport *vport,
2596                                                struct mlx5_vport_drop_stats *stats)
2597 {
2598         struct mlx5_eswitch *esw = dev->priv.eswitch;
2599         u64 rx_discard_vport_down, tx_discard_vport_down;
2600         u64 bytes = 0;
2601         int err = 0;
2602
2603         if (!vport->enabled || esw->mode != MLX5_ESWITCH_LEGACY)
2604                 return 0;
2605
2606         if (vport->egress.legacy.drop_counter)
2607                 mlx5_fc_query(dev, vport->egress.legacy.drop_counter,
2608                               &stats->rx_dropped, &bytes);
2609
2610         if (vport->ingress.legacy.drop_counter)
2611                 mlx5_fc_query(dev, vport->ingress.legacy.drop_counter,
2612                               &stats->tx_dropped, &bytes);
2613
2614         if (!MLX5_CAP_GEN(dev, receive_discard_vport_down) &&
2615             !MLX5_CAP_GEN(dev, transmit_discard_vport_down))
2616                 return 0;
2617
2618         err = mlx5_query_vport_down_stats(dev, vport->vport, 1,
2619                                           &rx_discard_vport_down,
2620                                           &tx_discard_vport_down);
2621         if (err)
2622                 return err;
2623
2624         if (MLX5_CAP_GEN(dev, receive_discard_vport_down))
2625                 stats->rx_dropped += rx_discard_vport_down;
2626         if (MLX5_CAP_GEN(dev, transmit_discard_vport_down))
2627                 stats->tx_dropped += tx_discard_vport_down;
2628
2629         return 0;
2630 }
2631
2632 int mlx5_eswitch_get_vport_stats(struct mlx5_eswitch *esw,
2633                                  u16 vport_num,
2634                                  struct ifla_vf_stats *vf_stats)
2635 {
2636         struct mlx5_vport *vport = mlx5_eswitch_get_vport(esw, vport_num);
2637         int outlen = MLX5_ST_SZ_BYTES(query_vport_counter_out);
2638         u32 in[MLX5_ST_SZ_DW(query_vport_counter_in)] = {0};
2639         struct mlx5_vport_drop_stats stats = {0};
2640         int err = 0;
2641         u32 *out;
2642
2643         if (IS_ERR(vport))
2644                 return PTR_ERR(vport);
2645
2646         out = kvzalloc(outlen, GFP_KERNEL);
2647         if (!out)
2648                 return -ENOMEM;
2649
2650         MLX5_SET(query_vport_counter_in, in, opcode,
2651                  MLX5_CMD_OP_QUERY_VPORT_COUNTER);
2652         MLX5_SET(query_vport_counter_in, in, op_mod, 0);
2653         MLX5_SET(query_vport_counter_in, in, vport_number, vport->vport);
2654         MLX5_SET(query_vport_counter_in, in, other_vport, 1);
2655
2656         err = mlx5_cmd_exec(esw->dev, in, sizeof(in), out, outlen);
2657         if (err)
2658                 goto free_out;
2659
2660         #define MLX5_GET_CTR(p, x) \
2661                 MLX5_GET64(query_vport_counter_out, p, x)
2662
2663         memset(vf_stats, 0, sizeof(*vf_stats));
2664         vf_stats->rx_packets =
2665                 MLX5_GET_CTR(out, received_eth_unicast.packets) +
2666                 MLX5_GET_CTR(out, received_ib_unicast.packets) +
2667                 MLX5_GET_CTR(out, received_eth_multicast.packets) +
2668                 MLX5_GET_CTR(out, received_ib_multicast.packets) +
2669                 MLX5_GET_CTR(out, received_eth_broadcast.packets);
2670
2671         vf_stats->rx_bytes =
2672                 MLX5_GET_CTR(out, received_eth_unicast.octets) +
2673                 MLX5_GET_CTR(out, received_ib_unicast.octets) +
2674                 MLX5_GET_CTR(out, received_eth_multicast.octets) +
2675                 MLX5_GET_CTR(out, received_ib_multicast.octets) +
2676                 MLX5_GET_CTR(out, received_eth_broadcast.octets);
2677
2678         vf_stats->tx_packets =
2679                 MLX5_GET_CTR(out, transmitted_eth_unicast.packets) +
2680                 MLX5_GET_CTR(out, transmitted_ib_unicast.packets) +
2681                 MLX5_GET_CTR(out, transmitted_eth_multicast.packets) +
2682                 MLX5_GET_CTR(out, transmitted_ib_multicast.packets) +
2683                 MLX5_GET_CTR(out, transmitted_eth_broadcast.packets);
2684
2685         vf_stats->tx_bytes =
2686                 MLX5_GET_CTR(out, transmitted_eth_unicast.octets) +
2687                 MLX5_GET_CTR(out, transmitted_ib_unicast.octets) +
2688                 MLX5_GET_CTR(out, transmitted_eth_multicast.octets) +
2689                 MLX5_GET_CTR(out, transmitted_ib_multicast.octets) +
2690                 MLX5_GET_CTR(out, transmitted_eth_broadcast.octets);
2691
2692         vf_stats->multicast =
2693                 MLX5_GET_CTR(out, received_eth_multicast.packets) +
2694                 MLX5_GET_CTR(out, received_ib_multicast.packets);
2695
2696         vf_stats->broadcast =
2697                 MLX5_GET_CTR(out, received_eth_broadcast.packets);
2698
2699         err = mlx5_eswitch_query_vport_drop_stats(esw->dev, vport, &stats);
2700         if (err)
2701                 goto free_out;
2702         vf_stats->rx_dropped = stats.rx_dropped;
2703         vf_stats->tx_dropped = stats.tx_dropped;
2704
2705 free_out:
2706         kvfree(out);
2707         return err;
2708 }
2709
2710 u8 mlx5_eswitch_mode(struct mlx5_eswitch *esw)
2711 {
2712         return ESW_ALLOWED(esw) ? esw->mode : MLX5_ESWITCH_NONE;
2713 }
2714 EXPORT_SYMBOL_GPL(mlx5_eswitch_mode);
2715
2716 enum devlink_eswitch_encap_mode
2717 mlx5_eswitch_get_encap_mode(const struct mlx5_core_dev *dev)
2718 {
2719         struct mlx5_eswitch *esw;
2720
2721         esw = dev->priv.eswitch;
2722         return ESW_ALLOWED(esw) ? esw->offloads.encap :
2723                 DEVLINK_ESWITCH_ENCAP_MODE_NONE;
2724 }
2725 EXPORT_SYMBOL(mlx5_eswitch_get_encap_mode);
2726
2727 bool mlx5_esw_lag_prereq(struct mlx5_core_dev *dev0, struct mlx5_core_dev *dev1)
2728 {
2729         if ((dev0->priv.eswitch->mode == MLX5_ESWITCH_NONE &&
2730              dev1->priv.eswitch->mode == MLX5_ESWITCH_NONE) ||
2731             (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
2732              dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS))
2733                 return true;
2734
2735         return false;
2736 }
2737
2738 bool mlx5_esw_multipath_prereq(struct mlx5_core_dev *dev0,
2739                                struct mlx5_core_dev *dev1)
2740 {
2741         return (dev0->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS &&
2742                 dev1->priv.eswitch->mode == MLX5_ESWITCH_OFFLOADS);
2743 }
2744
2745 void mlx5_eswitch_update_num_of_vfs(struct mlx5_eswitch *esw, const int num_vfs)
2746 {
2747         const u32 *out;
2748
2749         WARN_ON_ONCE(esw->mode != MLX5_ESWITCH_NONE);
2750
2751         if (!mlx5_core_is_ecpf_esw_manager(esw->dev)) {
2752                 esw->esw_funcs.num_vfs = num_vfs;
2753                 return;
2754         }
2755
2756         out = mlx5_esw_query_functions(esw->dev);
2757         if (IS_ERR(out))
2758                 return;
2759
2760         esw->esw_funcs.num_vfs = MLX5_GET(query_esw_functions_out, out,
2761                                           host_params_context.host_num_of_vfs);
2762         kvfree(out);
2763 }