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