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