1290650Shselasky/*-
2290650Shselasky * Copyright (c) 2015 Mellanox Technologies. All rights reserved.
3290650Shselasky *
4290650Shselasky * Redistribution and use in source and binary forms, with or without
5290650Shselasky * modification, are permitted provided that the following conditions
6290650Shselasky * are met:
7290650Shselasky * 1. Redistributions of source code must retain the above copyright
8290650Shselasky *    notice, this list of conditions and the following disclaimer.
9290650Shselasky * 2. Redistributions in binary form must reproduce the above copyright
10290650Shselasky *    notice, this list of conditions and the following disclaimer in the
11290650Shselasky *    documentation and/or other materials provided with the distribution.
12290650Shselasky *
13290650Shselasky * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS `AS IS' AND
14290650Shselasky * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15290650Shselasky * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16290650Shselasky * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
17290650Shselasky * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18290650Shselasky * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19290650Shselasky * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20290650Shselasky * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21290650Shselasky * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22290650Shselasky * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23290650Shselasky * SUCH DAMAGE.
24290650Shselasky *
25290650Shselasky * $FreeBSD: stable/10/sys/dev/mlx5/mlx5_en/mlx5_en_flow_table.c 310244 2016-12-19 09:38:34Z hselasky $
26290650Shselasky */
27290650Shselasky
28290650Shselasky#include "en.h"
29290650Shselasky
30290650Shselasky#include <linux/list.h>
31290650Shselasky#include <dev/mlx5/flow_table.h>
32290650Shselasky
33290650Shselaskyenum {
34290650Shselasky	MLX5E_FULLMATCH = 0,
35290650Shselasky	MLX5E_ALLMULTI = 1,
36290650Shselasky	MLX5E_PROMISC = 2,
37290650Shselasky};
38290650Shselasky
39290650Shselaskyenum {
40290650Shselasky	MLX5E_UC = 0,
41290650Shselasky	MLX5E_MC_IPV4 = 1,
42290650Shselasky	MLX5E_MC_IPV6 = 2,
43290650Shselasky	MLX5E_MC_OTHER = 3,
44290650Shselasky};
45290650Shselasky
46290650Shselaskyenum {
47290650Shselasky	MLX5E_ACTION_NONE = 0,
48290650Shselasky	MLX5E_ACTION_ADD = 1,
49290650Shselasky	MLX5E_ACTION_DEL = 2,
50290650Shselasky};
51290650Shselasky
52290650Shselaskystruct mlx5e_eth_addr_hash_node {
53290650Shselasky	LIST_ENTRY(mlx5e_eth_addr_hash_node) hlist;
54290650Shselasky	u8	action;
55290650Shselasky	struct mlx5e_eth_addr_info ai;
56290650Shselasky};
57290650Shselasky
58290650Shselaskystatic inline int
59290650Shselaskymlx5e_hash_eth_addr(const u8 * addr)
60290650Shselasky{
61290650Shselasky	return (addr[5]);
62290650Shselasky}
63290650Shselasky
64290650Shselaskystatic void
65290650Shselaskymlx5e_add_eth_addr_to_hash(struct mlx5e_eth_addr_hash_head *hash,
66290650Shselasky    const u8 * addr)
67290650Shselasky{
68290650Shselasky	struct mlx5e_eth_addr_hash_node *hn;
69290650Shselasky	int ix = mlx5e_hash_eth_addr(addr);
70290650Shselasky
71290650Shselasky	LIST_FOREACH(hn, &hash[ix], hlist) {
72290650Shselasky		if (bcmp(hn->ai.addr, addr, ETHER_ADDR_LEN) == 0) {
73290650Shselasky			if (hn->action == MLX5E_ACTION_DEL)
74290650Shselasky				hn->action = MLX5E_ACTION_NONE;
75290650Shselasky			return;
76290650Shselasky		}
77290650Shselasky	}
78290650Shselasky
79290650Shselasky	hn = malloc(sizeof(*hn), M_MLX5EN, M_NOWAIT | M_ZERO);
80290650Shselasky	if (hn == NULL)
81290650Shselasky		return;
82290650Shselasky
83290650Shselasky	ether_addr_copy(hn->ai.addr, addr);
84290650Shselasky	hn->action = MLX5E_ACTION_ADD;
85290650Shselasky
86290650Shselasky	LIST_INSERT_HEAD(&hash[ix], hn, hlist);
87290650Shselasky}
88290650Shselasky
89290650Shselaskystatic void
90290650Shselaskymlx5e_del_eth_addr_from_hash(struct mlx5e_eth_addr_hash_node *hn)
91290650Shselasky{
92290650Shselasky	LIST_REMOVE(hn, hlist);
93290650Shselasky	free(hn, M_MLX5EN);
94290650Shselasky}
95290650Shselasky
96290650Shselaskystatic void
97290650Shselaskymlx5e_del_eth_addr_from_flow_table(struct mlx5e_priv *priv,
98290650Shselasky    struct mlx5e_eth_addr_info *ai)
99290650Shselasky{
100290650Shselasky	void *ft = priv->ft.main;
101290650Shselasky
102290650Shselasky	if (ai->tt_vec & (1 << MLX5E_TT_IPV6_TCP))
103290650Shselasky		mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_TCP]);
104290650Shselasky
105290650Shselasky	if (ai->tt_vec & (1 << MLX5E_TT_IPV4_TCP))
106290650Shselasky		mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_TCP]);
107290650Shselasky
108290650Shselasky	if (ai->tt_vec & (1 << MLX5E_TT_IPV6_UDP))
109290650Shselasky		mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6_UDP]);
110290650Shselasky
111290650Shselasky	if (ai->tt_vec & (1 << MLX5E_TT_IPV4_UDP))
112290650Shselasky		mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4_UDP]);
113290650Shselasky
114290650Shselasky	if (ai->tt_vec & (1 << MLX5E_TT_IPV6))
115290650Shselasky		mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV6]);
116290650Shselasky
117290650Shselasky	if (ai->tt_vec & (1 << MLX5E_TT_IPV4))
118290650Shselasky		mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_IPV4]);
119290650Shselasky
120290650Shselasky	if (ai->tt_vec & (1 << MLX5E_TT_ANY))
121290650Shselasky		mlx5_del_flow_table_entry(ft, ai->ft_ix[MLX5E_TT_ANY]);
122290650Shselasky}
123290650Shselasky
124290650Shselaskystatic int
125290650Shselaskymlx5e_get_eth_addr_type(const u8 * addr)
126290650Shselasky{
127290650Shselasky	if (ETHER_IS_MULTICAST(addr) == 0)
128290650Shselasky		return (MLX5E_UC);
129290650Shselasky
130290650Shselasky	if ((addr[0] == 0x01) &&
131290650Shselasky	    (addr[1] == 0x00) &&
132290650Shselasky	    (addr[2] == 0x5e) &&
133290650Shselasky	    !(addr[3] & 0x80))
134290650Shselasky		return (MLX5E_MC_IPV4);
135290650Shselasky
136290650Shselasky	if ((addr[0] == 0x33) &&
137290650Shselasky	    (addr[1] == 0x33))
138290650Shselasky		return (MLX5E_MC_IPV6);
139290650Shselasky
140290650Shselasky	return (MLX5E_MC_OTHER);
141290650Shselasky}
142290650Shselasky
143290650Shselaskystatic	u32
144290650Shselaskymlx5e_get_tt_vec(struct mlx5e_eth_addr_info *ai, int type)
145290650Shselasky{
146290650Shselasky	int eth_addr_type;
147290650Shselasky	u32 ret;
148290650Shselasky
149290650Shselasky	switch (type) {
150290650Shselasky	case MLX5E_FULLMATCH:
151290650Shselasky		eth_addr_type = mlx5e_get_eth_addr_type(ai->addr);
152290650Shselasky		switch (eth_addr_type) {
153290650Shselasky		case MLX5E_UC:
154290650Shselasky			ret =
155290650Shselasky			    (1 << MLX5E_TT_IPV4_TCP) |
156290650Shselasky			    (1 << MLX5E_TT_IPV6_TCP) |
157290650Shselasky			    (1 << MLX5E_TT_IPV4_UDP) |
158290650Shselasky			    (1 << MLX5E_TT_IPV6_UDP) |
159290650Shselasky			    (1 << MLX5E_TT_IPV4) |
160290650Shselasky			    (1 << MLX5E_TT_IPV6) |
161290650Shselasky			    (1 << MLX5E_TT_ANY) |
162290650Shselasky			    0;
163290650Shselasky			break;
164290650Shselasky
165290650Shselasky		case MLX5E_MC_IPV4:
166290650Shselasky			ret =
167290650Shselasky			    (1 << MLX5E_TT_IPV4_UDP) |
168290650Shselasky			    (1 << MLX5E_TT_IPV4) |
169290650Shselasky			    0;
170290650Shselasky			break;
171290650Shselasky
172290650Shselasky		case MLX5E_MC_IPV6:
173290650Shselasky			ret =
174290650Shselasky			    (1 << MLX5E_TT_IPV6_UDP) |
175290650Shselasky			    (1 << MLX5E_TT_IPV6) |
176290650Shselasky			    0;
177290650Shselasky			break;
178290650Shselasky
179290650Shselasky		default:
180290650Shselasky			ret =
181290650Shselasky			    (1 << MLX5E_TT_ANY) |
182290650Shselasky			    0;
183290650Shselasky			break;
184290650Shselasky		}
185290650Shselasky		break;
186290650Shselasky
187290650Shselasky	case MLX5E_ALLMULTI:
188290650Shselasky		ret =
189290650Shselasky		    (1 << MLX5E_TT_IPV4_UDP) |
190290650Shselasky		    (1 << MLX5E_TT_IPV6_UDP) |
191290650Shselasky		    (1 << MLX5E_TT_IPV4) |
192290650Shselasky		    (1 << MLX5E_TT_IPV6) |
193290650Shselasky		    (1 << MLX5E_TT_ANY) |
194290650Shselasky		    0;
195290650Shselasky		break;
196290650Shselasky
197290650Shselasky	default:			/* MLX5E_PROMISC */
198290650Shselasky		ret =
199290650Shselasky		    (1 << MLX5E_TT_IPV4_TCP) |
200290650Shselasky		    (1 << MLX5E_TT_IPV6_TCP) |
201290650Shselasky		    (1 << MLX5E_TT_IPV4_UDP) |
202290650Shselasky		    (1 << MLX5E_TT_IPV6_UDP) |
203290650Shselasky		    (1 << MLX5E_TT_IPV4) |
204290650Shselasky		    (1 << MLX5E_TT_IPV6) |
205290650Shselasky		    (1 << MLX5E_TT_ANY) |
206290650Shselasky		    0;
207290650Shselasky		break;
208290650Shselasky	}
209290650Shselasky
210290650Shselasky	return (ret);
211290650Shselasky}
212290650Shselasky
213290650Shselaskystatic int
214290650Shselaskymlx5e_add_eth_addr_rule_sub(struct mlx5e_priv *priv,
215290650Shselasky    struct mlx5e_eth_addr_info *ai, int type,
216290650Shselasky    void *flow_context, void *match_criteria)
217290650Shselasky{
218290650Shselasky	u8 match_criteria_enable = 0;
219290650Shselasky	void *match_value;
220290650Shselasky	void *dest;
221290650Shselasky	u8 *dmac;
222290650Shselasky	u8 *match_criteria_dmac;
223290650Shselasky	void *ft = priv->ft.main;
224290650Shselasky	u32 *tirn = priv->tirn;
225290650Shselasky	u32 tt_vec;
226290650Shselasky	int err;
227290650Shselasky
228290650Shselasky	match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
229290650Shselasky	dmac = MLX5_ADDR_OF(fte_match_param, match_value,
230290650Shselasky	    outer_headers.dmac_47_16);
231290650Shselasky	match_criteria_dmac = MLX5_ADDR_OF(fte_match_param, match_criteria,
232290650Shselasky	    outer_headers.dmac_47_16);
233290650Shselasky	dest = MLX5_ADDR_OF(flow_context, flow_context, destination);
234290650Shselasky
235290650Shselasky	MLX5_SET(flow_context, flow_context, action,
236290650Shselasky	    MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
237290650Shselasky	MLX5_SET(flow_context, flow_context, destination_list_size, 1);
238290650Shselasky	MLX5_SET(dest_format_struct, dest, destination_type,
239290650Shselasky	    MLX5_FLOW_CONTEXT_DEST_TYPE_TIR);
240290650Shselasky
241290650Shselasky	switch (type) {
242290650Shselasky	case MLX5E_FULLMATCH:
243290650Shselasky		match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
244290650Shselasky		memset(match_criteria_dmac, 0xff, ETH_ALEN);
245290650Shselasky		ether_addr_copy(dmac, ai->addr);
246290650Shselasky		break;
247290650Shselasky
248290650Shselasky	case MLX5E_ALLMULTI:
249290650Shselasky		match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
250290650Shselasky		match_criteria_dmac[0] = 0x01;
251290650Shselasky		dmac[0] = 0x01;
252290650Shselasky		break;
253290650Shselasky
254290650Shselasky	case MLX5E_PROMISC:
255290650Shselasky		break;
256290650Shselasky	default:
257290650Shselasky		break;
258290650Shselasky	}
259290650Shselasky
260290650Shselasky	tt_vec = mlx5e_get_tt_vec(ai, type);
261290650Shselasky
262290650Shselasky	if (tt_vec & (1 << MLX5E_TT_ANY)) {
263290650Shselasky		MLX5_SET(dest_format_struct, dest, destination_id,
264290650Shselasky		    tirn[MLX5E_TT_ANY]);
265290650Shselasky		err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
266290650Shselasky		    match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_ANY]);
267290650Shselasky		if (err) {
268290650Shselasky			mlx5e_del_eth_addr_from_flow_table(priv, ai);
269290650Shselasky			return (err);
270290650Shselasky		}
271290650Shselasky		ai->tt_vec |= (1 << MLX5E_TT_ANY);
272290650Shselasky	}
273290650Shselasky	match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
274290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, match_criteria,
275290650Shselasky	    outer_headers.ethertype);
276290650Shselasky
277290650Shselasky	if (tt_vec & (1 << MLX5E_TT_IPV4)) {
278290650Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
279290650Shselasky		    ETHERTYPE_IP);
280290650Shselasky		MLX5_SET(dest_format_struct, dest, destination_id,
281290650Shselasky		    tirn[MLX5E_TT_IPV4]);
282290650Shselasky		err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
283290650Shselasky		    match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4]);
284290650Shselasky		if (err) {
285290650Shselasky			mlx5e_del_eth_addr_from_flow_table(priv, ai);
286290650Shselasky			return (err);
287290650Shselasky		}
288290650Shselasky		ai->tt_vec |= (1 << MLX5E_TT_IPV4);
289290650Shselasky	}
290290650Shselasky	if (tt_vec & (1 << MLX5E_TT_IPV6)) {
291290650Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
292290650Shselasky		    ETHERTYPE_IPV6);
293290650Shselasky		MLX5_SET(dest_format_struct, dest, destination_id,
294290650Shselasky		    tirn[MLX5E_TT_IPV6]);
295290650Shselasky		err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
296290650Shselasky		    match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6]);
297290650Shselasky		if (err) {
298290650Shselasky			mlx5e_del_eth_addr_from_flow_table(priv, ai);
299290650Shselasky			return (err);
300290650Shselasky		}
301290650Shselasky		ai->tt_vec |= (1 << MLX5E_TT_IPV6);
302290650Shselasky	}
303290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, match_criteria,
304290650Shselasky	    outer_headers.ip_protocol);
305290650Shselasky	MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol,
306290650Shselasky	    IPPROTO_UDP);
307290650Shselasky
308290650Shselasky	if (tt_vec & (1 << MLX5E_TT_IPV4_UDP)) {
309290650Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
310290650Shselasky		    ETHERTYPE_IP);
311290650Shselasky		MLX5_SET(dest_format_struct, dest, destination_id,
312290650Shselasky		    tirn[MLX5E_TT_IPV4_UDP]);
313290650Shselasky		err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
314290650Shselasky		    match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4_UDP]);
315290650Shselasky		if (err) {
316290650Shselasky			mlx5e_del_eth_addr_from_flow_table(priv, ai);
317290650Shselasky			return (err);
318290650Shselasky		}
319290650Shselasky		ai->tt_vec |= (1 << MLX5E_TT_IPV4_UDP);
320290650Shselasky	}
321290650Shselasky	if (tt_vec & (1 << MLX5E_TT_IPV6_UDP)) {
322290650Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
323290650Shselasky		    ETHERTYPE_IPV6);
324290650Shselasky		MLX5_SET(dest_format_struct, dest, destination_id,
325290650Shselasky		    tirn[MLX5E_TT_IPV6_UDP]);
326290650Shselasky		err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
327290650Shselasky		    match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6_UDP]);
328290650Shselasky		if (err) {
329290650Shselasky			mlx5e_del_eth_addr_from_flow_table(priv, ai);
330290650Shselasky			return (err);
331290650Shselasky		}
332290650Shselasky		ai->tt_vec |= (1 << MLX5E_TT_IPV6_UDP);
333290650Shselasky	}
334290650Shselasky	MLX5_SET(fte_match_param, match_value, outer_headers.ip_protocol,
335290650Shselasky	    IPPROTO_TCP);
336290650Shselasky
337290650Shselasky	if (tt_vec & (1 << MLX5E_TT_IPV4_TCP)) {
338290650Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
339290650Shselasky		    ETHERTYPE_IP);
340290650Shselasky		MLX5_SET(dest_format_struct, dest, destination_id,
341290650Shselasky		    tirn[MLX5E_TT_IPV4_TCP]);
342290650Shselasky		err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
343290650Shselasky		    match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV4_TCP]);
344290650Shselasky		if (err) {
345290650Shselasky			mlx5e_del_eth_addr_from_flow_table(priv, ai);
346290650Shselasky			return (err);
347290650Shselasky		}
348290650Shselasky		ai->tt_vec |= (1 << MLX5E_TT_IPV4_TCP);
349290650Shselasky	}
350290650Shselasky	if (tt_vec & (1 << MLX5E_TT_IPV6_TCP)) {
351290650Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.ethertype,
352290650Shselasky		    ETHERTYPE_IPV6);
353290650Shselasky		MLX5_SET(dest_format_struct, dest, destination_id,
354290650Shselasky		    tirn[MLX5E_TT_IPV6_TCP]);
355290650Shselasky		err = mlx5_add_flow_table_entry(ft, match_criteria_enable,
356290650Shselasky		    match_criteria, flow_context, &ai->ft_ix[MLX5E_TT_IPV6_TCP]);
357290650Shselasky		if (err) {
358290650Shselasky			mlx5e_del_eth_addr_from_flow_table(priv, ai);
359290650Shselasky			return (err);
360290650Shselasky		}
361290650Shselasky		ai->tt_vec |= (1 << MLX5E_TT_IPV6_TCP);
362290650Shselasky	}
363290650Shselasky	return (0);
364290650Shselasky}
365290650Shselasky
366290650Shselaskystatic int
367290650Shselaskymlx5e_add_eth_addr_rule(struct mlx5e_priv *priv,
368290650Shselasky    struct mlx5e_eth_addr_info *ai, int type)
369290650Shselasky{
370290650Shselasky	u32 *flow_context;
371290650Shselasky	u32 *match_criteria;
372290650Shselasky	int err;
373290650Shselasky
374290650Shselasky	flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) +
375290650Shselasky	    MLX5_ST_SZ_BYTES(dest_format_struct));
376290650Shselasky	match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
377290650Shselasky	if (!flow_context || !match_criteria) {
378290650Shselasky		if_printf(priv->ifp, "%s: alloc failed\n", __func__);
379290650Shselasky		err = -ENOMEM;
380290650Shselasky		goto add_eth_addr_rule_out;
381290650Shselasky	}
382290650Shselasky	err = mlx5e_add_eth_addr_rule_sub(priv, ai, type, flow_context,
383290650Shselasky	    match_criteria);
384290650Shselasky	if (err)
385290650Shselasky		if_printf(priv->ifp, "%s: failed\n", __func__);
386290650Shselasky
387290650Shselaskyadd_eth_addr_rule_out:
388290650Shselasky	kvfree(match_criteria);
389290650Shselasky	kvfree(flow_context);
390290650Shselasky	return (err);
391290650Shselasky}
392290650Shselasky
393302270Shselaskystatic int mlx5e_vport_context_update_vlans(struct mlx5e_priv *priv)
394302270Shselasky{
395302270Shselasky	struct ifnet *ifp = priv->ifp;
396302270Shselasky	int max_list_size;
397302270Shselasky	int list_size;
398302270Shselasky	u16 *vlans;
399302270Shselasky	int vlan;
400302270Shselasky	int err;
401302270Shselasky	int i;
402302270Shselasky
403302270Shselasky	list_size = 0;
404302270Shselasky	for_each_set_bit(vlan, priv->vlan.active_vlans, VLAN_N_VID)
405302270Shselasky		list_size++;
406302270Shselasky
407302270Shselasky	max_list_size = 1 << MLX5_CAP_GEN(priv->mdev, log_max_vlan_list);
408302270Shselasky
409302270Shselasky	if (list_size > max_list_size) {
410302270Shselasky		if_printf(ifp,
411302270Shselasky			    "ifnet vlans list size (%d) > (%d) max vport list size, some vlans will be dropped\n",
412302270Shselasky			    list_size, max_list_size);
413302270Shselasky		list_size = max_list_size;
414302270Shselasky	}
415302270Shselasky
416302270Shselasky	vlans = kcalloc(list_size, sizeof(*vlans), GFP_KERNEL);
417302270Shselasky	if (!vlans)
418302270Shselasky		return -ENOMEM;
419302270Shselasky
420302270Shselasky	i = 0;
421302270Shselasky	for_each_set_bit(vlan, priv->vlan.active_vlans, VLAN_N_VID) {
422302270Shselasky		if (i >= list_size)
423302270Shselasky			break;
424302270Shselasky		vlans[i++] = vlan;
425302270Shselasky	}
426302270Shselasky
427302270Shselasky	err = mlx5_modify_nic_vport_vlans(priv->mdev, vlans, list_size);
428302270Shselasky	if (err)
429302270Shselasky		if_printf(ifp, "Failed to modify vport vlans list err(%d)\n",
430302270Shselasky			   err);
431302270Shselasky
432302270Shselasky	kfree(vlans);
433302270Shselasky	return err;
434302270Shselasky}
435302270Shselasky
436290650Shselaskyenum mlx5e_vlan_rule_type {
437290650Shselasky	MLX5E_VLAN_RULE_TYPE_UNTAGGED,
438290650Shselasky	MLX5E_VLAN_RULE_TYPE_ANY_VID,
439290650Shselasky	MLX5E_VLAN_RULE_TYPE_MATCH_VID,
440290650Shselasky};
441290650Shselasky
442290650Shselaskystatic int
443290650Shselaskymlx5e_add_vlan_rule(struct mlx5e_priv *priv,
444290650Shselasky    enum mlx5e_vlan_rule_type rule_type, u16 vid)
445290650Shselasky{
446290650Shselasky	u8 match_criteria_enable = 0;
447290650Shselasky	u32 *flow_context;
448290650Shselasky	void *match_value;
449290650Shselasky	void *dest;
450290650Shselasky	u32 *match_criteria;
451290650Shselasky	u32 *ft_ix;
452290650Shselasky	int err;
453290650Shselasky
454290650Shselasky	flow_context = mlx5_vzalloc(MLX5_ST_SZ_BYTES(flow_context) +
455290650Shselasky	    MLX5_ST_SZ_BYTES(dest_format_struct));
456290650Shselasky	match_criteria = mlx5_vzalloc(MLX5_ST_SZ_BYTES(fte_match_param));
457290650Shselasky	if (!flow_context || !match_criteria) {
458290650Shselasky		if_printf(priv->ifp, "%s: alloc failed\n", __func__);
459290650Shselasky		err = -ENOMEM;
460290650Shselasky		goto add_vlan_rule_out;
461290650Shselasky	}
462290650Shselasky	match_value = MLX5_ADDR_OF(flow_context, flow_context, match_value);
463290650Shselasky	dest = MLX5_ADDR_OF(flow_context, flow_context, destination);
464290650Shselasky
465290650Shselasky	MLX5_SET(flow_context, flow_context, action,
466291184Shselasky	    MLX5_FLOW_CONTEXT_ACTION_FWD_DEST);
467290650Shselasky	MLX5_SET(flow_context, flow_context, destination_list_size, 1);
468290650Shselasky	MLX5_SET(dest_format_struct, dest, destination_type,
469291184Shselasky	    MLX5_FLOW_CONTEXT_DEST_TYPE_FLOW_TABLE);
470290650Shselasky	MLX5_SET(dest_format_struct, dest, destination_id,
471291184Shselasky	    mlx5_get_flow_table_id(priv->ft.main));
472290650Shselasky
473290650Shselasky	match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
474290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, match_criteria,
475306244Shselasky	    outer_headers.cvlan_tag);
476290650Shselasky
477290650Shselasky	switch (rule_type) {
478290650Shselasky	case MLX5E_VLAN_RULE_TYPE_UNTAGGED:
479290650Shselasky		ft_ix = &priv->vlan.untagged_rule_ft_ix;
480290650Shselasky		break;
481290650Shselasky	case MLX5E_VLAN_RULE_TYPE_ANY_VID:
482290650Shselasky		ft_ix = &priv->vlan.any_vlan_rule_ft_ix;
483306244Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.cvlan_tag,
484290650Shselasky		    1);
485290650Shselasky		break;
486290650Shselasky	default:			/* MLX5E_VLAN_RULE_TYPE_MATCH_VID */
487290650Shselasky		ft_ix = &priv->vlan.active_vlans_ft_ix[vid];
488306244Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.cvlan_tag,
489290650Shselasky		    1);
490290650Shselasky		MLX5_SET_TO_ONES(fte_match_param, match_criteria,
491290650Shselasky		    outer_headers.first_vid);
492290650Shselasky		MLX5_SET(fte_match_param, match_value, outer_headers.first_vid,
493290650Shselasky		    vid);
494302270Shselasky		mlx5e_vport_context_update_vlans(priv);
495290650Shselasky		break;
496290650Shselasky	}
497290650Shselasky
498290650Shselasky	err = mlx5_add_flow_table_entry(priv->ft.vlan, match_criteria_enable,
499290650Shselasky	    match_criteria, flow_context, ft_ix);
500290650Shselasky	if (err)
501290650Shselasky		if_printf(priv->ifp, "%s: failed\n", __func__);
502290650Shselasky
503290650Shselaskyadd_vlan_rule_out:
504290650Shselasky	kvfree(match_criteria);
505290650Shselasky	kvfree(flow_context);
506290650Shselasky	return (err);
507290650Shselasky}
508290650Shselasky
509290650Shselaskystatic void
510290650Shselaskymlx5e_del_vlan_rule(struct mlx5e_priv *priv,
511290650Shselasky    enum mlx5e_vlan_rule_type rule_type, u16 vid)
512290650Shselasky{
513290650Shselasky	switch (rule_type) {
514290650Shselasky	case MLX5E_VLAN_RULE_TYPE_UNTAGGED:
515290650Shselasky		mlx5_del_flow_table_entry(priv->ft.vlan,
516290650Shselasky		    priv->vlan.untagged_rule_ft_ix);
517290650Shselasky		break;
518290650Shselasky	case MLX5E_VLAN_RULE_TYPE_ANY_VID:
519290650Shselasky		mlx5_del_flow_table_entry(priv->ft.vlan,
520290650Shselasky		    priv->vlan.any_vlan_rule_ft_ix);
521290650Shselasky		break;
522290650Shselasky	case MLX5E_VLAN_RULE_TYPE_MATCH_VID:
523290650Shselasky		mlx5_del_flow_table_entry(priv->ft.vlan,
524290650Shselasky		    priv->vlan.active_vlans_ft_ix[vid]);
525302270Shselasky		mlx5e_vport_context_update_vlans(priv);
526290650Shselasky		break;
527290650Shselasky	}
528290650Shselasky}
529290650Shselasky
530290650Shselaskyvoid
531290650Shselaskymlx5e_enable_vlan_filter(struct mlx5e_priv *priv)
532290650Shselasky{
533290650Shselasky	if (priv->vlan.filter_disabled) {
534290650Shselasky		priv->vlan.filter_disabled = false;
535290650Shselasky		if (test_bit(MLX5E_STATE_OPENED, &priv->state))
536290650Shselasky			mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
537290650Shselasky			    0);
538290650Shselasky	}
539290650Shselasky}
540290650Shselasky
541290650Shselaskyvoid
542290650Shselaskymlx5e_disable_vlan_filter(struct mlx5e_priv *priv)
543290650Shselasky{
544290650Shselasky	if (!priv->vlan.filter_disabled) {
545290650Shselasky		priv->vlan.filter_disabled = true;
546290650Shselasky		if (test_bit(MLX5E_STATE_OPENED, &priv->state))
547290650Shselasky			mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
548290650Shselasky			    0);
549290650Shselasky	}
550290650Shselasky}
551290650Shselasky
552290650Shselaskyvoid
553290650Shselaskymlx5e_vlan_rx_add_vid(void *arg, struct ifnet *ifp, u16 vid)
554290650Shselasky{
555290650Shselasky	struct mlx5e_priv *priv = arg;
556290650Shselasky
557290650Shselasky	if (ifp != priv->ifp)
558290650Shselasky		return;
559290650Shselasky
560290650Shselasky	PRIV_LOCK(priv);
561290650Shselasky	set_bit(vid, priv->vlan.active_vlans);
562290650Shselasky	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
563290650Shselasky		mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
564290650Shselasky	PRIV_UNLOCK(priv);
565290650Shselasky}
566290650Shselasky
567290650Shselaskyvoid
568290650Shselaskymlx5e_vlan_rx_kill_vid(void *arg, struct ifnet *ifp, u16 vid)
569290650Shselasky{
570290650Shselasky	struct mlx5e_priv *priv = arg;
571290650Shselasky
572290650Shselasky	if (ifp != priv->ifp)
573290650Shselasky		return;
574290650Shselasky
575290650Shselasky	PRIV_LOCK(priv);
576290650Shselasky	clear_bit(vid, priv->vlan.active_vlans);
577290650Shselasky	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
578290650Shselasky		mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
579290650Shselasky	PRIV_UNLOCK(priv);
580290650Shselasky}
581290650Shselasky
582290650Shselaskyint
583290650Shselaskymlx5e_add_all_vlan_rules(struct mlx5e_priv *priv)
584290650Shselasky{
585290650Shselasky	u16 vid;
586290650Shselasky	int err;
587290650Shselasky
588290650Shselasky	for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID) {
589290650Shselasky		err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID,
590290650Shselasky		    vid);
591290650Shselasky		if (err)
592290650Shselasky			return (err);
593290650Shselasky	}
594290650Shselasky
595290650Shselasky	err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
596290650Shselasky	if (err)
597290650Shselasky		return (err);
598290650Shselasky
599290650Shselasky	if (priv->vlan.filter_disabled) {
600290650Shselasky		err = mlx5e_add_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID,
601290650Shselasky		    0);
602290650Shselasky		if (err)
603290650Shselasky			return (err);
604290650Shselasky	}
605290650Shselasky	return (0);
606290650Shselasky}
607290650Shselasky
608290650Shselaskyvoid
609290650Shselaskymlx5e_del_all_vlan_rules(struct mlx5e_priv *priv)
610290650Shselasky{
611290650Shselasky	u16 vid;
612290650Shselasky
613290650Shselasky	if (priv->vlan.filter_disabled)
614290650Shselasky		mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_ANY_VID, 0);
615290650Shselasky
616290650Shselasky	mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_UNTAGGED, 0);
617290650Shselasky
618290650Shselasky	for_each_set_bit(vid, priv->vlan.active_vlans, VLAN_N_VID)
619290650Shselasky	    mlx5e_del_vlan_rule(priv, MLX5E_VLAN_RULE_TYPE_MATCH_VID, vid);
620290650Shselasky}
621290650Shselasky
622290650Shselasky#define	mlx5e_for_each_hash_node(hn, tmp, hash, i) \
623290650Shselasky	for (i = 0; i < MLX5E_ETH_ADDR_HASH_SIZE; i++) \
624290650Shselasky		LIST_FOREACH_SAFE(hn, &(hash)[i], hlist, tmp)
625290650Shselasky
626290650Shselaskystatic void
627290650Shselaskymlx5e_execute_action(struct mlx5e_priv *priv,
628290650Shselasky    struct mlx5e_eth_addr_hash_node *hn)
629290650Shselasky{
630290650Shselasky	switch (hn->action) {
631290650Shselasky	case MLX5E_ACTION_ADD:
632290650Shselasky		mlx5e_add_eth_addr_rule(priv, &hn->ai, MLX5E_FULLMATCH);
633290650Shselasky		hn->action = MLX5E_ACTION_NONE;
634290650Shselasky		break;
635290650Shselasky
636290650Shselasky	case MLX5E_ACTION_DEL:
637290650Shselasky		mlx5e_del_eth_addr_from_flow_table(priv, &hn->ai);
638290650Shselasky		mlx5e_del_eth_addr_from_hash(hn);
639290650Shselasky		break;
640290650Shselasky
641290650Shselasky	default:
642290650Shselasky		break;
643290650Shselasky	}
644290650Shselasky}
645290650Shselasky
646290650Shselaskystatic void
647290650Shselaskymlx5e_sync_ifp_addr(struct mlx5e_priv *priv)
648290650Shselasky{
649290650Shselasky	struct ifnet *ifp = priv->ifp;
650290650Shselasky	struct ifaddr *ifa;
651290650Shselasky	struct ifmultiaddr *ifma;
652290650Shselasky
653290650Shselasky	/* XXX adding this entry might not be needed */
654290650Shselasky	mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_uc,
655290650Shselasky	    LLADDR((struct sockaddr_dl *)(ifp->if_addr->ifa_addr)));
656290650Shselasky
657290650Shselasky	if_addr_rlock(ifp);
658290650Shselasky	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
659290650Shselasky		if (ifa->ifa_addr->sa_family != AF_LINK)
660290650Shselasky			continue;
661290650Shselasky		mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_uc,
662290650Shselasky		    LLADDR((struct sockaddr_dl *)ifa->ifa_addr));
663290650Shselasky	}
664290650Shselasky	if_addr_runlock(ifp);
665290650Shselasky
666290650Shselasky	if_maddr_rlock(ifp);
667290650Shselasky	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
668290650Shselasky		if (ifma->ifma_addr->sa_family != AF_LINK)
669290650Shselasky			continue;
670290650Shselasky		mlx5e_add_eth_addr_to_hash(priv->eth_addr.if_mc,
671290650Shselasky		    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
672290650Shselasky	}
673290650Shselasky	if_maddr_runlock(ifp);
674290650Shselasky}
675290650Shselasky
676302270Shselaskystatic void mlx5e_fill_addr_array(struct mlx5e_priv *priv, int list_type,
677302270Shselasky				  u8 addr_array[][ETH_ALEN], int size)
678302270Shselasky{
679302270Shselasky	bool is_uc = (list_type == MLX5_NIC_VPORT_LIST_TYPE_UC);
680302270Shselasky	struct ifnet *ifp = priv->ifp;
681302270Shselasky	struct mlx5e_eth_addr_hash_node *hn;
682302270Shselasky	struct mlx5e_eth_addr_hash_head *addr_list;
683302270Shselasky	struct mlx5e_eth_addr_hash_node *tmp;
684302270Shselasky	int i = 0;
685302270Shselasky	int hi;
686302270Shselasky
687302270Shselasky	addr_list = is_uc ? priv->eth_addr.if_uc : priv->eth_addr.if_mc;
688302270Shselasky
689302270Shselasky	if (is_uc) /* Make sure our own address is pushed first */
690302270Shselasky		ether_addr_copy(addr_array[i++], IF_LLADDR(ifp));
691302270Shselasky	else if (priv->eth_addr.broadcast_enabled)
692302270Shselasky		ether_addr_copy(addr_array[i++], ifp->if_broadcastaddr);
693302270Shselasky
694302270Shselasky	mlx5e_for_each_hash_node(hn, tmp, addr_list, hi) {
695302270Shselasky		if (ether_addr_equal(IF_LLADDR(ifp), hn->ai.addr))
696302270Shselasky			continue;
697302270Shselasky		if (i >= size)
698302270Shselasky			break;
699302270Shselasky		ether_addr_copy(addr_array[i++], hn->ai.addr);
700302270Shselasky	}
701302270Shselasky}
702302270Shselasky
703302270Shselaskystatic void mlx5e_vport_context_update_addr_list(struct mlx5e_priv *priv,
704302270Shselasky						 int list_type)
705302270Shselasky{
706302270Shselasky	bool is_uc = (list_type == MLX5_NIC_VPORT_LIST_TYPE_UC);
707302270Shselasky	struct mlx5e_eth_addr_hash_node *hn;
708302270Shselasky	u8 (*addr_array)[ETH_ALEN] = NULL;
709302270Shselasky	struct mlx5e_eth_addr_hash_head *addr_list;
710302270Shselasky	struct mlx5e_eth_addr_hash_node *tmp;
711302270Shselasky	int max_size;
712302270Shselasky	int size;
713302270Shselasky	int err;
714302270Shselasky	int hi;
715302270Shselasky
716302270Shselasky	size = is_uc ? 0 : (priv->eth_addr.broadcast_enabled ? 1 : 0);
717302270Shselasky	max_size = is_uc ?
718302270Shselasky		1 << MLX5_CAP_GEN(priv->mdev, log_max_current_uc_list) :
719302270Shselasky		1 << MLX5_CAP_GEN(priv->mdev, log_max_current_mc_list);
720302270Shselasky
721302270Shselasky	addr_list = is_uc ? priv->eth_addr.if_uc : priv->eth_addr.if_mc;
722302270Shselasky	mlx5e_for_each_hash_node(hn, tmp, addr_list, hi)
723302270Shselasky		size++;
724302270Shselasky
725302270Shselasky	if (size > max_size) {
726302270Shselasky		if_printf(priv->ifp,
727302270Shselasky			    "ifp %s list size (%d) > (%d) max vport list size, some addresses will be dropped\n",
728302270Shselasky			    is_uc ? "UC" : "MC", size, max_size);
729302270Shselasky		size = max_size;
730302270Shselasky	}
731302270Shselasky
732302270Shselasky	if (size) {
733302270Shselasky		addr_array = kcalloc(size, ETH_ALEN, GFP_KERNEL);
734302270Shselasky		if (!addr_array) {
735302270Shselasky			err = -ENOMEM;
736302270Shselasky			goto out;
737302270Shselasky		}
738302270Shselasky		mlx5e_fill_addr_array(priv, list_type, addr_array, size);
739302270Shselasky	}
740302270Shselasky
741302270Shselasky	err = mlx5_modify_nic_vport_mac_list(priv->mdev, list_type, addr_array, size);
742302270Shselaskyout:
743302270Shselasky	if (err)
744302270Shselasky		if_printf(priv->ifp,
745302270Shselasky			   "Failed to modify vport %s list err(%d)\n",
746302270Shselasky			   is_uc ? "UC" : "MC", err);
747302270Shselasky	kfree(addr_array);
748302270Shselasky}
749302270Shselasky
750302270Shselaskystatic void mlx5e_vport_context_update(struct mlx5e_priv *priv)
751302270Shselasky{
752302270Shselasky	struct mlx5e_eth_addr_db *ea = &priv->eth_addr;
753302270Shselasky
754302270Shselasky	mlx5e_vport_context_update_addr_list(priv, MLX5_NIC_VPORT_LIST_TYPE_UC);
755302270Shselasky	mlx5e_vport_context_update_addr_list(priv, MLX5_NIC_VPORT_LIST_TYPE_MC);
756302270Shselasky	mlx5_modify_nic_vport_promisc(priv->mdev, 0,
757302270Shselasky				      ea->allmulti_enabled,
758302270Shselasky				      ea->promisc_enabled);
759302270Shselasky}
760302270Shselasky
761290650Shselaskystatic void
762290650Shselaskymlx5e_apply_ifp_addr(struct mlx5e_priv *priv)
763290650Shselasky{
764290650Shselasky	struct mlx5e_eth_addr_hash_node *hn;
765290650Shselasky	struct mlx5e_eth_addr_hash_node *tmp;
766290650Shselasky	int i;
767290650Shselasky
768290650Shselasky	mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_uc, i)
769290650Shselasky	    mlx5e_execute_action(priv, hn);
770290650Shselasky
771290650Shselasky	mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_mc, i)
772290650Shselasky	    mlx5e_execute_action(priv, hn);
773290650Shselasky}
774290650Shselasky
775290650Shselaskystatic void
776290650Shselaskymlx5e_handle_ifp_addr(struct mlx5e_priv *priv)
777290650Shselasky{
778290650Shselasky	struct mlx5e_eth_addr_hash_node *hn;
779290650Shselasky	struct mlx5e_eth_addr_hash_node *tmp;
780290650Shselasky	int i;
781290650Shselasky
782290650Shselasky	mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_uc, i)
783290650Shselasky	    hn->action = MLX5E_ACTION_DEL;
784290650Shselasky	mlx5e_for_each_hash_node(hn, tmp, priv->eth_addr.if_mc, i)
785290650Shselasky	    hn->action = MLX5E_ACTION_DEL;
786290650Shselasky
787290650Shselasky	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
788290650Shselasky		mlx5e_sync_ifp_addr(priv);
789290650Shselasky
790290650Shselasky	mlx5e_apply_ifp_addr(priv);
791290650Shselasky}
792290650Shselasky
793290650Shselaskyvoid
794290650Shselaskymlx5e_set_rx_mode_core(struct mlx5e_priv *priv)
795290650Shselasky{
796290650Shselasky	struct mlx5e_eth_addr_db *ea = &priv->eth_addr;
797290650Shselasky	struct ifnet *ndev = priv->ifp;
798290650Shselasky
799290650Shselasky	bool rx_mode_enable = test_bit(MLX5E_STATE_OPENED, &priv->state);
800290650Shselasky	bool promisc_enabled = rx_mode_enable && (ndev->if_flags & IFF_PROMISC);
801290650Shselasky	bool allmulti_enabled = rx_mode_enable && (ndev->if_flags & IFF_ALLMULTI);
802290650Shselasky	bool broadcast_enabled = rx_mode_enable;
803290650Shselasky
804290650Shselasky	bool enable_promisc = !ea->promisc_enabled && promisc_enabled;
805290650Shselasky	bool disable_promisc = ea->promisc_enabled && !promisc_enabled;
806290650Shselasky	bool enable_allmulti = !ea->allmulti_enabled && allmulti_enabled;
807290650Shselasky	bool disable_allmulti = ea->allmulti_enabled && !allmulti_enabled;
808290650Shselasky	bool enable_broadcast = !ea->broadcast_enabled && broadcast_enabled;
809290650Shselasky	bool disable_broadcast = ea->broadcast_enabled && !broadcast_enabled;
810290650Shselasky
811290650Shselasky	/* update broadcast address */
812290650Shselasky	ether_addr_copy(priv->eth_addr.broadcast.addr,
813290650Shselasky	    priv->ifp->if_broadcastaddr);
814290650Shselasky
815290650Shselasky	if (enable_promisc)
816290650Shselasky		mlx5e_add_eth_addr_rule(priv, &ea->promisc, MLX5E_PROMISC);
817290650Shselasky	if (enable_allmulti)
818290650Shselasky		mlx5e_add_eth_addr_rule(priv, &ea->allmulti, MLX5E_ALLMULTI);
819290650Shselasky	if (enable_broadcast)
820290650Shselasky		mlx5e_add_eth_addr_rule(priv, &ea->broadcast, MLX5E_FULLMATCH);
821290650Shselasky
822290650Shselasky	mlx5e_handle_ifp_addr(priv);
823290650Shselasky
824290650Shselasky	if (disable_broadcast)
825290650Shselasky		mlx5e_del_eth_addr_from_flow_table(priv, &ea->broadcast);
826290650Shselasky	if (disable_allmulti)
827290650Shselasky		mlx5e_del_eth_addr_from_flow_table(priv, &ea->allmulti);
828290650Shselasky	if (disable_promisc)
829290650Shselasky		mlx5e_del_eth_addr_from_flow_table(priv, &ea->promisc);
830290650Shselasky
831290650Shselasky	ea->promisc_enabled = promisc_enabled;
832290650Shselasky	ea->allmulti_enabled = allmulti_enabled;
833290650Shselasky	ea->broadcast_enabled = broadcast_enabled;
834302270Shselasky
835302270Shselasky	mlx5e_vport_context_update(priv);
836290650Shselasky}
837290650Shselasky
838290650Shselaskyvoid
839290650Shselaskymlx5e_set_rx_mode_work(struct work_struct *work)
840290650Shselasky{
841290650Shselasky	struct mlx5e_priv *priv =
842290650Shselasky	    container_of(work, struct mlx5e_priv, set_rx_mode_work);
843290650Shselasky
844290650Shselasky	PRIV_LOCK(priv);
845290650Shselasky	if (test_bit(MLX5E_STATE_OPENED, &priv->state))
846290650Shselasky		mlx5e_set_rx_mode_core(priv);
847290650Shselasky	PRIV_UNLOCK(priv);
848290650Shselasky}
849290650Shselasky
850290650Shselaskystatic int
851290650Shselaskymlx5e_create_main_flow_table(struct mlx5e_priv *priv)
852290650Shselasky{
853290650Shselasky	struct mlx5_flow_table_group *g;
854290650Shselasky	u8 *dmac;
855290650Shselasky
856290650Shselasky	g = malloc(9 * sizeof(*g), M_MLX5EN, M_WAITOK | M_ZERO);
857290650Shselasky
858290650Shselasky	g[0].log_sz = 2;
859290650Shselasky	g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
860290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
861290650Shselasky	    outer_headers.ethertype);
862290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
863290650Shselasky	    outer_headers.ip_protocol);
864290650Shselasky
865290650Shselasky	g[1].log_sz = 1;
866290650Shselasky	g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
867290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria,
868290650Shselasky	    outer_headers.ethertype);
869290650Shselasky
870290650Shselasky	g[2].log_sz = 0;
871290650Shselasky
872290650Shselasky	g[3].log_sz = 14;
873290650Shselasky	g[3].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
874290650Shselasky	dmac = MLX5_ADDR_OF(fte_match_param, g[3].match_criteria,
875290650Shselasky	    outer_headers.dmac_47_16);
876290650Shselasky	memset(dmac, 0xff, ETH_ALEN);
877290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria,
878290650Shselasky	    outer_headers.ethertype);
879290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[3].match_criteria,
880290650Shselasky	    outer_headers.ip_protocol);
881290650Shselasky
882290650Shselasky	g[4].log_sz = 13;
883290650Shselasky	g[4].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
884290650Shselasky	dmac = MLX5_ADDR_OF(fte_match_param, g[4].match_criteria,
885290650Shselasky	    outer_headers.dmac_47_16);
886290650Shselasky	memset(dmac, 0xff, ETH_ALEN);
887290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[4].match_criteria,
888290650Shselasky	    outer_headers.ethertype);
889290650Shselasky
890290650Shselasky	g[5].log_sz = 11;
891290650Shselasky	g[5].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
892290650Shselasky	dmac = MLX5_ADDR_OF(fte_match_param, g[5].match_criteria,
893290650Shselasky	    outer_headers.dmac_47_16);
894290650Shselasky	memset(dmac, 0xff, ETH_ALEN);
895290650Shselasky
896290650Shselasky	g[6].log_sz = 2;
897290650Shselasky	g[6].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
898290650Shselasky	dmac = MLX5_ADDR_OF(fte_match_param, g[6].match_criteria,
899290650Shselasky	    outer_headers.dmac_47_16);
900290650Shselasky	dmac[0] = 0x01;
901290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria,
902290650Shselasky	    outer_headers.ethertype);
903290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[6].match_criteria,
904290650Shselasky	    outer_headers.ip_protocol);
905290650Shselasky
906290650Shselasky	g[7].log_sz = 1;
907290650Shselasky	g[7].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
908290650Shselasky	dmac = MLX5_ADDR_OF(fte_match_param, g[7].match_criteria,
909290650Shselasky	    outer_headers.dmac_47_16);
910290650Shselasky	dmac[0] = 0x01;
911290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[7].match_criteria,
912290650Shselasky	    outer_headers.ethertype);
913290650Shselasky
914290650Shselasky	g[8].log_sz = 0;
915290650Shselasky	g[8].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
916290650Shselasky	dmac = MLX5_ADDR_OF(fte_match_param, g[8].match_criteria,
917290650Shselasky	    outer_headers.dmac_47_16);
918290650Shselasky	dmac[0] = 0x01;
919290650Shselasky	priv->ft.main = mlx5_create_flow_table(priv->mdev, 1,
920290650Shselasky	    MLX5_FLOW_TABLE_TYPE_NIC_RCV,
921290650Shselasky	    0, 9, g);
922290650Shselasky	free(g, M_MLX5EN);
923290650Shselasky
924290650Shselasky	return (priv->ft.main ? 0 : -ENOMEM);
925290650Shselasky}
926290650Shselasky
927290650Shselaskystatic void
928290650Shselaskymlx5e_destroy_main_flow_table(struct mlx5e_priv *priv)
929290650Shselasky{
930290650Shselasky	mlx5_destroy_flow_table(priv->ft.main);
931290650Shselasky	priv->ft.main = NULL;
932290650Shselasky}
933290650Shselasky
934290650Shselaskystatic int
935290650Shselaskymlx5e_create_vlan_flow_table(struct mlx5e_priv *priv)
936290650Shselasky{
937290650Shselasky	struct mlx5_flow_table_group *g;
938290650Shselasky
939290650Shselasky	g = malloc(2 * sizeof(*g), M_MLX5EN, M_WAITOK | M_ZERO);
940290650Shselasky
941290650Shselasky	g[0].log_sz = 12;
942290650Shselasky	g[0].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
943290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
944306244Shselasky	    outer_headers.cvlan_tag);
945290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[0].match_criteria,
946290650Shselasky	    outer_headers.first_vid);
947290650Shselasky
948290650Shselasky	/* untagged + any vlan id */
949290650Shselasky	g[1].log_sz = 1;
950290650Shselasky	g[1].match_criteria_enable = MLX5_MATCH_OUTER_HEADERS;
951290650Shselasky	MLX5_SET_TO_ONES(fte_match_param, g[1].match_criteria,
952306244Shselasky	    outer_headers.cvlan_tag);
953290650Shselasky
954290650Shselasky	priv->ft.vlan = mlx5_create_flow_table(priv->mdev, 0,
955290650Shselasky	    MLX5_FLOW_TABLE_TYPE_NIC_RCV,
956290650Shselasky	    0, 2, g);
957290650Shselasky	free(g, M_MLX5EN);
958290650Shselasky
959290650Shselasky	return (priv->ft.vlan ? 0 : -ENOMEM);
960290650Shselasky}
961290650Shselasky
962290650Shselaskystatic void
963290650Shselaskymlx5e_destroy_vlan_flow_table(struct mlx5e_priv *priv)
964290650Shselasky{
965290650Shselasky	mlx5_destroy_flow_table(priv->ft.vlan);
966290650Shselasky	priv->ft.vlan = NULL;
967290650Shselasky}
968290650Shselasky
969290650Shselaskyint
970290650Shselaskymlx5e_open_flow_table(struct mlx5e_priv *priv)
971290650Shselasky{
972290650Shselasky	int err;
973290650Shselasky
974290650Shselasky	err = mlx5e_create_main_flow_table(priv);
975290650Shselasky	if (err)
976290650Shselasky		return (err);
977290650Shselasky
978290650Shselasky	err = mlx5e_create_vlan_flow_table(priv);
979290650Shselasky	if (err)
980290650Shselasky		goto err_destroy_main_flow_table;
981290650Shselasky
982290650Shselasky	return (0);
983290650Shselasky
984290650Shselaskyerr_destroy_main_flow_table:
985290650Shselasky	mlx5e_destroy_main_flow_table(priv);
986290650Shselasky
987290650Shselasky	return (err);
988290650Shselasky}
989290650Shselasky
990290650Shselaskyvoid
991290650Shselaskymlx5e_close_flow_table(struct mlx5e_priv *priv)
992290650Shselasky{
993290650Shselasky	mlx5e_destroy_vlan_flow_table(priv);
994290650Shselasky	mlx5e_destroy_main_flow_table(priv);
995290650Shselasky}
996