xref: /freebsd/sys/dev/sfxge/common/ef10_filter.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1 /*-
2  * Copyright (c) 2007-2016 Solarflare Communications Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  *    this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * The views and conclusions contained in the software and documentation are
27  * those of the authors and should not be interpreted as representing official
28  * policies, either expressed or implied, of the FreeBSD Project.
29  */
30 
31 #include <sys/cdefs.h>
32 #include "efx.h"
33 #include "efx_impl.h"
34 
35 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
36 
37 #if EFSYS_OPT_FILTER
38 
39 #define	EFE_SPEC(eftp, index)	((eftp)->eft_entry[(index)].efe_spec)
40 
41 static			efx_filter_spec_t *
ef10_filter_entry_spec(__in const ef10_filter_table_t * eftp,__in unsigned int index)42 ef10_filter_entry_spec(
43 	__in		const ef10_filter_table_t *eftp,
44 	__in		unsigned int index)
45 {
46 	return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) &
47 		~(uintptr_t)EFX_EF10_FILTER_FLAGS));
48 }
49 
50 static			boolean_t
ef10_filter_entry_is_busy(__in const ef10_filter_table_t * eftp,__in unsigned int index)51 ef10_filter_entry_is_busy(
52 	__in		const ef10_filter_table_t *eftp,
53 	__in		unsigned int index)
54 {
55 	if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY)
56 		return (B_TRUE);
57 	else
58 		return (B_FALSE);
59 }
60 
61 static			boolean_t
ef10_filter_entry_is_auto_old(__in const ef10_filter_table_t * eftp,__in unsigned int index)62 ef10_filter_entry_is_auto_old(
63 	__in		const ef10_filter_table_t *eftp,
64 	__in		unsigned int index)
65 {
66 	if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD)
67 		return (B_TRUE);
68 	else
69 		return (B_FALSE);
70 }
71 
72 static			void
ef10_filter_set_entry(__inout ef10_filter_table_t * eftp,__in unsigned int index,__in_opt const efx_filter_spec_t * efsp)73 ef10_filter_set_entry(
74 	__inout		ef10_filter_table_t *eftp,
75 	__in		unsigned int index,
76 	__in_opt	const efx_filter_spec_t *efsp)
77 {
78 	EFE_SPEC(eftp, index) = (uintptr_t)efsp;
79 }
80 
81 static			void
ef10_filter_set_entry_busy(__inout ef10_filter_table_t * eftp,__in unsigned int index)82 ef10_filter_set_entry_busy(
83 	__inout		ef10_filter_table_t *eftp,
84 	__in		unsigned int index)
85 {
86 	EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY;
87 }
88 
89 static			void
ef10_filter_set_entry_not_busy(__inout ef10_filter_table_t * eftp,__in unsigned int index)90 ef10_filter_set_entry_not_busy(
91 	__inout		ef10_filter_table_t *eftp,
92 	__in		unsigned int index)
93 {
94 	EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY;
95 }
96 
97 static			void
ef10_filter_set_entry_auto_old(__inout ef10_filter_table_t * eftp,__in unsigned int index)98 ef10_filter_set_entry_auto_old(
99 	__inout		ef10_filter_table_t *eftp,
100 	__in		unsigned int index)
101 {
102 	EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL);
103 	EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD;
104 }
105 
106 static			void
ef10_filter_set_entry_not_auto_old(__inout ef10_filter_table_t * eftp,__in unsigned int index)107 ef10_filter_set_entry_not_auto_old(
108 	__inout		ef10_filter_table_t *eftp,
109 	__in		unsigned int index)
110 {
111 	EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD;
112 	EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL);
113 }
114 
115 	__checkReturn	efx_rc_t
ef10_filter_init(__in efx_nic_t * enp)116 ef10_filter_init(
117 	__in		efx_nic_t *enp)
118 {
119 	efx_rc_t rc;
120 	ef10_filter_table_t *eftp;
121 
122 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
123 	    enp->en_family == EFX_FAMILY_MEDFORD ||
124 	    enp->en_family == EFX_FAMILY_MEDFORD2);
125 
126 #define	MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match))
127 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST ==
128 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP));
129 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST ==
130 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP));
131 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC ==
132 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC));
133 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT ==
134 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT));
135 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC ==
136 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC));
137 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT ==
138 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT));
139 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE ==
140 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE));
141 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID ==
142 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN));
143 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID ==
144 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN));
145 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO ==
146 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO));
147 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_VNI_OR_VSID ==
148 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_VNI_OR_VSID));
149 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_LOC_MAC ==
150 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_DST_MAC));
151 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST ==
152 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST));
153 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST ==
154 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST));
155 	EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST ==
156 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST));
157 	EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST ==
158 	    MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST));
159 #undef MATCH_MASK
160 
161 	EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp);
162 
163 	if (!eftp) {
164 		rc = ENOMEM;
165 		goto fail1;
166 	}
167 
168 	enp->en_filter.ef_ef10_filter_table = eftp;
169 
170 	return (0);
171 
172 fail1:
173 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
174 
175 	return (rc);
176 }
177 
178 			void
ef10_filter_fini(__in efx_nic_t * enp)179 ef10_filter_fini(
180 	__in		efx_nic_t *enp)
181 {
182 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
183 	    enp->en_family == EFX_FAMILY_MEDFORD ||
184 	    enp->en_family == EFX_FAMILY_MEDFORD2);
185 
186 	if (enp->en_filter.ef_ef10_filter_table != NULL) {
187 		EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t),
188 		    enp->en_filter.ef_ef10_filter_table);
189 	}
190 }
191 
192 static	__checkReturn	efx_rc_t
efx_mcdi_filter_op_add(__in efx_nic_t * enp,__in efx_filter_spec_t * spec,__in unsigned int filter_op,__inout ef10_filter_handle_t * handle)193 efx_mcdi_filter_op_add(
194 	__in		efx_nic_t *enp,
195 	__in		efx_filter_spec_t *spec,
196 	__in		unsigned int filter_op,
197 	__inout		ef10_filter_handle_t *handle)
198 {
199 	efx_mcdi_req_t req;
200 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_V3_IN_LEN,
201 		MC_CMD_FILTER_OP_EXT_OUT_LEN);
202 	efx_filter_match_flags_t match_flags;
203 	efx_rc_t rc;
204 
205 	req.emr_cmd = MC_CMD_FILTER_OP;
206 	req.emr_in_buf = payload;
207 	req.emr_in_length = MC_CMD_FILTER_OP_V3_IN_LEN;
208 	req.emr_out_buf = payload;
209 	req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
210 
211 	/*
212 	 * Remove match flag for encapsulated filters that does not correspond
213 	 * to the MCDI match flags
214 	 */
215 	match_flags = spec->efs_match_flags & ~EFX_FILTER_MATCH_ENCAP_TYPE;
216 
217 	switch (filter_op) {
218 	case MC_CMD_FILTER_OP_IN_OP_REPLACE:
219 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO,
220 		    handle->efh_lo);
221 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI,
222 		    handle->efh_hi);
223 		/* Fall through */
224 	case MC_CMD_FILTER_OP_IN_OP_INSERT:
225 	case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE:
226 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, filter_op);
227 		break;
228 	default:
229 		EFSYS_ASSERT(0);
230 		rc = EINVAL;
231 		goto fail1;
232 	}
233 
234 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID,
235 	    EVB_PORT_ID_ASSIGNED);
236 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS,
237 	    match_flags);
238 	if (spec->efs_dmaq_id == EFX_FILTER_SPEC_RX_DMAQ_ID_DROP) {
239 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
240 		    MC_CMD_FILTER_OP_EXT_IN_RX_DEST_DROP);
241 	} else {
242 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST,
243 		    MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST);
244 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE,
245 		    spec->efs_dmaq_id);
246 	}
247 
248 #if EFSYS_OPT_RX_SCALE
249 	if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) {
250 		uint32_t rss_context;
251 
252 		if (spec->efs_rss_context == EFX_RSS_CONTEXT_DEFAULT)
253 			rss_context = enp->en_rss_context;
254 		else
255 			rss_context = spec->efs_rss_context;
256 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_CONTEXT,
257 		    rss_context);
258 	}
259 #endif
260 
261 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_MODE,
262 	    spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ?
263 	    MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS :
264 	    MC_CMD_FILTER_OP_EXT_IN_RX_MODE_SIMPLE);
265 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_TX_DEST,
266 	    MC_CMD_FILTER_OP_EXT_IN_TX_DEST_DEFAULT);
267 
268 	if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) {
269 		/*
270 		 * NOTE: Unlike most MCDI requests, the filter fields
271 		 * are presented in network (big endian) byte order.
272 		 */
273 		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_MAC),
274 		    spec->efs_rem_mac, EFX_MAC_ADDR_LEN);
275 		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_MAC),
276 		    spec->efs_loc_mac, EFX_MAC_ADDR_LEN);
277 
278 		MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_SRC_PORT,
279 		    __CPU_TO_BE_16(spec->efs_rem_port));
280 		MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_DST_PORT,
281 		    __CPU_TO_BE_16(spec->efs_loc_port));
282 
283 		MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_ETHER_TYPE,
284 		    __CPU_TO_BE_16(spec->efs_ether_type));
285 
286 		MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_INNER_VLAN,
287 		    __CPU_TO_BE_16(spec->efs_inner_vid));
288 		MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_OUTER_VLAN,
289 		    __CPU_TO_BE_16(spec->efs_outer_vid));
290 
291 		/* IP protocol (in low byte, high byte is zero) */
292 		MCDI_IN_SET_BYTE(req, FILTER_OP_EXT_IN_IP_PROTO,
293 		    spec->efs_ip_proto);
294 
295 		EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) ==
296 		    MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN);
297 		EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) ==
298 		    MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
299 
300 		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_IP),
301 		    &spec->efs_rem_host.eo_byte[0],
302 		    MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN);
303 		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_IP),
304 		    &spec->efs_loc_host.eo_byte[0],
305 		    MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN);
306 
307 		/*
308 		 * On Medford, filters for encapsulated packets match based on
309 		 * the ether type and IP protocol in the outer frame.  In
310 		 * addition we need to fill in the VNI or VSID type field.
311 		 */
312 		switch (spec->efs_encap_type) {
313 		case EFX_TUNNEL_PROTOCOL_NONE:
314 			break;
315 		case EFX_TUNNEL_PROTOCOL_VXLAN:
316 		case EFX_TUNNEL_PROTOCOL_GENEVE:
317 			MCDI_IN_POPULATE_DWORD_1(req,
318 			    FILTER_OP_EXT_IN_VNI_OR_VSID,
319 			    FILTER_OP_EXT_IN_VNI_TYPE,
320 			    spec->efs_encap_type == EFX_TUNNEL_PROTOCOL_VXLAN ?
321 				    MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN :
322 				    MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE);
323 			break;
324 		case EFX_TUNNEL_PROTOCOL_NVGRE:
325 			MCDI_IN_POPULATE_DWORD_1(req,
326 			    FILTER_OP_EXT_IN_VNI_OR_VSID,
327 			    FILTER_OP_EXT_IN_VSID_TYPE,
328 			    MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE);
329 			break;
330 		default:
331 			EFSYS_ASSERT(0);
332 			rc = EINVAL;
333 			goto fail2;
334 		}
335 
336 		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_VNI_OR_VSID),
337 		    spec->efs_vni_or_vsid, EFX_VNI_OR_VSID_LEN);
338 
339 		memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_IFRM_DST_MAC),
340 		    spec->efs_ifrm_loc_mac, EFX_MAC_ADDR_LEN);
341 	}
342 
343 	/*
344 	 * Set the "MARK" or "FLAG" action for all packets matching this filter
345 	 * if necessary (only useful with equal stride packed stream Rx mode
346 	 * which provide the information in pseudo-header).
347 	 * These actions require MC_CMD_FILTER_OP_V3_IN msgrequest.
348 	 */
349 	if ((spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) &&
350 	    (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG)) {
351 		rc = EINVAL;
352 		goto fail3;
353 	}
354 	if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_MARK) {
355 		MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_ACTION,
356 		    MC_CMD_FILTER_OP_V3_IN_MATCH_ACTION_MARK);
357 		MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_MARK_VALUE,
358 		    spec->efs_mark);
359 	} else if (spec->efs_flags & EFX_FILTER_FLAG_ACTION_FLAG) {
360 		MCDI_IN_SET_DWORD(req, FILTER_OP_V3_IN_MATCH_ACTION,
361 		    MC_CMD_FILTER_OP_V3_IN_MATCH_ACTION_FLAG);
362 	}
363 
364 	efx_mcdi_execute(enp, &req);
365 
366 	if (req.emr_rc != 0) {
367 		rc = req.emr_rc;
368 		goto fail4;
369 	}
370 
371 	if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
372 		rc = EMSGSIZE;
373 		goto fail5;
374 	}
375 
376 	handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO);
377 	handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_HI);
378 
379 	return (0);
380 
381 fail5:
382 	EFSYS_PROBE(fail5);
383 fail4:
384 	EFSYS_PROBE(fail4);
385 fail3:
386 	EFSYS_PROBE(fail3);
387 fail2:
388 	EFSYS_PROBE(fail2);
389 fail1:
390 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
391 
392 	return (rc);
393 
394 }
395 
396 static	__checkReturn	efx_rc_t
efx_mcdi_filter_op_delete(__in efx_nic_t * enp,__in unsigned int filter_op,__inout ef10_filter_handle_t * handle)397 efx_mcdi_filter_op_delete(
398 	__in		efx_nic_t *enp,
399 	__in		unsigned int filter_op,
400 	__inout		ef10_filter_handle_t *handle)
401 {
402 	efx_mcdi_req_t req;
403 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_EXT_IN_LEN,
404 		MC_CMD_FILTER_OP_EXT_OUT_LEN);
405 	efx_rc_t rc;
406 
407 	req.emr_cmd = MC_CMD_FILTER_OP;
408 	req.emr_in_buf = payload;
409 	req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN;
410 	req.emr_out_buf = payload;
411 	req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN;
412 
413 	switch (filter_op) {
414 	case MC_CMD_FILTER_OP_IN_OP_REMOVE:
415 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP,
416 		    MC_CMD_FILTER_OP_IN_OP_REMOVE);
417 		break;
418 	case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE:
419 		MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP,
420 		    MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE);
421 		break;
422 	default:
423 		EFSYS_ASSERT(0);
424 		rc = EINVAL;
425 		goto fail1;
426 	}
427 
428 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO, handle->efh_lo);
429 	MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI, handle->efh_hi);
430 
431 	efx_mcdi_execute_quiet(enp, &req);
432 
433 	if (req.emr_rc != 0) {
434 		rc = req.emr_rc;
435 		goto fail2;
436 	}
437 
438 	if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) {
439 		rc = EMSGSIZE;
440 		goto fail3;
441 	}
442 
443 	return (0);
444 
445 fail3:
446 	EFSYS_PROBE(fail3);
447 
448 fail2:
449 	EFSYS_PROBE(fail2);
450 fail1:
451 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
452 
453 	return (rc);
454 }
455 
456 static	__checkReturn	boolean_t
ef10_filter_equal(__in const efx_filter_spec_t * left,__in const efx_filter_spec_t * right)457 ef10_filter_equal(
458 	__in		const efx_filter_spec_t *left,
459 	__in		const efx_filter_spec_t *right)
460 {
461 	/* FIXME: Consider rx vs tx filters (look at efs_flags) */
462 	if (left->efs_match_flags != right->efs_match_flags)
463 		return (B_FALSE);
464 	if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host))
465 		return (B_FALSE);
466 	if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host))
467 		return (B_FALSE);
468 	if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN))
469 		return (B_FALSE);
470 	if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN))
471 		return (B_FALSE);
472 	if (left->efs_rem_port != right->efs_rem_port)
473 		return (B_FALSE);
474 	if (left->efs_loc_port != right->efs_loc_port)
475 		return (B_FALSE);
476 	if (left->efs_inner_vid != right->efs_inner_vid)
477 		return (B_FALSE);
478 	if (left->efs_outer_vid != right->efs_outer_vid)
479 		return (B_FALSE);
480 	if (left->efs_ether_type != right->efs_ether_type)
481 		return (B_FALSE);
482 	if (left->efs_ip_proto != right->efs_ip_proto)
483 		return (B_FALSE);
484 	if (left->efs_encap_type != right->efs_encap_type)
485 		return (B_FALSE);
486 	if (memcmp(left->efs_vni_or_vsid, right->efs_vni_or_vsid,
487 	    EFX_VNI_OR_VSID_LEN))
488 		return (B_FALSE);
489 	if (memcmp(left->efs_ifrm_loc_mac, right->efs_ifrm_loc_mac,
490 	    EFX_MAC_ADDR_LEN))
491 		return (B_FALSE);
492 
493 	return (B_TRUE);
494 
495 }
496 
497 static	__checkReturn	boolean_t
ef10_filter_same_dest(__in const efx_filter_spec_t * left,__in const efx_filter_spec_t * right)498 ef10_filter_same_dest(
499 	__in		const efx_filter_spec_t *left,
500 	__in		const efx_filter_spec_t *right)
501 {
502 	if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
503 	    (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) {
504 		if (left->efs_rss_context == right->efs_rss_context)
505 			return (B_TRUE);
506 	} else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) &&
507 	    (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) {
508 		if (left->efs_dmaq_id == right->efs_dmaq_id)
509 			return (B_TRUE);
510 	}
511 	return (B_FALSE);
512 }
513 
514 static	__checkReturn	uint32_t
ef10_filter_hash(__in efx_filter_spec_t * spec)515 ef10_filter_hash(
516 	__in		efx_filter_spec_t *spec)
517 {
518 	EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t))
519 			    == 0);
520 	EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) %
521 			    sizeof (uint32_t)) == 0);
522 
523 	/*
524 	 * As the area of the efx_filter_spec_t we need to hash is DWORD
525 	 * aligned and an exact number of DWORDs in size we can use the
526 	 * optimised efx_hash_dwords() rather than efx_hash_bytes()
527 	 */
528 	return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid,
529 			(sizeof (efx_filter_spec_t) -
530 			EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) /
531 			sizeof (uint32_t), 0));
532 }
533 
534 /*
535  * Decide whether a filter should be exclusive or else should allow
536  * delivery to additional recipients.  Currently we decide that
537  * filters for specific local unicast MAC and IP addresses are
538  * exclusive.
539  */
540 static	__checkReturn	boolean_t
ef10_filter_is_exclusive(__in efx_filter_spec_t * spec)541 ef10_filter_is_exclusive(
542 	__in		efx_filter_spec_t *spec)
543 {
544 	if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) &&
545 	    !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac))
546 		return (B_TRUE);
547 
548 	if ((spec->efs_match_flags &
549 		(EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) ==
550 	    (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) {
551 		if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) &&
552 		    ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe))
553 			return (B_TRUE);
554 		if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) &&
555 		    (spec->efs_loc_host.eo_u8[0] != 0xff))
556 			return (B_TRUE);
557 	}
558 
559 	return (B_FALSE);
560 }
561 
562 	__checkReturn	efx_rc_t
ef10_filter_restore(__in efx_nic_t * enp)563 ef10_filter_restore(
564 	__in		efx_nic_t *enp)
565 {
566 	int tbl_id;
567 	efx_filter_spec_t *spec;
568 	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
569 	boolean_t restoring;
570 	efsys_lock_state_t state;
571 	efx_rc_t rc;
572 
573 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
574 	    enp->en_family == EFX_FAMILY_MEDFORD ||
575 	    enp->en_family == EFX_FAMILY_MEDFORD2);
576 
577 	for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) {
578 		EFSYS_LOCK(enp->en_eslp, state);
579 
580 		spec = ef10_filter_entry_spec(eftp, tbl_id);
581 		if (spec == NULL) {
582 			restoring = B_FALSE;
583 		} else if (ef10_filter_entry_is_busy(eftp, tbl_id)) {
584 			/* Ignore busy entries. */
585 			restoring = B_FALSE;
586 		} else {
587 			ef10_filter_set_entry_busy(eftp, tbl_id);
588 			restoring = B_TRUE;
589 		}
590 
591 		EFSYS_UNLOCK(enp->en_eslp, state);
592 
593 		if (restoring == B_FALSE)
594 			continue;
595 
596 		if (ef10_filter_is_exclusive(spec)) {
597 			rc = efx_mcdi_filter_op_add(enp, spec,
598 			    MC_CMD_FILTER_OP_IN_OP_INSERT,
599 			    &eftp->eft_entry[tbl_id].efe_handle);
600 		} else {
601 			rc = efx_mcdi_filter_op_add(enp, spec,
602 			    MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
603 			    &eftp->eft_entry[tbl_id].efe_handle);
604 		}
605 
606 		if (rc != 0)
607 			goto fail1;
608 
609 		EFSYS_LOCK(enp->en_eslp, state);
610 
611 		ef10_filter_set_entry_not_busy(eftp, tbl_id);
612 
613 		EFSYS_UNLOCK(enp->en_eslp, state);
614 	}
615 
616 	return (0);
617 
618 fail1:
619 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
620 
621 	return (rc);
622 }
623 
624 /*
625  * An arbitrary search limit for the software hash table. As per the linux net
626  * driver.
627  */
628 #define	EF10_FILTER_SEARCH_LIMIT 200
629 
630 static	__checkReturn	efx_rc_t
ef10_filter_add_internal(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec,__in boolean_t may_replace,__out_opt uint32_t * filter_id)631 ef10_filter_add_internal(
632 	__in		efx_nic_t *enp,
633 	__inout		efx_filter_spec_t *spec,
634 	__in		boolean_t may_replace,
635 	__out_opt	uint32_t *filter_id)
636 {
637 	efx_rc_t rc;
638 	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
639 	efx_filter_spec_t *saved_spec;
640 	uint32_t hash;
641 	unsigned int depth;
642 	int ins_index;
643 	boolean_t replacing = B_FALSE;
644 	unsigned int i;
645 	efsys_lock_state_t state;
646 	boolean_t locked = B_FALSE;
647 
648 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
649 	    enp->en_family == EFX_FAMILY_MEDFORD ||
650 	    enp->en_family == EFX_FAMILY_MEDFORD2);
651 
652 	hash = ef10_filter_hash(spec);
653 
654 	/*
655 	 * FIXME: Add support for inserting filters of different priorities
656 	 * and removing lower priority multicast filters (bug 42378)
657 	 */
658 
659 	/*
660 	 * Find any existing filters with the same match tuple or
661 	 * else a free slot to insert at.  If any of them are busy,
662 	 * we have to wait and retry.
663 	 */
664 	for (;;) {
665 		ins_index = -1;
666 		depth = 1;
667 		EFSYS_LOCK(enp->en_eslp, state);
668 		locked = B_TRUE;
669 
670 		for (;;) {
671 			i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
672 			saved_spec = ef10_filter_entry_spec(eftp, i);
673 
674 			if (!saved_spec) {
675 				if (ins_index < 0) {
676 					ins_index = i;
677 				}
678 			} else if (ef10_filter_equal(spec, saved_spec)) {
679 				if (ef10_filter_entry_is_busy(eftp, i))
680 					break;
681 				if (saved_spec->efs_priority
682 					    == EFX_FILTER_PRI_AUTO) {
683 					ins_index = i;
684 					goto found;
685 				} else if (ef10_filter_is_exclusive(spec)) {
686 					if (may_replace) {
687 						ins_index = i;
688 						goto found;
689 					} else {
690 						rc = EEXIST;
691 						goto fail1;
692 					}
693 				}
694 
695 				/* Leave existing */
696 			}
697 
698 			/*
699 			 * Once we reach the maximum search depth, use
700 			 * the first suitable slot or return EBUSY if
701 			 * there was none.
702 			 */
703 			if (depth == EF10_FILTER_SEARCH_LIMIT) {
704 				if (ins_index < 0) {
705 					rc = EBUSY;
706 					goto fail2;
707 				}
708 				goto found;
709 			}
710 			depth++;
711 		}
712 		EFSYS_UNLOCK(enp->en_eslp, state);
713 		locked = B_FALSE;
714 	}
715 
716 found:
717 	/*
718 	 * Create a software table entry if necessary, and mark it
719 	 * busy.  We might yet fail to insert, but any attempt to
720 	 * insert a conflicting filter while we're waiting for the
721 	 * firmware must find the busy entry.
722 	 */
723 	saved_spec = ef10_filter_entry_spec(eftp, ins_index);
724 	if (saved_spec) {
725 		if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) {
726 			/* This is a filter we are refreshing */
727 			ef10_filter_set_entry_not_auto_old(eftp, ins_index);
728 			goto out_unlock;
729 		}
730 		replacing = B_TRUE;
731 	} else {
732 		EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec);
733 		if (!saved_spec) {
734 			rc = ENOMEM;
735 			goto fail3;
736 		}
737 		*saved_spec = *spec;
738 		ef10_filter_set_entry(eftp, ins_index, saved_spec);
739 	}
740 	ef10_filter_set_entry_busy(eftp, ins_index);
741 
742 	EFSYS_UNLOCK(enp->en_eslp, state);
743 	locked = B_FALSE;
744 
745 	/*
746 	 * On replacing the filter handle may change after after a successful
747 	 * replace operation.
748 	 */
749 	if (replacing) {
750 		rc = efx_mcdi_filter_op_add(enp, spec,
751 		    MC_CMD_FILTER_OP_IN_OP_REPLACE,
752 		    &eftp->eft_entry[ins_index].efe_handle);
753 	} else if (ef10_filter_is_exclusive(spec)) {
754 		rc = efx_mcdi_filter_op_add(enp, spec,
755 		    MC_CMD_FILTER_OP_IN_OP_INSERT,
756 		    &eftp->eft_entry[ins_index].efe_handle);
757 	} else {
758 		rc = efx_mcdi_filter_op_add(enp, spec,
759 		    MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE,
760 		    &eftp->eft_entry[ins_index].efe_handle);
761 	}
762 
763 	if (rc != 0)
764 		goto fail4;
765 
766 	EFSYS_LOCK(enp->en_eslp, state);
767 	locked = B_TRUE;
768 
769 	if (replacing) {
770 		/* Update the fields that may differ */
771 		saved_spec->efs_priority = spec->efs_priority;
772 		saved_spec->efs_flags = spec->efs_flags;
773 		saved_spec->efs_rss_context = spec->efs_rss_context;
774 		saved_spec->efs_dmaq_id = spec->efs_dmaq_id;
775 	}
776 
777 	ef10_filter_set_entry_not_busy(eftp, ins_index);
778 
779 out_unlock:
780 
781 	EFSYS_UNLOCK(enp->en_eslp, state);
782 	locked = B_FALSE;
783 
784 	if (filter_id)
785 		*filter_id = ins_index;
786 
787 	return (0);
788 
789 fail4:
790 	EFSYS_PROBE(fail4);
791 
792 	if (!replacing) {
793 		EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec);
794 		saved_spec = NULL;
795 	}
796 	ef10_filter_set_entry_not_busy(eftp, ins_index);
797 	ef10_filter_set_entry(eftp, ins_index, NULL);
798 
799 fail3:
800 	EFSYS_PROBE(fail3);
801 
802 fail2:
803 	EFSYS_PROBE(fail2);
804 
805 fail1:
806 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
807 
808 	if (locked)
809 		EFSYS_UNLOCK(enp->en_eslp, state);
810 
811 	return (rc);
812 }
813 
814 	__checkReturn	efx_rc_t
ef10_filter_add(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec,__in boolean_t may_replace)815 ef10_filter_add(
816 	__in		efx_nic_t *enp,
817 	__inout		efx_filter_spec_t *spec,
818 	__in		boolean_t may_replace)
819 {
820 	efx_rc_t rc;
821 
822 	rc = ef10_filter_add_internal(enp, spec, may_replace, NULL);
823 	if (rc != 0)
824 		goto fail1;
825 
826 	return (0);
827 
828 fail1:
829 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
830 
831 	return (rc);
832 }
833 
834 static	__checkReturn	efx_rc_t
ef10_filter_delete_internal(__in efx_nic_t * enp,__in uint32_t filter_id)835 ef10_filter_delete_internal(
836 	__in		efx_nic_t *enp,
837 	__in		uint32_t filter_id)
838 {
839 	efx_rc_t rc;
840 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
841 	efx_filter_spec_t *spec;
842 	efsys_lock_state_t state;
843 	uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS;
844 
845 	/*
846 	 * Find the software table entry and mark it busy.  Don't
847 	 * remove it yet; any attempt to update while we're waiting
848 	 * for the firmware must find the busy entry.
849 	 *
850 	 * FIXME: What if the busy flag is never cleared?
851 	 */
852 	EFSYS_LOCK(enp->en_eslp, state);
853 	while (ef10_filter_entry_is_busy(table, filter_idx)) {
854 		EFSYS_UNLOCK(enp->en_eslp, state);
855 		EFSYS_SPIN(1);
856 		EFSYS_LOCK(enp->en_eslp, state);
857 	}
858 	if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) {
859 		ef10_filter_set_entry_busy(table, filter_idx);
860 	}
861 	EFSYS_UNLOCK(enp->en_eslp, state);
862 
863 	if (spec == NULL) {
864 		rc = ENOENT;
865 		goto fail1;
866 	}
867 
868 	/*
869 	 * Try to remove the hardware filter. This may fail if the MC has
870 	 * rebooted (which frees all hardware filter resources).
871 	 */
872 	if (ef10_filter_is_exclusive(spec)) {
873 		rc = efx_mcdi_filter_op_delete(enp,
874 		    MC_CMD_FILTER_OP_IN_OP_REMOVE,
875 		    &table->eft_entry[filter_idx].efe_handle);
876 	} else {
877 		rc = efx_mcdi_filter_op_delete(enp,
878 		    MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE,
879 		    &table->eft_entry[filter_idx].efe_handle);
880 	}
881 
882 	/* Free the software table entry */
883 	EFSYS_LOCK(enp->en_eslp, state);
884 	ef10_filter_set_entry_not_busy(table, filter_idx);
885 	ef10_filter_set_entry(table, filter_idx, NULL);
886 	EFSYS_UNLOCK(enp->en_eslp, state);
887 
888 	EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec);
889 
890 	/* Check result of hardware filter removal */
891 	if (rc != 0)
892 		goto fail2;
893 
894 	return (0);
895 
896 fail2:
897 	EFSYS_PROBE(fail2);
898 
899 fail1:
900 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
901 
902 	return (rc);
903 }
904 
905 	__checkReturn	efx_rc_t
ef10_filter_delete(__in efx_nic_t * enp,__inout efx_filter_spec_t * spec)906 ef10_filter_delete(
907 	__in		efx_nic_t *enp,
908 	__inout		efx_filter_spec_t *spec)
909 {
910 	efx_rc_t rc;
911 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
912 	efx_filter_spec_t *saved_spec;
913 	unsigned int hash;
914 	unsigned int depth;
915 	unsigned int i;
916 	efsys_lock_state_t state;
917 	boolean_t locked = B_FALSE;
918 
919 	EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON ||
920 	    enp->en_family == EFX_FAMILY_MEDFORD ||
921 	    enp->en_family == EFX_FAMILY_MEDFORD2);
922 
923 	hash = ef10_filter_hash(spec);
924 
925 	EFSYS_LOCK(enp->en_eslp, state);
926 	locked = B_TRUE;
927 
928 	depth = 1;
929 	for (;;) {
930 		i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1);
931 		saved_spec = ef10_filter_entry_spec(table, i);
932 		if (saved_spec && ef10_filter_equal(spec, saved_spec) &&
933 		    ef10_filter_same_dest(spec, saved_spec)) {
934 			break;
935 		}
936 		if (depth == EF10_FILTER_SEARCH_LIMIT) {
937 			rc = ENOENT;
938 			goto fail1;
939 		}
940 		depth++;
941 	}
942 
943 	EFSYS_UNLOCK(enp->en_eslp, state);
944 	locked = B_FALSE;
945 
946 	rc = ef10_filter_delete_internal(enp, i);
947 	if (rc != 0)
948 		goto fail2;
949 
950 	return (0);
951 
952 fail2:
953 	EFSYS_PROBE(fail2);
954 
955 fail1:
956 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
957 
958 	if (locked)
959 		EFSYS_UNLOCK(enp->en_eslp, state);
960 
961 	return (rc);
962 }
963 
964 static	__checkReturn	efx_rc_t
efx_mcdi_get_parser_disp_info(__in efx_nic_t * enp,__out_ecount (buffer_length)uint32_t * buffer,__in size_t buffer_length,__in boolean_t encap,__out size_t * list_lengthp)965 efx_mcdi_get_parser_disp_info(
966 	__in				efx_nic_t *enp,
967 	__out_ecount(buffer_length)	uint32_t *buffer,
968 	__in				size_t buffer_length,
969 	__in				boolean_t encap,
970 	__out				size_t *list_lengthp)
971 {
972 	efx_mcdi_req_t req;
973 	EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PARSER_DISP_INFO_IN_LEN,
974 		MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX);
975 	size_t matches_count;
976 	size_t list_size;
977 	efx_rc_t rc;
978 
979 	req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO;
980 	req.emr_in_buf = payload;
981 	req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN;
982 	req.emr_out_buf = payload;
983 	req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX;
984 
985 	MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, encap ?
986 	    MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_ENCAP_RX_MATCHES :
987 	    MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES);
988 
989 	efx_mcdi_execute(enp, &req);
990 
991 	if (req.emr_rc != 0) {
992 		rc = req.emr_rc;
993 		goto fail1;
994 	}
995 
996 	matches_count = MCDI_OUT_DWORD(req,
997 	    GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES);
998 
999 	if (req.emr_out_length_used <
1000 	    MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) {
1001 		rc = EMSGSIZE;
1002 		goto fail2;
1003 	}
1004 
1005 	*list_lengthp = matches_count;
1006 
1007 	if (buffer_length < matches_count) {
1008 		rc = ENOSPC;
1009 		goto fail3;
1010 	}
1011 
1012 	/*
1013 	 * Check that the elements in the list in the MCDI response are the size
1014 	 * we expect, so we can just copy them directly. Any conversion of the
1015 	 * flags is handled by the caller.
1016 	 */
1017 	EFX_STATIC_ASSERT(sizeof (uint32_t) ==
1018 	    MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN);
1019 
1020 	list_size = matches_count *
1021 		MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN;
1022 	memcpy(buffer,
1023 	    MCDI_OUT2(req, uint32_t,
1024 		    GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES),
1025 	    list_size);
1026 
1027 	return (0);
1028 
1029 fail3:
1030 	EFSYS_PROBE(fail3);
1031 fail2:
1032 	EFSYS_PROBE(fail2);
1033 fail1:
1034 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1035 
1036 	return (rc);
1037 }
1038 
1039 	__checkReturn	efx_rc_t
ef10_filter_supported_filters(__in efx_nic_t * enp,__out_ecount (buffer_length)uint32_t * buffer,__in size_t buffer_length,__out size_t * list_lengthp)1040 ef10_filter_supported_filters(
1041 	__in				efx_nic_t *enp,
1042 	__out_ecount(buffer_length)	uint32_t *buffer,
1043 	__in				size_t buffer_length,
1044 	__out				size_t *list_lengthp)
1045 {
1046 	efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
1047 	size_t mcdi_list_length;
1048 	size_t mcdi_encap_list_length;
1049 	size_t list_length;
1050 	uint32_t i;
1051 	uint32_t next_buf_idx;
1052 	size_t next_buf_length;
1053 	efx_rc_t rc;
1054 	boolean_t no_space = B_FALSE;
1055 	efx_filter_match_flags_t all_filter_flags =
1056 	    (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST |
1057 	    EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT |
1058 	    EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT |
1059 	    EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID |
1060 	    EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO |
1061 	    EFX_FILTER_MATCH_VNI_OR_VSID |
1062 	    EFX_FILTER_MATCH_IFRM_LOC_MAC |
1063 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST |
1064 	    EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST |
1065 	    EFX_FILTER_MATCH_ENCAP_TYPE |
1066 	    EFX_FILTER_MATCH_UNKNOWN_MCAST_DST |
1067 	    EFX_FILTER_MATCH_UNKNOWN_UCAST_DST);
1068 
1069 	/*
1070 	 * Two calls to MC_CMD_GET_PARSER_DISP_INFO are needed: one to get the
1071 	 * list of supported filters for ordinary packets, and then another to
1072 	 * get the list of supported filters for encapsulated packets. To
1073 	 * distinguish the second list from the first, the
1074 	 * EFX_FILTER_MATCH_ENCAP_TYPE flag is added to each filter for
1075 	 * encapsulated packets.
1076 	 */
1077 	rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, B_FALSE,
1078 	    &mcdi_list_length);
1079 	if (rc != 0) {
1080 		if (rc == ENOSPC)
1081 			no_space = B_TRUE;
1082 		else
1083 			goto fail1;
1084 	}
1085 
1086 	if (no_space) {
1087 		next_buf_idx = 0;
1088 		next_buf_length = 0;
1089 	} else {
1090 		EFSYS_ASSERT(mcdi_list_length <= buffer_length);
1091 		next_buf_idx = mcdi_list_length;
1092 		next_buf_length = buffer_length - mcdi_list_length;
1093 	}
1094 
1095 	if (encp->enc_tunnel_encapsulations_supported != 0) {
1096 		rc = efx_mcdi_get_parser_disp_info(enp, &buffer[next_buf_idx],
1097 		    next_buf_length, B_TRUE, &mcdi_encap_list_length);
1098 		if (rc != 0) {
1099 			if (rc == ENOSPC)
1100 				no_space = B_TRUE;
1101 			else
1102 				goto fail2;
1103 		} else {
1104 			for (i = next_buf_idx;
1105 			    i < next_buf_idx + mcdi_encap_list_length; i++)
1106 				buffer[i] |= EFX_FILTER_MATCH_ENCAP_TYPE;
1107 		}
1108 	} else {
1109 		mcdi_encap_list_length = 0;
1110 	}
1111 
1112 	if (no_space) {
1113 		*list_lengthp = mcdi_list_length + mcdi_encap_list_length;
1114 		rc = ENOSPC;
1115 		goto fail3;
1116 	}
1117 
1118 	/*
1119 	 * The static assertions in ef10_filter_init() ensure that the values of
1120 	 * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't
1121 	 * need to be converted.
1122 	 *
1123 	 * In case support is added to MCDI for additional flags, remove any
1124 	 * matches from the list which include flags we don't support. The order
1125 	 * of the matches is preserved as they are ordered from highest to
1126 	 * lowest priority.
1127 	 */
1128 	EFSYS_ASSERT(mcdi_list_length + mcdi_encap_list_length <=
1129 	    buffer_length);
1130 	list_length = 0;
1131 	for (i = 0; i < mcdi_list_length + mcdi_encap_list_length; i++) {
1132 		if ((buffer[i] & ~all_filter_flags) == 0) {
1133 			buffer[list_length] = buffer[i];
1134 			list_length++;
1135 		}
1136 	}
1137 
1138 	*list_lengthp = list_length;
1139 
1140 	return (0);
1141 
1142 fail3:
1143 	EFSYS_PROBE(fail3);
1144 fail2:
1145 	EFSYS_PROBE(fail2);
1146 fail1:
1147 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1148 
1149 	return (rc);
1150 }
1151 
1152 static	__checkReturn	efx_rc_t
1153 ef10_filter_insert_unicast(
1154 	__in				efx_nic_t *enp,
1155 	__in_ecount(6)			uint8_t const *addr,
1156 	__in				efx_filter_flags_t filter_flags)
1157 {
1158 	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1159 	efx_filter_spec_t spec;
1160 	efx_rc_t rc;
1161 
1162 	/* Insert the filter for the local station address */
1163 	efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1164 	    filter_flags,
1165 	    eftp->eft_default_rxq);
1166 	rc = efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC,
1167 	    addr);
1168 	if (rc != 0)
1169 		goto fail1;
1170 
1171 	rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1172 	    &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1173 	if (rc != 0)
1174 		goto fail2;
1175 
1176 	eftp->eft_unicst_filter_count++;
1177 	EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1178 		    EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1179 
1180 	return (0);
1181 
1182 fail2:
1183 	EFSYS_PROBE(fail2);
1184 fail1:
1185 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1186 	return (rc);
1187 }
1188 
1189 static	__checkReturn	efx_rc_t
ef10_filter_insert_all_unicast(__in efx_nic_t * enp,__in efx_filter_flags_t filter_flags)1190 ef10_filter_insert_all_unicast(
1191 	__in				efx_nic_t *enp,
1192 	__in				efx_filter_flags_t filter_flags)
1193 {
1194 	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1195 	efx_filter_spec_t spec;
1196 	efx_rc_t rc;
1197 
1198 	/* Insert the unknown unicast filter */
1199 	efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1200 	    filter_flags,
1201 	    eftp->eft_default_rxq);
1202 	rc = efx_filter_spec_set_uc_def(&spec);
1203 	if (rc != 0)
1204 		goto fail1;
1205 	rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1206 	    &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]);
1207 	if (rc != 0)
1208 		goto fail2;
1209 
1210 	eftp->eft_unicst_filter_count++;
1211 	EFSYS_ASSERT(eftp->eft_unicst_filter_count <=
1212 		    EFX_EF10_FILTER_UNICAST_FILTERS_MAX);
1213 
1214 	return (0);
1215 
1216 fail2:
1217 	EFSYS_PROBE(fail2);
1218 fail1:
1219 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1220 	return (rc);
1221 }
1222 
1223 static	__checkReturn	efx_rc_t
1224 ef10_filter_insert_multicast_list(
1225 	__in				efx_nic_t *enp,
1226 	__in				boolean_t mulcst,
1227 	__in				boolean_t brdcst,
1228 	__in_ecount(6*count)		uint8_t const *addrs,
1229 	__in				uint32_t count,
1230 	__in				efx_filter_flags_t filter_flags,
1231 	__in				boolean_t rollback)
1232 {
1233 	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1234 	efx_filter_spec_t spec;
1235 	uint8_t addr[6];
1236 	uint32_t i;
1237 	uint32_t filter_index;
1238 	uint32_t filter_count;
1239 	efx_rc_t rc;
1240 
1241 	if (mulcst == B_FALSE)
1242 		count = 0;
1243 
1244 	if (count + (brdcst ? 1 : 0) >
1245 	    EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) {
1246 		/* Too many MAC addresses */
1247 		rc = EINVAL;
1248 		goto fail1;
1249 	}
1250 
1251 	/* Insert/renew multicast address list filters */
1252 	filter_count = 0;
1253 	for (i = 0; i < count; i++) {
1254 		efx_filter_spec_init_rx(&spec,
1255 		    EFX_FILTER_PRI_AUTO,
1256 		    filter_flags,
1257 		    eftp->eft_default_rxq);
1258 
1259 		rc = efx_filter_spec_set_eth_local(&spec,
1260 		    EFX_FILTER_SPEC_VID_UNSPEC,
1261 		    &addrs[i * EFX_MAC_ADDR_LEN]);
1262 		if (rc != 0) {
1263 			if (rollback == B_TRUE) {
1264 				/* Only stop upon failure if told to rollback */
1265 				goto rollback;
1266 			} else {
1267 				/*
1268 				 * Don't try to add a filter with a corrupt
1269 				 * specification.
1270 				 */
1271 				continue;
1272 			}
1273 		}
1274 
1275 		rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1276 					    &filter_index);
1277 
1278 		if (rc == 0) {
1279 			eftp->eft_mulcst_filter_indexes[filter_count] =
1280 				filter_index;
1281 			filter_count++;
1282 		} else if (rollback == B_TRUE) {
1283 			/* Only stop upon failure if told to rollback */
1284 			goto rollback;
1285 		}
1286 	}
1287 
1288 	if (brdcst == B_TRUE) {
1289 		/* Insert/renew broadcast address filter */
1290 		efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1291 		    filter_flags,
1292 		    eftp->eft_default_rxq);
1293 
1294 		EFX_MAC_BROADCAST_ADDR_SET(addr);
1295 		rc = efx_filter_spec_set_eth_local(&spec,
1296 		    EFX_FILTER_SPEC_VID_UNSPEC, addr);
1297 		if ((rc != 0) && (rollback == B_TRUE)) {
1298 			/* Only stop upon failure if told to rollback */
1299 			goto rollback;
1300 		}
1301 
1302 		rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1303 					    &filter_index);
1304 
1305 		if (rc == 0) {
1306 			eftp->eft_mulcst_filter_indexes[filter_count] =
1307 				filter_index;
1308 			filter_count++;
1309 		} else if (rollback == B_TRUE) {
1310 			/* Only stop upon failure if told to rollback */
1311 			goto rollback;
1312 		}
1313 	}
1314 
1315 	eftp->eft_mulcst_filter_count = filter_count;
1316 	eftp->eft_using_all_mulcst = B_FALSE;
1317 
1318 	return (0);
1319 
1320 rollback:
1321 	/* Remove any filters we have inserted */
1322 	i = filter_count;
1323 	while (i--) {
1324 		(void) ef10_filter_delete_internal(enp,
1325 		    eftp->eft_mulcst_filter_indexes[i]);
1326 	}
1327 	eftp->eft_mulcst_filter_count = 0;
1328 
1329 fail1:
1330 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1331 
1332 	return (rc);
1333 }
1334 
1335 static	__checkReturn	efx_rc_t
ef10_filter_insert_all_multicast(__in efx_nic_t * enp,__in efx_filter_flags_t filter_flags)1336 ef10_filter_insert_all_multicast(
1337 	__in				efx_nic_t *enp,
1338 	__in				efx_filter_flags_t filter_flags)
1339 {
1340 	ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table;
1341 	efx_filter_spec_t spec;
1342 	efx_rc_t rc;
1343 
1344 	/* Insert the unknown multicast filter */
1345 	efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1346 	    filter_flags,
1347 	    eftp->eft_default_rxq);
1348 	rc = efx_filter_spec_set_mc_def(&spec);
1349 	if (rc != 0)
1350 		goto fail1;
1351 
1352 	rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1353 	    &eftp->eft_mulcst_filter_indexes[0]);
1354 	if (rc != 0)
1355 		goto fail2;
1356 
1357 	eftp->eft_mulcst_filter_count = 1;
1358 	eftp->eft_using_all_mulcst = B_TRUE;
1359 
1360 	/*
1361 	 * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic.
1362 	 */
1363 
1364 	return (0);
1365 
1366 fail2:
1367 	EFSYS_PROBE(fail2);
1368 fail1:
1369 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1370 
1371 	return (rc);
1372 }
1373 
1374 typedef struct ef10_filter_encap_entry_s {
1375 	uint16_t		ether_type;
1376 	efx_tunnel_protocol_t	encap_type;
1377 	uint32_t		inner_frame_match;
1378 } ef10_filter_encap_entry_t;
1379 
1380 #define	EF10_ENCAP_FILTER_ENTRY(ipv, encap_type, inner_frame_match)	\
1381 	{ EFX_ETHER_TYPE_##ipv, EFX_TUNNEL_PROTOCOL_##encap_type,	\
1382 	    EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_##inner_frame_match }
1383 
1384 static ef10_filter_encap_entry_t ef10_filter_encap_list[] = {
1385 	EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, UCAST_DST),
1386 	EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, MCAST_DST),
1387 	EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, UCAST_DST),
1388 	EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, MCAST_DST),
1389 
1390 	EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, UCAST_DST),
1391 	EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, MCAST_DST),
1392 	EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, UCAST_DST),
1393 	EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, MCAST_DST),
1394 
1395 	EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, UCAST_DST),
1396 	EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, MCAST_DST),
1397 	EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, UCAST_DST),
1398 	EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, MCAST_DST),
1399 };
1400 
1401 #undef EF10_ENCAP_FILTER_ENTRY
1402 
1403 static	__checkReturn	efx_rc_t
ef10_filter_insert_encap_filters(__in efx_nic_t * enp,__in boolean_t mulcst,__in efx_filter_flags_t filter_flags)1404 ef10_filter_insert_encap_filters(
1405 	__in		efx_nic_t *enp,
1406 	__in		boolean_t mulcst,
1407 	__in		efx_filter_flags_t filter_flags)
1408 {
1409 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1410 	uint32_t i;
1411 	efx_rc_t rc;
1412 
1413 	EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(ef10_filter_encap_list) <=
1414 			    EFX_ARRAY_SIZE(table->eft_encap_filter_indexes));
1415 
1416 	/*
1417 	 * On Medford, full-featured firmware can identify packets as being
1418 	 * tunnel encapsulated, even if no encapsulated packet offloads are in
1419 	 * use. When packets are identified as such, ordinary filters are not
1420 	 * applied, only ones specific to encapsulated packets. Hence we need to
1421 	 * insert filters for encapsulated packets in order to receive them.
1422 	 *
1423 	 * Separate filters need to be inserted for each ether type,
1424 	 * encapsulation type, and inner frame type (unicast or multicast). To
1425 	 * keep things simple and reduce the number of filters needed, catch-all
1426 	 * filters for all combinations of types are inserted, even if
1427 	 * all_unicst or all_mulcst have not been set. (These catch-all filters
1428 	 * may well, however, fail to insert on unprivileged functions.)
1429 	 */
1430 	table->eft_encap_filter_count = 0;
1431 	for (i = 0; i < EFX_ARRAY_SIZE(ef10_filter_encap_list); i++) {
1432 		efx_filter_spec_t spec;
1433 		ef10_filter_encap_entry_t *encap_filter =
1434 			&ef10_filter_encap_list[i];
1435 
1436 		/*
1437 		 * Skip multicast filters if we've not been asked for
1438 		 * any multicast traffic.
1439 		 */
1440 		if ((mulcst == B_FALSE) &&
1441 		    (encap_filter->inner_frame_match ==
1442 		    EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST))
1443 			continue;
1444 
1445 		efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO,
1446 					filter_flags,
1447 					table->eft_default_rxq);
1448 		efx_filter_spec_set_ether_type(&spec, encap_filter->ether_type);
1449 		rc = efx_filter_spec_set_encap_type(&spec,
1450 					    encap_filter->encap_type,
1451 					    encap_filter->inner_frame_match);
1452 		if (rc != 0)
1453 			goto fail1;
1454 
1455 		rc = ef10_filter_add_internal(enp, &spec, B_TRUE,
1456 			    &table->eft_encap_filter_indexes[
1457 				    table->eft_encap_filter_count]);
1458 		if (rc != 0) {
1459 			if (rc != EACCES)
1460 				goto fail2;
1461 		} else {
1462 			table->eft_encap_filter_count++;
1463 		}
1464 	}
1465 
1466 	return (0);
1467 
1468 fail2:
1469 	EFSYS_PROBE(fail2);
1470 fail1:
1471 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1472 
1473 	return (rc);
1474 }
1475 
1476 static			void
ef10_filter_remove_old(__in efx_nic_t * enp)1477 ef10_filter_remove_old(
1478 	__in		efx_nic_t *enp)
1479 {
1480 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1481 	uint32_t i;
1482 
1483 	for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1484 		if (ef10_filter_entry_is_auto_old(table, i)) {
1485 			(void) ef10_filter_delete_internal(enp, i);
1486 		}
1487 	}
1488 }
1489 
1490 static	__checkReturn	efx_rc_t
ef10_filter_get_workarounds(__in efx_nic_t * enp)1491 ef10_filter_get_workarounds(
1492 	__in				efx_nic_t *enp)
1493 {
1494 	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1495 	uint32_t implemented = 0;
1496 	uint32_t enabled = 0;
1497 	efx_rc_t rc;
1498 
1499 	rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled);
1500 	if (rc == 0) {
1501 		/* Check if chained multicast filter support is enabled */
1502 		if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807)
1503 			encp->enc_bug26807_workaround = B_TRUE;
1504 		else
1505 			encp->enc_bug26807_workaround = B_FALSE;
1506 	} else if (rc == ENOTSUP) {
1507 		/*
1508 		 * Firmware is too old to support GET_WORKAROUNDS, and support
1509 		 * for this workaround was implemented later.
1510 		 */
1511 		encp->enc_bug26807_workaround = B_FALSE;
1512 	} else {
1513 		goto fail1;
1514 	}
1515 
1516 	return (0);
1517 
1518 fail1:
1519 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1520 
1521 	return (rc);
1522 
1523 }
1524 
1525 /*
1526  * Reconfigure all filters.
1527  * If all_unicst and/or all mulcst filters cannot be applied then
1528  * return ENOTSUP (Note the filters for the specified addresses are
1529  * still applied in this case).
1530  */
1531 	__checkReturn	efx_rc_t
1532 ef10_filter_reconfigure(
1533 	__in				efx_nic_t *enp,
1534 	__in_ecount(6)			uint8_t const *mac_addr,
1535 	__in				boolean_t all_unicst,
1536 	__in				boolean_t mulcst,
1537 	__in				boolean_t all_mulcst,
1538 	__in				boolean_t brdcst,
1539 	__in_ecount(6*count)		uint8_t const *addrs,
1540 	__in				uint32_t count)
1541 {
1542 	efx_nic_cfg_t *encp = &enp->en_nic_cfg;
1543 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1544 	efx_filter_flags_t filter_flags;
1545 	unsigned int i;
1546 	efx_rc_t all_unicst_rc = 0;
1547 	efx_rc_t all_mulcst_rc = 0;
1548 	efx_rc_t rc;
1549 
1550 	if (table->eft_default_rxq == NULL) {
1551 		/*
1552 		 * Filters direct traffic to the default RXQ, and so cannot be
1553 		 * inserted until it is available. Any currently configured
1554 		 * filters must be removed (ignore errors in case the MC
1555 		 * has rebooted, which removes hardware filters).
1556 		 */
1557 		for (i = 0; i < table->eft_unicst_filter_count; i++) {
1558 			(void) ef10_filter_delete_internal(enp,
1559 					table->eft_unicst_filter_indexes[i]);
1560 		}
1561 		table->eft_unicst_filter_count = 0;
1562 
1563 		for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1564 			(void) ef10_filter_delete_internal(enp,
1565 					table->eft_mulcst_filter_indexes[i]);
1566 		}
1567 		table->eft_mulcst_filter_count = 0;
1568 
1569 		for (i = 0; i < table->eft_encap_filter_count; i++) {
1570 			(void) ef10_filter_delete_internal(enp,
1571 					table->eft_encap_filter_indexes[i]);
1572 		}
1573 		table->eft_encap_filter_count = 0;
1574 
1575 		return (0);
1576 	}
1577 
1578 	if (table->eft_using_rss)
1579 		filter_flags = EFX_FILTER_FLAG_RX_RSS;
1580 	else
1581 		filter_flags = 0;
1582 
1583 	/* Mark old filters which may need to be removed */
1584 	for (i = 0; i < table->eft_unicst_filter_count; i++) {
1585 		ef10_filter_set_entry_auto_old(table,
1586 					table->eft_unicst_filter_indexes[i]);
1587 	}
1588 	for (i = 0; i < table->eft_mulcst_filter_count; i++) {
1589 		ef10_filter_set_entry_auto_old(table,
1590 					table->eft_mulcst_filter_indexes[i]);
1591 	}
1592 	for (i = 0; i < table->eft_encap_filter_count; i++) {
1593 		ef10_filter_set_entry_auto_old(table,
1594 					table->eft_encap_filter_indexes[i]);
1595 	}
1596 
1597 	/*
1598 	 * Insert or renew unicast filters.
1599 	 *
1600 	 * Firmware does not perform chaining on unicast filters. As traffic is
1601 	 * therefore only delivered to the first matching filter, we should
1602 	 * always insert the specific filter for our MAC address, to try and
1603 	 * ensure we get that traffic.
1604 	 *
1605 	 * (If the filter for our MAC address has already been inserted by
1606 	 * another function, we won't receive traffic sent to us, even if we
1607 	 * insert a unicast mismatch filter. To prevent traffic stealing, this
1608 	 * therefore relies on the privilege model only allowing functions to
1609 	 * insert filters for their own MAC address unless explicitly given
1610 	 * additional privileges by the user. This also means that, even on a
1611 	 * priviliged function, inserting a unicast mismatch filter may not
1612 	 * catch all traffic in multi PCI function scenarios.)
1613 	 */
1614 	table->eft_unicst_filter_count = 0;
1615 	rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags);
1616 	if (all_unicst || (rc != 0)) {
1617 		all_unicst_rc = ef10_filter_insert_all_unicast(enp,
1618 						    filter_flags);
1619 		if ((rc != 0) && (all_unicst_rc != 0))
1620 			goto fail1;
1621 	}
1622 
1623 	/*
1624 	 * WORKAROUND_BUG26807 controls firmware support for chained multicast
1625 	 * filters, and can only be enabled or disabled when the hardware filter
1626 	 * table is empty.
1627 	 *
1628 	 * Chained multicast filters require support from the datapath firmware,
1629 	 * and may not be available (e.g. low-latency variants or old Huntington
1630 	 * firmware).
1631 	 *
1632 	 * Firmware will reset (FLR) functions which have inserted filters in
1633 	 * the hardware filter table when the workaround is enabled/disabled.
1634 	 * Functions without any hardware filters are not reset.
1635 	 *
1636 	 * Re-check if the workaround is enabled after adding unicast hardware
1637 	 * filters. This ensures that encp->enc_bug26807_workaround matches the
1638 	 * firmware state, and that later changes to enable/disable the
1639 	 * workaround will result in this function seeing a reset (FLR).
1640 	 *
1641 	 * In common-code drivers, we only support multiple PCI function
1642 	 * scenarios with firmware that supports multicast chaining, so we can
1643 	 * assume it is enabled for such cases and hence simplify the filter
1644 	 * insertion logic. Firmware that does not support multicast chaining
1645 	 * does not support multiple PCI function configurations either, so
1646 	 * filter insertion is much simpler and the same strategies can still be
1647 	 * used.
1648 	 */
1649 	if ((rc = ef10_filter_get_workarounds(enp)) != 0)
1650 		goto fail2;
1651 
1652 	if ((table->eft_using_all_mulcst != all_mulcst) &&
1653 	    (encp->enc_bug26807_workaround == B_TRUE)) {
1654 		/*
1655 		 * Multicast filter chaining is enabled, so traffic that matches
1656 		 * more than one multicast filter will be replicated and
1657 		 * delivered to multiple recipients.  To avoid this duplicate
1658 		 * delivery, remove old multicast filters before inserting new
1659 		 * multicast filters.
1660 		 */
1661 		ef10_filter_remove_old(enp);
1662 	}
1663 
1664 	/* Insert or renew multicast filters */
1665 	if (all_mulcst == B_TRUE) {
1666 		/*
1667 		 * Insert the all multicast filter. If that fails, try to insert
1668 		 * all of our multicast filters (but without rollback on
1669 		 * failure).
1670 		 */
1671 		all_mulcst_rc = ef10_filter_insert_all_multicast(enp,
1672 							    filter_flags);
1673 		if (all_mulcst_rc != 0) {
1674 			rc = ef10_filter_insert_multicast_list(enp, B_TRUE,
1675 			    brdcst, addrs, count, filter_flags, B_FALSE);
1676 			if (rc != 0)
1677 				goto fail3;
1678 		}
1679 	} else {
1680 		/*
1681 		 * Insert filters for multicast addresses.
1682 		 * If any insertion fails, then rollback and try to insert the
1683 		 * all multicast filter instead.
1684 		 * If that also fails, try to insert all of the multicast
1685 		 * filters (but without rollback on failure).
1686 		 */
1687 		rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst,
1688 			    addrs, count, filter_flags, B_TRUE);
1689 		if (rc != 0) {
1690 			if ((table->eft_using_all_mulcst == B_FALSE) &&
1691 			    (encp->enc_bug26807_workaround == B_TRUE)) {
1692 				/*
1693 				 * Multicast filter chaining is on, so remove
1694 				 * old filters before inserting the multicast
1695 				 * all filter to avoid duplicate delivery caused
1696 				 * by packets matching multiple filters.
1697 				 */
1698 				ef10_filter_remove_old(enp);
1699 			}
1700 
1701 			rc = ef10_filter_insert_all_multicast(enp,
1702 							    filter_flags);
1703 			if (rc != 0) {
1704 				rc = ef10_filter_insert_multicast_list(enp,
1705 				    mulcst, brdcst,
1706 				    addrs, count, filter_flags, B_FALSE);
1707 				if (rc != 0)
1708 					goto fail4;
1709 			}
1710 		}
1711 	}
1712 
1713 	if (encp->enc_tunnel_encapsulations_supported != 0) {
1714 		/* Try to insert filters for encapsulated packets. */
1715 		(void) ef10_filter_insert_encap_filters(enp,
1716 					    mulcst || all_mulcst || brdcst,
1717 					    filter_flags);
1718 	}
1719 
1720 	/* Remove old filters which were not renewed */
1721 	ef10_filter_remove_old(enp);
1722 
1723 	/* report if any optional flags were rejected */
1724 	if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) ||
1725 	    ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) {
1726 		rc = ENOTSUP;
1727 	}
1728 
1729 	return (rc);
1730 
1731 fail4:
1732 	EFSYS_PROBE(fail4);
1733 fail3:
1734 	EFSYS_PROBE(fail3);
1735 fail2:
1736 	EFSYS_PROBE(fail2);
1737 fail1:
1738 	EFSYS_PROBE1(fail1, efx_rc_t, rc);
1739 
1740 	/* Clear auto old flags */
1741 	for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) {
1742 		if (ef10_filter_entry_is_auto_old(table, i)) {
1743 			ef10_filter_set_entry_not_auto_old(table, i);
1744 		}
1745 	}
1746 
1747 	return (rc);
1748 }
1749 
1750 		void
ef10_filter_get_default_rxq(__in efx_nic_t * enp,__out efx_rxq_t ** erpp,__out boolean_t * using_rss)1751 ef10_filter_get_default_rxq(
1752 	__in		efx_nic_t *enp,
1753 	__out		efx_rxq_t **erpp,
1754 	__out		boolean_t *using_rss)
1755 {
1756 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1757 
1758 	*erpp = table->eft_default_rxq;
1759 	*using_rss = table->eft_using_rss;
1760 }
1761 
1762 		void
ef10_filter_default_rxq_set(__in efx_nic_t * enp,__in efx_rxq_t * erp,__in boolean_t using_rss)1763 ef10_filter_default_rxq_set(
1764 	__in		efx_nic_t *enp,
1765 	__in		efx_rxq_t *erp,
1766 	__in		boolean_t using_rss)
1767 {
1768 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1769 
1770 #if EFSYS_OPT_RX_SCALE
1771 	EFSYS_ASSERT((using_rss == B_FALSE) ||
1772 	    (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID));
1773 	table->eft_using_rss = using_rss;
1774 #else
1775 	EFSYS_ASSERT(using_rss == B_FALSE);
1776 	table->eft_using_rss = B_FALSE;
1777 #endif
1778 	table->eft_default_rxq = erp;
1779 }
1780 
1781 		void
ef10_filter_default_rxq_clear(__in efx_nic_t * enp)1782 ef10_filter_default_rxq_clear(
1783 	__in		efx_nic_t *enp)
1784 {
1785 	ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table;
1786 
1787 	table->eft_default_rxq = NULL;
1788 	table->eft_using_rss = B_FALSE;
1789 }
1790 
1791 #endif /* EFSYS_OPT_FILTER */
1792 
1793 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
1794