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