1227569Sphilip/*-
2227569Sphilip * Copyright 2007-2009 Solarflare Communications Inc.  All rights reserved.
3227569Sphilip *
4227569Sphilip * Redistribution and use in source and binary forms, with or without
5227569Sphilip * modification, are permitted provided that the following conditions
6227569Sphilip * are met:
7227569Sphilip * 1. Redistributions of source code must retain the above copyright
8227569Sphilip *    notice, this list of conditions and the following disclaimer.
9227569Sphilip * 2. Redistributions in binary form must reproduce the above copyright
10227569Sphilip *    notice, this list of conditions and the following disclaimer in the
11227569Sphilip *    documentation and/or other materials provided with the distribution.
12227569Sphilip *
13227569Sphilip * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
14227569Sphilip * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15227569Sphilip * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16227569Sphilip * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17227569Sphilip * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18227569Sphilip * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19227569Sphilip * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20227569Sphilip * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21227569Sphilip * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22227569Sphilip * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23227569Sphilip * SUCH DAMAGE.
24227569Sphilip */
25227569Sphilip
26228100Sphilip#include <sys/cdefs.h>
27228100Sphilip__FBSDID("$FreeBSD$");
28228100Sphilip
29227569Sphilip#include "efsys.h"
30227569Sphilip#include "efx.h"
31227569Sphilip#include "efx_types.h"
32227569Sphilip#include "efx_regs.h"
33227569Sphilip#include "efx_impl.h"
34227569Sphilip
35227569Sphilip
36227569Sphilip#if EFSYS_OPT_FILTER
37227569Sphilip
38227569Sphilip/* "Fudge factors" - difference between programmed value and actual depth.
39227569Sphilip * Due to pipelined implementation we need to program H/W with a value that
40227569Sphilip * is larger than the hop limit we want.
41227569Sphilip */
42227569Sphilip#define FILTER_CTL_SRCH_FUDGE_WILD 3
43227569Sphilip#define FILTER_CTL_SRCH_FUDGE_FULL 1
44227569Sphilip
45227569Sphilip/* Hard maximum hop limit.  Hardware will time-out beyond 200-something.
46227569Sphilip * We also need to avoid infinite loops in efx_filter_search() when the
47227569Sphilip * table is full.
48227569Sphilip */
49227569Sphilip#define FILTER_CTL_SRCH_MAX 200
50227569Sphilip
51227569Sphilip/* The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
52227569Sphilip * key derived from the n-tuple. */
53227569Sphilipstatic			uint16_t
54227569Sphilipefx_filter_tbl_hash(
55227569Sphilip	__in 		uint32_t key)
56227569Sphilip{
57227569Sphilip	uint16_t tmp;
58227569Sphilip
59227569Sphilip	/* First 16 rounds */
60227569Sphilip	tmp = 0x1fff ^ (uint16_t)(key >> 16);
61227569Sphilip	tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
62227569Sphilip	tmp = tmp ^ tmp >> 9;
63227569Sphilip
64227569Sphilip	/* Last 16 rounds */
65227569Sphilip	tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
66227569Sphilip	tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
67227569Sphilip	tmp = tmp ^ tmp >> 9;
68227569Sphilip
69227569Sphilip	return (tmp);
70227569Sphilip}
71227569Sphilip
72227569Sphilip
73227569Sphilip/* To allow for hash collisions, filter search continues at these
74227569Sphilip * increments from the first possible entry selected by the hash. */
75227569Sphilipstatic			uint16_t
76227569Sphilipefx_filter_tbl_increment(
77227569Sphilip	__in		uint32_t key)
78227569Sphilip{
79227569Sphilip	return ((uint16_t)(key * 2 - 1));
80227569Sphilip}
81227569Sphilip
82227569Sphilipstatic	__checkReturn	boolean_t
83227569Sphilipefx_filter_test_used(
84227569Sphilip	__in		efx_filter_tbl_t *eftp,
85227569Sphilip	__in		unsigned int index)
86227569Sphilip{
87227569Sphilip	EFSYS_ASSERT3P(eftp->eft_bitmap, !=, NULL);
88227569Sphilip	return ((eftp->eft_bitmap[index / 32] & (1 << (index % 32))) != 0);
89227569Sphilip}
90227569Sphilip
91227569Sphilipstatic			void
92227569Sphilipefx_filter_set_used(
93227569Sphilip	__in		efx_filter_tbl_t *eftp,
94227569Sphilip	__in		unsigned int index)
95227569Sphilip{
96227569Sphilip	EFSYS_ASSERT3P(eftp->eft_bitmap, !=, NULL);
97227569Sphilip	eftp->eft_bitmap[index / 32] |= (1 << (index % 32));
98227569Sphilip	++eftp->eft_used;
99227569Sphilip}
100227569Sphilip
101227569Sphilipstatic			void
102227569Sphilipefx_filter_clear_used(
103227569Sphilip	__in		efx_filter_tbl_t *eftp,
104227569Sphilip	__in		unsigned int index)
105227569Sphilip{
106227569Sphilip	EFSYS_ASSERT3P(eftp->eft_bitmap, !=, NULL);
107227569Sphilip	eftp->eft_bitmap[index / 32] &= ~(1 << (index % 32));
108227569Sphilip
109227569Sphilip	--eftp->eft_used;
110227569Sphilip	EFSYS_ASSERT3U(eftp->eft_used, >=, 0);
111227569Sphilip}
112227569Sphilip
113227569Sphilip
114227569Sphilipstatic 			efx_filter_tbl_id_t
115227569Sphilipefx_filter_tbl_id(
116227569Sphilip	__in		efx_filter_type_t type)
117227569Sphilip{
118227569Sphilip	efx_filter_tbl_id_t tbl_id;
119227569Sphilip
120227569Sphilip	switch (type)
121227569Sphilip	{
122227569Sphilip	case EFX_FILTER_RX_TCP_FULL:
123227569Sphilip	case EFX_FILTER_RX_TCP_WILD:
124227569Sphilip	case EFX_FILTER_RX_UDP_FULL:
125227569Sphilip	case EFX_FILTER_RX_UDP_WILD:
126227569Sphilip		tbl_id = EFX_FILTER_TBL_RX_IP;
127227569Sphilip		break;
128227569Sphilip
129227569Sphilip#if EFSYS_OPT_SIENA
130227569Sphilip	case EFX_FILTER_RX_MAC_FULL:
131227569Sphilip	case EFX_FILTER_RX_MAC_WILD:
132227569Sphilip		tbl_id = EFX_FILTER_TBL_RX_MAC;
133227569Sphilip		break;
134227569Sphilip
135227569Sphilip	case EFX_FILTER_TX_TCP_FULL:
136227569Sphilip	case EFX_FILTER_TX_TCP_WILD:
137227569Sphilip	case EFX_FILTER_TX_UDP_FULL:
138227569Sphilip	case EFX_FILTER_TX_UDP_WILD:
139227569Sphilip		tbl_id = EFX_FILTER_TBL_TX_IP;
140227569Sphilip		break;
141227569Sphilip
142227569Sphilip	case EFX_FILTER_TX_MAC_FULL:
143227569Sphilip	case EFX_FILTER_TX_MAC_WILD:
144227569Sphilip		tbl_id = EFX_FILTER_TBL_RX_MAC;
145227569Sphilip		break;
146227569Sphilip#endif	/* EFSYS_OPT_SIENA */
147227569Sphilip
148227569Sphilip	default:
149227569Sphilip		EFSYS_ASSERT(B_FALSE);
150227569Sphilip		break;
151227569Sphilip	}
152227569Sphilip	return (tbl_id);
153227569Sphilip}
154227569Sphilip
155227569Sphilipstatic			void
156227569Sphilipefx_filter_reset_search_depth(
157227569Sphilip	__inout		efx_filter_t *efp,
158227569Sphilip	__in		efx_filter_tbl_id_t tbl_id)
159227569Sphilip{
160227569Sphilip	switch (tbl_id)
161227569Sphilip	{
162227569Sphilip	case EFX_FILTER_TBL_RX_IP:
163227569Sphilip		efp->ef_depth[EFX_FILTER_RX_TCP_FULL] = 0;
164227569Sphilip		efp->ef_depth[EFX_FILTER_RX_TCP_WILD] = 0;
165227569Sphilip		efp->ef_depth[EFX_FILTER_RX_UDP_FULL] = 0;
166227569Sphilip		efp->ef_depth[EFX_FILTER_RX_UDP_WILD] = 0;
167227569Sphilip		break;
168227569Sphilip
169227569Sphilip#if EFSYS_OPT_SIENA
170227569Sphilip	case EFX_FILTER_TBL_RX_MAC:
171227569Sphilip		efp->ef_depth[EFX_FILTER_RX_MAC_FULL] = 0;
172227569Sphilip		efp->ef_depth[EFX_FILTER_RX_MAC_WILD] = 0;
173227569Sphilip		break;
174227569Sphilip
175227569Sphilip	case EFX_FILTER_TBL_TX_IP:
176227569Sphilip		efp->ef_depth[EFX_FILTER_TX_TCP_FULL] = 0;
177227569Sphilip		efp->ef_depth[EFX_FILTER_TX_TCP_WILD] = 0;
178227569Sphilip		efp->ef_depth[EFX_FILTER_TX_UDP_FULL] = 0;
179227569Sphilip		efp->ef_depth[EFX_FILTER_TX_UDP_WILD] = 0;
180227569Sphilip		break;
181227569Sphilip
182227569Sphilip	case EFX_FILTER_TBL_TX_MAC:
183227569Sphilip		efp->ef_depth[EFX_FILTER_TX_MAC_FULL] = 0;
184227569Sphilip		efp->ef_depth[EFX_FILTER_TX_MAC_WILD] = 0;
185227569Sphilip		break;
186227569Sphilip#endif	/* EFSYS_OPT_SIENA */
187227569Sphilip
188227569Sphilip	default:
189227569Sphilip		EFSYS_ASSERT(B_FALSE);
190227569Sphilip		break;
191227569Sphilip	}
192227569Sphilip}
193227569Sphilip
194227569Sphilipstatic			void
195227569Sphilipefx_filter_push_rx_limits(
196227569Sphilip	__in		efx_nic_t *enp)
197227569Sphilip{
198227569Sphilip	efx_filter_t *efp = &enp->en_filter;
199227569Sphilip	efx_oword_t oword;
200227569Sphilip
201227569Sphilip	EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
202227569Sphilip
203227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
204227569Sphilip	    efp->ef_depth[EFX_FILTER_RX_TCP_FULL] +
205227569Sphilip	    FILTER_CTL_SRCH_FUDGE_FULL);
206227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
207227569Sphilip	    efp->ef_depth[EFX_FILTER_RX_TCP_WILD] +
208227569Sphilip	    FILTER_CTL_SRCH_FUDGE_WILD);
209227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
210227569Sphilip	    efp->ef_depth[EFX_FILTER_RX_UDP_FULL] +
211227569Sphilip	    FILTER_CTL_SRCH_FUDGE_FULL);
212227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
213227569Sphilip	    efp->ef_depth[EFX_FILTER_RX_UDP_WILD] +
214227569Sphilip	    FILTER_CTL_SRCH_FUDGE_WILD);
215227569Sphilip
216227569Sphilip#if EFSYS_OPT_SIENA
217227569Sphilip	if (efp->ef_tbl[EFX_FILTER_TBL_RX_MAC].eft_size) {
218227569Sphilip		EFX_SET_OWORD_FIELD(oword,
219227569Sphilip		    FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
220227569Sphilip		    efp->ef_depth[EFX_FILTER_RX_MAC_FULL] +
221227569Sphilip		    FILTER_CTL_SRCH_FUDGE_FULL);
222227569Sphilip		EFX_SET_OWORD_FIELD(oword,
223227569Sphilip		    FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
224227569Sphilip		    efp->ef_depth[EFX_FILTER_RX_MAC_WILD] +
225227569Sphilip		    FILTER_CTL_SRCH_FUDGE_WILD);
226227569Sphilip	}
227227569Sphilip#endif /* EFSYS_OPT_SIENA */
228227569Sphilip
229227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
230227569Sphilip}
231227569Sphilip
232227569Sphilipstatic			void
233227569Sphilipefx_filter_push_tx_limits(
234227569Sphilip	__in		efx_nic_t *enp)
235227569Sphilip{
236227569Sphilip	efx_filter_t *efp = &enp->en_filter;
237227569Sphilip	efx_oword_t oword;
238227569Sphilip
239227569Sphilip	if (efp->ef_tbl[EFX_FILTER_TBL_TX_IP].eft_size == 0)
240227569Sphilip		return;
241227569Sphilip
242227569Sphilip	EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
243227569Sphilip
244227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
245227569Sphilip	    efp->ef_depth[EFX_FILTER_TX_TCP_FULL] +
246227569Sphilip	    FILTER_CTL_SRCH_FUDGE_FULL);
247227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
248227569Sphilip	    efp->ef_depth[EFX_FILTER_TX_TCP_WILD] +
249227569Sphilip	    FILTER_CTL_SRCH_FUDGE_WILD);
250227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
251227569Sphilip	    efp->ef_depth[EFX_FILTER_TX_UDP_FULL] +
252227569Sphilip	    FILTER_CTL_SRCH_FUDGE_FULL);
253227569Sphilip	EFX_SET_OWORD_FIELD(oword, FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
254227569Sphilip	    efp->ef_depth[EFX_FILTER_TX_UDP_WILD] +
255227569Sphilip	    FILTER_CTL_SRCH_FUDGE_WILD);
256227569Sphilip
257227569Sphilip	EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
258227569Sphilip}
259227569Sphilip
260227569Sphilip/* Build a filter entry and return its n-tuple key. */
261227569Sphilipstatic	__checkReturn	uint32_t
262227569Sphilipefx_filter_build(
263227569Sphilip	__out		efx_oword_t *filter,
264227569Sphilip	__in		efx_filter_spec_t *spec)
265227569Sphilip{
266227569Sphilip	uint32_t dword3;
267227569Sphilip	uint32_t key;
268227569Sphilip	uint8_t  type  = spec->efs_type;
269227569Sphilip	uint8_t  flags = spec->efs_flags;
270227569Sphilip
271227569Sphilip	switch (efx_filter_tbl_id(type)) {
272227569Sphilip	case EFX_FILTER_TBL_RX_IP: {
273227569Sphilip		boolean_t is_udp = (type == EFX_FILTER_RX_UDP_FULL ||
274227569Sphilip		    type == EFX_FILTER_RX_UDP_WILD);
275227569Sphilip		EFX_POPULATE_OWORD_7(*filter,
276227569Sphilip		    FRF_BZ_RSS_EN,     (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
277227569Sphilip		    FRF_BZ_SCATTER_EN, (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
278227569Sphilip		    FRF_AZ_TCP_UDP, is_udp,
279227569Sphilip		    FRF_AZ_RXQ_ID, spec->efs_dmaq_id,
280227569Sphilip		    EFX_DWORD_2, spec->efs_dword[2],
281227569Sphilip		    EFX_DWORD_1, spec->efs_dword[1],
282227569Sphilip		    EFX_DWORD_0, spec->efs_dword[0]);
283227569Sphilip		dword3 = is_udp;
284227569Sphilip		break;
285227569Sphilip	}
286227569Sphilip
287227569Sphilip#if EFSYS_OPT_SIENA
288227569Sphilip	case EFX_FILTER_TBL_RX_MAC: {
289227569Sphilip		boolean_t is_wild = (type == EFX_FILTER_RX_MAC_WILD);
290227569Sphilip		EFX_POPULATE_OWORD_8(*filter,
291227569Sphilip		    FRF_CZ_RMFT_RSS_EN, (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
292227569Sphilip		    FRF_CZ_RMFT_SCATTER_EN, (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
293227569Sphilip		    FRF_CZ_RMFT_IP_OVERRIDE, (flags & EFX_FILTER_FLAG_RX_OVERRIDE_IP) ? 1 : 0,
294227569Sphilip		    FRF_CZ_RMFT_RXQ_ID, spec->efs_dmaq_id,
295227569Sphilip		    FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
296227569Sphilip		    FRF_CZ_RMFT_DEST_MAC_DW1, spec->efs_dword[2],
297227569Sphilip		    FRF_CZ_RMFT_DEST_MAC_DW0, spec->efs_dword[1],
298227569Sphilip		    FRF_CZ_RMFT_VLAN_ID, spec->efs_dword[0]);
299227569Sphilip		dword3 = is_wild;
300227569Sphilip		break;
301227569Sphilip	}
302227569Sphilip#endif /* EFSYS_OPT_SIENA */
303227569Sphilip
304227569Sphilip	case EFX_FILTER_TBL_TX_IP: {
305227569Sphilip		boolean_t is_udp = (type == EFX_FILTER_TX_UDP_FULL ||
306227569Sphilip		    type == EFX_FILTER_TX_UDP_WILD);
307227569Sphilip		EFX_POPULATE_OWORD_5(*filter,
308227569Sphilip		    FRF_CZ_TIFT_TCP_UDP, is_udp,
309227569Sphilip		    FRF_CZ_TIFT_TXQ_ID, spec->efs_dmaq_id,
310227569Sphilip		    EFX_DWORD_2, spec->efs_dword[2],
311227569Sphilip		    EFX_DWORD_1, spec->efs_dword[1],
312227569Sphilip		    EFX_DWORD_0, spec->efs_dword[0]);
313227569Sphilip		dword3 = is_udp | spec->efs_dmaq_id << 1;
314227569Sphilip		break;
315227569Sphilip	}
316227569Sphilip
317227569Sphilip#if EFSYS_OPT_SIENA
318227569Sphilip	case EFX_FILTER_TBL_TX_MAC: {
319227569Sphilip		boolean_t is_wild = (type == EFX_FILTER_TX_MAC_WILD);
320227569Sphilip		EFX_POPULATE_OWORD_5(*filter,
321227569Sphilip		    FRF_CZ_TMFT_TXQ_ID, spec->efs_dmaq_id,
322227569Sphilip		    FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
323227569Sphilip		    FRF_CZ_TMFT_SRC_MAC_DW1, spec->efs_dword[2],
324227569Sphilip		    FRF_CZ_TMFT_SRC_MAC_DW0, spec->efs_dword[1],
325227569Sphilip		    FRF_CZ_TMFT_VLAN_ID, spec->efs_dword[0]);
326227569Sphilip		dword3 = is_wild | spec->efs_dmaq_id << 1;
327227569Sphilip		break;
328227569Sphilip	}
329227569Sphilip#endif /* EFSYS_OPT_SIENA */
330227569Sphilip
331227569Sphilip	default:
332227569Sphilip		EFSYS_ASSERT(B_FALSE);
333227569Sphilip	}
334227569Sphilip
335227569Sphilip	key = spec->efs_dword[0] ^ spec->efs_dword[1] ^ spec->efs_dword[2] ^ dword3;
336227569Sphilip	return (key);
337227569Sphilip}
338227569Sphilip
339227569Sphilipstatic	__checkReturn		int
340227569Sphilipefx_filter_push_entry(
341227569Sphilip	__inout			efx_nic_t *enp,
342227569Sphilip	__in			efx_filter_type_t type,
343227569Sphilip	__in			int index,
344227569Sphilip	__in			efx_oword_t *eop)
345227569Sphilip{
346227569Sphilip	int rc;
347227569Sphilip
348227569Sphilip	switch (type)
349227569Sphilip	{
350227569Sphilip	case EFX_FILTER_RX_TCP_FULL:
351227569Sphilip	case EFX_FILTER_RX_TCP_WILD:
352227569Sphilip	case EFX_FILTER_RX_UDP_FULL:
353227569Sphilip	case EFX_FILTER_RX_UDP_WILD:
354227569Sphilip		EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index, eop);
355227569Sphilip		break;
356227569Sphilip
357227569Sphilip#if EFSYS_OPT_SIENA
358227569Sphilip	case EFX_FILTER_RX_MAC_FULL:
359227569Sphilip	case EFX_FILTER_RX_MAC_WILD:
360227569Sphilip		EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index, eop);
361227569Sphilip		break;
362227569Sphilip
363227569Sphilip	case EFX_FILTER_TX_TCP_FULL:
364227569Sphilip	case EFX_FILTER_TX_TCP_WILD:
365227569Sphilip	case EFX_FILTER_TX_UDP_FULL:
366227569Sphilip	case EFX_FILTER_TX_UDP_WILD:
367227569Sphilip		EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index, eop);
368227569Sphilip		break;
369227569Sphilip
370227569Sphilip	case EFX_FILTER_TX_MAC_FULL:
371227569Sphilip	case EFX_FILTER_TX_MAC_WILD:
372227569Sphilip		EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index, eop);
373227569Sphilip		break;
374227569Sphilip#endif	/* EFSYS_OPT_SIENA */
375227569Sphilip
376227569Sphilip	default:
377227569Sphilip		rc = ENOTSUP;
378227569Sphilip		goto fail1;
379227569Sphilip	}
380227569Sphilip	return (0);
381227569Sphilip
382227569Sphilipfail1:
383227569Sphilip	return (rc);
384227569Sphilip}
385227569Sphilip
386227569Sphilip
387227569Sphilipstatic	__checkReturn	boolean_t
388227569Sphilipefx_filter_equal(
389227569Sphilip	__in		const efx_filter_spec_t *left,
390227569Sphilip	__in		const efx_filter_spec_t *right)
391227569Sphilip{
392227569Sphilip	efx_filter_tbl_id_t tbl_id = efx_filter_tbl_id(left->efs_type);
393227569Sphilip
394227569Sphilip	if (left->efs_type != right->efs_type)
395227569Sphilip		return (B_FALSE);
396227569Sphilip
397227569Sphilip	if (memcmp(left->efs_dword, right->efs_dword, sizeof(left->efs_dword)))
398227569Sphilip		return (B_FALSE);
399227569Sphilip
400227569Sphilip	if ((tbl_id == EFX_FILTER_TBL_TX_IP ||
401227569Sphilip	     tbl_id == EFX_FILTER_TBL_TX_MAC) &&
402227569Sphilip	    left->efs_dmaq_id != right->efs_dmaq_id)
403227569Sphilip		return (B_FALSE);
404227569Sphilip
405227569Sphilip	return (B_TRUE);
406227569Sphilip}
407227569Sphilip
408227569Sphilipstatic	__checkReturn	int
409227569Sphilipefx_filter_search(
410227569Sphilip	__in		efx_filter_tbl_t *eftp,
411227569Sphilip	__in		efx_filter_spec_t *spec,
412227569Sphilip	__in		uint32_t key,
413227569Sphilip	__in		boolean_t for_insert,
414227569Sphilip	__out		int *filter_index,
415227569Sphilip	__out		int *depth_required)
416227569Sphilip{
417227569Sphilip	unsigned hash, incr, filter_idx, depth;
418227569Sphilip
419227569Sphilip	hash = efx_filter_tbl_hash(key);
420227569Sphilip	incr = efx_filter_tbl_increment(key);
421227569Sphilip
422227569Sphilip	filter_idx = hash & (eftp->eft_size - 1);
423227569Sphilip	depth = 1;
424227569Sphilip
425227569Sphilip	for (;;) {
426227569Sphilip		/* Return success if entry is used and matches this spec
427227569Sphilip		 * or entry is unused and we are trying to insert.
428227569Sphilip		 */
429227569Sphilip		if (efx_filter_test_used(eftp, filter_idx) ?
430227569Sphilip		    efx_filter_equal(spec, &eftp->eft_spec[filter_idx]) :
431227569Sphilip		    for_insert) {
432227569Sphilip			*filter_index = filter_idx;
433227569Sphilip			*depth_required = depth;
434227569Sphilip			return (0);
435227569Sphilip		}
436227569Sphilip
437227569Sphilip		/* Return failure if we reached the maximum search depth */
438227569Sphilip		if (depth == FILTER_CTL_SRCH_MAX)
439227569Sphilip			return for_insert ? EBUSY : ENOENT;
440227569Sphilip
441227569Sphilip		filter_idx = (filter_idx + incr) & (eftp->eft_size - 1);
442227569Sphilip		++depth;
443227569Sphilip	}
444227569Sphilip}
445227569Sphilip
446227569Sphilip	__checkReturn	int
447227569Sphilipefx_filter_insert_filter(
448227569Sphilip	__in		efx_nic_t *enp,
449227569Sphilip	__in		efx_filter_spec_t *spec,
450227569Sphilip	__in		boolean_t replace)
451227569Sphilip{
452227569Sphilip	efx_filter_t *efp = &enp->en_filter;
453227569Sphilip	efx_filter_tbl_id_t tbl_id = efx_filter_tbl_id(spec->efs_type);
454227569Sphilip	efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id];
455227569Sphilip	efx_filter_spec_t *saved_spec;
456227569Sphilip	efx_oword_t filter;
457227569Sphilip	int filter_idx;
458227569Sphilip	unsigned int depth;
459227569Sphilip	int state;
460227569Sphilip	uint32_t key;
461227569Sphilip	int rc;
462227569Sphilip
463227569Sphilip	if (eftp->eft_size == 0)
464227569Sphilip		return (EINVAL);
465227569Sphilip
466227569Sphilip	key = efx_filter_build(&filter, spec);
467227569Sphilip
468227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
469227569Sphilip
470227569Sphilip	rc = efx_filter_search(eftp, spec, key, B_TRUE, &filter_idx, &depth);
471227569Sphilip	if (rc != 0)
472227569Sphilip		goto done;
473227569Sphilip
474227569Sphilip	EFSYS_ASSERT3U(filter_idx, <, eftp->eft_size);
475227569Sphilip	saved_spec = &eftp->eft_spec[filter_idx];
476227569Sphilip
477227569Sphilip	if (efx_filter_test_used(eftp, filter_idx)) {
478227569Sphilip		if (replace == B_FALSE) {
479227569Sphilip			rc = EEXIST;
480227569Sphilip			goto done;
481227569Sphilip		}
482227569Sphilip	}
483227569Sphilip	efx_filter_set_used(eftp, filter_idx);
484227569Sphilip	*saved_spec = *spec;
485227569Sphilip
486227569Sphilip	if (efp->ef_depth[spec->efs_type] < depth) {
487227569Sphilip		efp->ef_depth[spec->efs_type] = depth;
488227569Sphilip		if (tbl_id == EFX_FILTER_TBL_TX_IP ||
489227569Sphilip		    tbl_id == EFX_FILTER_TBL_TX_MAC)
490227569Sphilip			efx_filter_push_tx_limits(enp);
491227569Sphilip		else
492227569Sphilip			efx_filter_push_rx_limits(enp);
493227569Sphilip	}
494227569Sphilip
495227569Sphilip	efx_filter_push_entry(enp, spec->efs_type, filter_idx, &filter);
496227569Sphilip
497227569Sphilipdone:
498227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
499227569Sphilip	return (rc);
500227569Sphilip}
501227569Sphilip
502227569Sphilipstatic			void
503227569Sphilipefx_filter_clear_entry(
504227569Sphilip	__in		efx_nic_t *enp,
505227569Sphilip	__in		efx_filter_tbl_t *eftp,
506227569Sphilip	__in		int index)
507227569Sphilip{
508227569Sphilip	efx_oword_t filter;
509227569Sphilip
510227569Sphilip	if (efx_filter_test_used(eftp, index)) {
511227569Sphilip		efx_filter_clear_used(eftp, index);
512227569Sphilip
513227569Sphilip		EFX_ZERO_OWORD(filter);
514227569Sphilip		efx_filter_push_entry(enp, eftp->eft_spec[index].efs_type,
515227569Sphilip		    index, &filter);
516227569Sphilip
517227569Sphilip		memset(&eftp->eft_spec[index], 0, sizeof(eftp->eft_spec[0]));
518227569Sphilip	}
519227569Sphilip}
520227569Sphilip
521227569Sphilip	__checkReturn	int
522227569Sphilipefx_filter_remove_filter(
523227569Sphilip	__in		efx_nic_t *enp,
524227569Sphilip	__in		efx_filter_spec_t *spec)
525227569Sphilip{
526227569Sphilip	efx_filter_t *efp = &enp->en_filter;
527227569Sphilip	efx_filter_tbl_id_t tbl_id = efx_filter_tbl_id(spec->efs_type);
528227569Sphilip	efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id];
529227569Sphilip	efx_filter_spec_t *saved_spec;
530227569Sphilip	efx_oword_t filter;
531227569Sphilip	int filter_idx, depth;
532227569Sphilip	int state;
533227569Sphilip	uint32_t key;
534227569Sphilip	int rc;
535227569Sphilip
536227569Sphilip	key = efx_filter_build(&filter, spec);
537227569Sphilip
538227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
539227569Sphilip
540227569Sphilip	rc = efx_filter_search(eftp, spec, key, B_FALSE, &filter_idx, &depth);
541227569Sphilip	if (rc != 0)
542227569Sphilip		goto out;
543227569Sphilip
544227569Sphilip	saved_spec = &eftp->eft_spec[filter_idx];
545227569Sphilip
546227569Sphilip	efx_filter_clear_entry(enp, eftp, filter_idx);
547227569Sphilip	if (eftp->eft_used == 0)
548227569Sphilip		efx_filter_reset_search_depth(efp, tbl_id);
549227569Sphilip
550227569Sphilip	rc = 0;
551227569Sphilip
552227569Sphilipout:
553227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
554227569Sphilip	return (rc);
555227569Sphilip}
556227569Sphilip
557227569Sphilip			void
558227569Sphilipefx_filter_remove_index(
559227569Sphilip	__inout		efx_nic_t *enp,
560227569Sphilip	__in		efx_filter_type_t type,
561227569Sphilip	__in		int index)
562227569Sphilip{
563227569Sphilip	efx_filter_t *efp = &enp->en_filter;
564227569Sphilip	enum efx_filter_tbl_id tbl_id = efx_filter_tbl_id(type);
565227569Sphilip	efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id];
566227569Sphilip	int state;
567227569Sphilip
568227569Sphilip	if (index < 0)
569227569Sphilip		return;
570227569Sphilip
571227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
572227569Sphilip
573227569Sphilip	efx_filter_clear_entry(enp, eftp, index);
574227569Sphilip	if (eftp->eft_used == 0)
575227569Sphilip		efx_filter_reset_search_depth(efp, tbl_id);
576227569Sphilip
577227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
578227569Sphilip}
579227569Sphilip
580227569Sphilip			void
581227569Sphilipefx_filter_tbl_clear(
582227569Sphilip	__inout		efx_nic_t *enp,
583227569Sphilip	__in		efx_filter_tbl_id_t tbl_id)
584227569Sphilip{
585227569Sphilip	efx_filter_t *efp = &enp->en_filter;
586227569Sphilip	efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id];
587227569Sphilip	int index;
588227569Sphilip	int state;
589227569Sphilip
590227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
591227569Sphilip
592227569Sphilip	for (index = 0; index < eftp->eft_size; ++index) {
593227569Sphilip		efx_filter_clear_entry(enp, eftp, index);
594227569Sphilip	}
595227569Sphilip
596227569Sphilip	if (eftp->eft_used == 0)
597227569Sphilip		efx_filter_reset_search_depth(efp, tbl_id);
598227569Sphilip
599227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
600227569Sphilip}
601227569Sphilip
602227569Sphilip/* Restore filter state after a reset */
603227569Sphilip			void
604227569Sphilipefx_filter_restore(
605227569Sphilip	__in		efx_nic_t *enp)
606227569Sphilip{
607227569Sphilip	efx_filter_t *efp = &enp->en_filter;
608227569Sphilip	efx_filter_tbl_id_t tbl_id;
609227569Sphilip	efx_filter_tbl_t *eftp;
610227569Sphilip	efx_filter_spec_t *spec;
611227569Sphilip	efx_oword_t filter;
612227569Sphilip	int filter_idx;
613227569Sphilip	int state;
614227569Sphilip
615227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
616227569Sphilip
617227569Sphilip	for (tbl_id = 0; tbl_id < EFX_FILTER_NTBLS; tbl_id++) {
618227569Sphilip		eftp = &efp->ef_tbl[tbl_id];
619227569Sphilip		for (filter_idx = 0; filter_idx < eftp->eft_size; filter_idx++) {
620227569Sphilip			if (!efx_filter_test_used(eftp, filter_idx))
621227569Sphilip				continue;
622227569Sphilip
623227569Sphilip			spec = &eftp->eft_spec[filter_idx];
624227569Sphilip			efx_filter_build(&filter, spec);
625227569Sphilip			efx_filter_push_entry(enp, spec->efs_type,
626227569Sphilip			    filter_idx, &filter);
627227569Sphilip		}
628227569Sphilip	}
629227569Sphilip
630227569Sphilip	efx_filter_push_rx_limits(enp);
631227569Sphilip	efx_filter_push_tx_limits(enp);
632227569Sphilip
633227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
634227569Sphilip}
635227569Sphilip
636227569Sphilip			void
637227569Sphilipefx_filter_redirect_index(
638227569Sphilip	__inout		efx_nic_t *enp,
639227569Sphilip	__in		efx_filter_type_t type,
640227569Sphilip	__in		int filter_index,
641227569Sphilip	__in		int rxq_index)
642227569Sphilip{
643227569Sphilip	efx_filter_t *efp = &enp->en_filter;
644227569Sphilip	efx_filter_tbl_t *eftp =
645227569Sphilip		&efp->ef_tbl[efx_filter_tbl_id(type)];
646227569Sphilip	efx_filter_spec_t *spec;
647227569Sphilip	efx_oword_t filter;
648227569Sphilip	int state;
649227569Sphilip
650227569Sphilip	EFSYS_LOCK(enp->en_eslp, state);
651227569Sphilip
652227569Sphilip	spec = &eftp->eft_spec[filter_index];
653227569Sphilip	spec->efs_dmaq_id = (uint16_t)rxq_index;
654227569Sphilip
655227569Sphilip	efx_filter_build(&filter, spec);
656227569Sphilip	efx_filter_push_entry(enp, spec->efs_type, filter_index, &filter);
657227569Sphilip
658227569Sphilip	EFSYS_UNLOCK(enp->en_eslp, state);
659227569Sphilip}
660227569Sphilip
661227569Sphilip	__checkReturn	int
662227569Sphilipefx_filter_init(
663227569Sphilip	__in		efx_nic_t *enp)
664227569Sphilip{
665227569Sphilip	efx_filter_t *efp = &enp->en_filter;
666227569Sphilip	efx_filter_tbl_t *eftp;
667227569Sphilip	int tbl_id;
668227569Sphilip	int rc;
669227569Sphilip
670227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
671227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
672227569Sphilip	EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
673227569Sphilip
674227569Sphilip	switch (enp->en_family)
675227569Sphilip	{
676227569Sphilip#if EFSYS_OPT_FALCON
677227569Sphilip	case EFX_FAMILY_FALCON:
678227569Sphilip		eftp = &efp->ef_tbl[EFX_FILTER_TBL_RX_IP];
679227569Sphilip		eftp->eft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
680227569Sphilip		break;
681227569Sphilip#endif	/* EFSYS_OPT_FALCON */
682227569Sphilip
683227569Sphilip#if EFSYS_OPT_SIENA
684227569Sphilip	case EFX_FAMILY_SIENA:
685227569Sphilip		eftp = &efp->ef_tbl[EFX_FILTER_TBL_RX_IP];
686227569Sphilip		eftp->eft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
687227569Sphilip
688227569Sphilip		eftp = &efp->ef_tbl[EFX_FILTER_TBL_RX_MAC];
689227569Sphilip		eftp->eft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
690227569Sphilip
691227569Sphilip		eftp = &efp->ef_tbl[EFX_FILTER_TBL_TX_IP];
692227569Sphilip		eftp->eft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
693227569Sphilip
694227569Sphilip		eftp = &efp->ef_tbl[EFX_FILTER_TBL_TX_MAC];
695227569Sphilip		eftp->eft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
696227569Sphilip		break;
697227569Sphilip#endif	/* EFSYS_OPT_SIENA */
698227569Sphilip
699227569Sphilip	default:
700227569Sphilip		rc = ENOTSUP;
701227569Sphilip		goto fail1;
702227569Sphilip	}
703227569Sphilip
704227569Sphilip	for (tbl_id = 0; tbl_id < EFX_FILTER_NTBLS; tbl_id++) {
705227569Sphilip		unsigned int bitmap_size;
706227569Sphilip
707227569Sphilip		eftp = &efp->ef_tbl[tbl_id];
708227569Sphilip		if (eftp->eft_size == 0)
709227569Sphilip			continue;
710227569Sphilip
711227569Sphilip		EFX_STATIC_ASSERT(sizeof(eftp->eft_bitmap[0]) == sizeof(uint32_t));
712227569Sphilip		bitmap_size = (eftp->eft_size + (sizeof(uint32_t) * 8) - 1) / 8;
713227569Sphilip
714227569Sphilip		EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, eftp->eft_bitmap);
715227569Sphilip		if (!eftp->eft_bitmap) {
716227569Sphilip			rc = ENOMEM;
717227569Sphilip			goto fail2;
718227569Sphilip		}
719227569Sphilip
720227569Sphilip		EFSYS_KMEM_ALLOC(enp->en_esip, eftp->eft_size * sizeof(*eftp->eft_spec),
721227569Sphilip		    eftp->eft_spec);
722227569Sphilip		if (!eftp->eft_spec) {
723227569Sphilip			rc = ENOMEM;
724227569Sphilip			goto fail2;
725227569Sphilip		}
726227569Sphilip		memset(eftp->eft_spec, 0, eftp->eft_size * sizeof(*eftp->eft_spec));
727227569Sphilip	}
728227569Sphilip	enp->en_mod_flags |= EFX_MOD_FILTER;
729227569Sphilip
730227569Sphilip	return (0);
731227569Sphilip
732227569Sphilipfail2:
733227569Sphilip	EFSYS_PROBE(fail2);
734227569Sphilip	efx_filter_fini(enp);
735227569Sphilip
736227569Sphilipfail1:
737227569Sphilip	EFSYS_PROBE1(fail1, int, rc);
738227569Sphilip	return (rc);
739227569Sphilip}
740227569Sphilip
741227569Sphilip			void
742227569Sphilipefx_filter_fini(
743227569Sphilip	__in		efx_nic_t *enp)
744227569Sphilip{
745227569Sphilip	efx_filter_t *efp = &enp->en_filter;
746227569Sphilip	efx_filter_tbl_id_t tbl_id;
747227569Sphilip
748227569Sphilip	EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
749227569Sphilip	EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
750227569Sphilip
751227569Sphilip	for (tbl_id = 0; tbl_id < EFX_FILTER_NTBLS; tbl_id++) {
752227569Sphilip		efx_filter_tbl_t *eftp = &efp->ef_tbl[tbl_id];
753227569Sphilip		unsigned int bitmap_size;
754227569Sphilip
755227569Sphilip		EFX_STATIC_ASSERT(sizeof(eftp->eft_bitmap[0]) == sizeof(uint32_t));
756227569Sphilip		bitmap_size = (eftp->eft_size + (sizeof(uint32_t) * 8) - 1) / 8;
757227569Sphilip
758227569Sphilip		EFSYS_KMEM_FREE(enp->en_esip, bitmap_size, eftp->eft_bitmap);
759227569Sphilip		eftp->eft_bitmap = NULL;
760227569Sphilip
761227569Sphilip		EFSYS_KMEM_FREE(enp->en_esip, eftp->eft_size * sizeof(*eftp->eft_spec),
762227569Sphilip		    eftp->eft_spec);
763227569Sphilip		eftp->eft_spec = NULL;
764227569Sphilip	}
765227569Sphilip
766227569Sphilip	enp->en_mod_flags &= ~EFX_MOD_FILTER;
767227569Sphilip}
768227569Sphilip
769227569Sphilipextern			void
770227569Sphilipefx_filter_spec_rx_ipv4_tcp_full(
771227569Sphilip	__inout		efx_filter_spec_t *spec,
772227569Sphilip	__in		unsigned int flags,
773227569Sphilip	__in		uint32_t src_ip,
774227569Sphilip	__in		uint16_t src_tcp,
775227569Sphilip	__in		uint32_t dest_ip,
776227569Sphilip	__in		uint16_t dest_tcp)
777227569Sphilip{
778227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
779227569Sphilip	EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
780227569Sphilip		    EFX_FILTER_FLAG_RX_SCATTER)) == 0);
781227569Sphilip
782227569Sphilip	spec->efs_type = EFX_FILTER_RX_TCP_FULL;
783227569Sphilip	spec->efs_flags = (uint8_t)flags;
784227569Sphilip	spec->efs_dword[0] = src_tcp | src_ip << 16;
785227569Sphilip	spec->efs_dword[1] = dest_tcp << 16 | src_ip >> 16;
786227569Sphilip	spec->efs_dword[2] = dest_ip;
787227569Sphilip}
788227569Sphilip
789227569Sphilipextern			void
790227569Sphilipefx_filter_spec_rx_ipv4_tcp_wild(
791227569Sphilip	__inout		efx_filter_spec_t *spec,
792227569Sphilip	__in		unsigned int flags,
793227569Sphilip	__in		uint32_t dest_ip,
794227569Sphilip	__in		uint16_t dest_tcp)
795227569Sphilip{
796227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
797227569Sphilip	EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
798227569Sphilip		    EFX_FILTER_FLAG_RX_SCATTER)) == 0);
799227569Sphilip
800227569Sphilip	spec->efs_type = EFX_FILTER_RX_TCP_WILD;
801227569Sphilip	spec->efs_flags = (uint8_t)flags;
802227569Sphilip	spec->efs_dword[0] = 0;
803227569Sphilip	spec->efs_dword[1] = dest_tcp << 16;
804227569Sphilip	spec->efs_dword[2] = dest_ip;
805227569Sphilip}
806227569Sphilip
807227569Sphilipextern			void
808227569Sphilipefx_filter_spec_rx_ipv4_udp_full(
809227569Sphilip	__inout		efx_filter_spec_t *spec,
810227569Sphilip	__in		unsigned int flags,
811227569Sphilip	__in		uint32_t src_ip,
812227569Sphilip	__in		uint16_t src_udp,
813227569Sphilip	__in		uint32_t dest_ip,
814227569Sphilip	__in		uint16_t dest_udp)
815227569Sphilip{
816227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
817227569Sphilip	EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
818227569Sphilip		    EFX_FILTER_FLAG_RX_SCATTER)) == 0);
819227569Sphilip
820227569Sphilip	spec->efs_type = EFX_FILTER_RX_UDP_FULL;
821227569Sphilip	spec->efs_flags = (uint8_t)flags;
822227569Sphilip	spec->efs_dword[0] = src_udp | src_ip << 16;
823227569Sphilip	spec->efs_dword[1] = dest_udp << 16 | src_ip >> 16;
824227569Sphilip	spec->efs_dword[2] = dest_ip;
825227569Sphilip}
826227569Sphilip
827227569Sphilipextern			void
828227569Sphilipefx_filter_spec_rx_ipv4_udp_wild(
829227569Sphilip	__inout		efx_filter_spec_t *spec,
830227569Sphilip	__in		unsigned int flags,
831227569Sphilip	__in		uint32_t dest_ip,
832227569Sphilip	__in		uint16_t dest_udp)
833227569Sphilip{
834227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
835227569Sphilip	EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
836227569Sphilip		    EFX_FILTER_FLAG_RX_SCATTER)) == 0);
837227569Sphilip
838227569Sphilip	spec->efs_type = EFX_FILTER_RX_UDP_WILD;
839227569Sphilip	spec->efs_flags = (uint8_t)flags;
840227569Sphilip	spec->efs_dword[0] = dest_udp;
841227569Sphilip	spec->efs_dword[1] = 0;
842227569Sphilip	spec->efs_dword[2] = dest_ip;
843227569Sphilip}
844227569Sphilip
845227569Sphilip#if EFSYS_OPT_SIENA
846227569Sphilipextern			void
847227569Sphilipefx_filter_spec_rx_mac_full(
848227569Sphilip	__inout		efx_filter_spec_t *spec,
849227569Sphilip	__in		unsigned int flags,
850227569Sphilip	__in		uint16_t vlan_id,
851227569Sphilip	__in		uint8_t *dest_mac)
852227569Sphilip{
853227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
854227569Sphilip	EFSYS_ASSERT3P(dest_mac, !=, NULL);
855227569Sphilip	EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
856227569Sphilip		    EFX_FILTER_FLAG_RX_SCATTER |
857227569Sphilip		    EFX_FILTER_FLAG_RX_OVERRIDE_IP)) == 0);
858227569Sphilip
859227569Sphilip	spec->efs_type = EFX_FILTER_RX_MAC_FULL;
860227569Sphilip	spec->efs_flags = (uint8_t)flags;
861227569Sphilip	spec->efs_dword[0] = vlan_id;
862227569Sphilip	spec->efs_dword[1] =
863227569Sphilip	    dest_mac[2] << 24 |
864227569Sphilip	    dest_mac[3] << 16 |
865227569Sphilip	    dest_mac[4] <<  8 |
866227569Sphilip	    dest_mac[5];
867227569Sphilip 	spec->efs_dword[2] =
868227569Sphilip	    dest_mac[0] <<  8 |
869227569Sphilip	    dest_mac[1];
870227569Sphilip}
871227569Sphilip#endif	/* EFSYS_OPT_SIENA */
872227569Sphilip
873227569Sphilip#if EFSYS_OPT_SIENA
874227569Sphilipextern			void
875227569Sphilipefx_filter_spec_rx_mac_wild(
876227569Sphilip	__inout		efx_filter_spec_t *spec,
877227569Sphilip	__in		unsigned int flags,
878227569Sphilip	__in		uint8_t *dest_mac)
879227569Sphilip{
880227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
881227569Sphilip	EFSYS_ASSERT3P(dest_mac, !=, NULL);
882227569Sphilip	EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
883227569Sphilip		    EFX_FILTER_FLAG_RX_SCATTER |
884227569Sphilip		    EFX_FILTER_FLAG_RX_OVERRIDE_IP)) == 0);
885227569Sphilip
886227569Sphilip	spec->efs_type = EFX_FILTER_RX_MAC_WILD;
887227569Sphilip	spec->efs_flags = (uint8_t)flags;
888227569Sphilip	spec->efs_dword[0] = 0;
889227569Sphilip	spec->efs_dword[1] =
890227569Sphilip	    dest_mac[2] << 24 |
891227569Sphilip	    dest_mac[3] << 16 |
892227569Sphilip	    dest_mac[4] <<  8 |
893227569Sphilip	    dest_mac[5];
894227569Sphilip 	spec->efs_dword[2] =
895227569Sphilip	    dest_mac[0] <<  8 |
896227569Sphilip	    dest_mac[1];
897227569Sphilip}
898227569Sphilip#endif	/* EFSYS_OPT_SIENA */
899227569Sphilip
900227569Sphilip#if EFSYS_OPT_SIENA
901227569Sphilipextern			void
902227569Sphilipefx_filter_spec_tx_ipv4_tcp_full(
903227569Sphilip	__inout		efx_filter_spec_t *spec,
904227569Sphilip	__in		uint32_t src_ip,
905227569Sphilip	__in		uint16_t src_tcp,
906227569Sphilip	__in		uint32_t dest_ip,
907227569Sphilip	__in		uint16_t dest_tcp)
908227569Sphilip{
909227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
910227569Sphilip
911227569Sphilip	spec->efs_type = EFX_FILTER_TX_TCP_FULL;
912227569Sphilip	spec->efs_flags = 0;
913227569Sphilip	spec->efs_dword[0] = src_tcp | src_ip << 16;
914227569Sphilip	spec->efs_dword[1] = dest_tcp << 16 | src_ip >> 16;
915227569Sphilip	spec->efs_dword[2] = dest_ip;
916227569Sphilip}
917227569Sphilip#endif	/* EFSYS_OPT_SIENA */
918227569Sphilip
919227569Sphilip#if EFSYS_OPT_SIENA
920227569Sphilipextern			void
921227569Sphilipefx_filter_spec_tx_ipv4_tcp_wild(
922227569Sphilip	__inout		efx_filter_spec_t *spec,
923227569Sphilip	__in		uint32_t src_ip,
924227569Sphilip	__in		uint16_t src_tcp)
925227569Sphilip{
926227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
927227569Sphilip
928227569Sphilip	spec->efs_type = EFX_FILTER_TX_TCP_WILD;
929227569Sphilip	spec->efs_flags = 0;
930227569Sphilip	spec->efs_dword[0] = 0;
931227569Sphilip	spec->efs_dword[1] = src_tcp << 16;
932227569Sphilip	spec->efs_dword[2] = src_ip;
933227569Sphilip}
934227569Sphilip#endif	/* EFSYS_OPT_SIENA */
935227569Sphilip
936227569Sphilip#if EFSYS_OPT_SIENA
937227569Sphilipextern			void
938227569Sphilipefx_filter_spec_tx_ipv4_udp_full(
939227569Sphilip	__inout		efx_filter_spec_t *spec,
940227569Sphilip	__in		uint32_t src_ip,
941227569Sphilip	__in		uint16_t src_udp,
942227569Sphilip	__in		uint32_t dest_ip,
943227569Sphilip	__in		uint16_t dest_udp)
944227569Sphilip{
945227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
946227569Sphilip
947227569Sphilip	spec->efs_type = EFX_FILTER_TX_UDP_FULL;
948227569Sphilip	spec->efs_flags = 0;
949227569Sphilip	spec->efs_dword[0] = src_udp | src_ip << 16;
950227569Sphilip	spec->efs_dword[1] = dest_udp << 16 | src_ip >> 16;
951227569Sphilip	spec->efs_dword[2] = dest_ip;
952227569Sphilip}
953227569Sphilip#endif	/* EFSYS_OPT_SIENA */
954227569Sphilip
955227569Sphilip#if EFSYS_OPT_SIENA
956227569Sphilipextern			void
957227569Sphilipefx_filter_spec_tx_ipv4_udp_wild(
958227569Sphilip	__inout		efx_filter_spec_t *spec,
959227569Sphilip	__in		uint32_t src_ip,
960227569Sphilip	__in		uint16_t src_udp)
961227569Sphilip{
962227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
963227569Sphilip
964227569Sphilip	spec->efs_type = EFX_FILTER_TX_UDP_WILD;
965227569Sphilip	spec->efs_flags = 0;
966227569Sphilip	spec->efs_dword[0] = src_udp;
967227569Sphilip	spec->efs_dword[1] = 0;
968227569Sphilip	spec->efs_dword[2] = src_ip;
969227569Sphilip}
970227569Sphilip#endif	/* EFSYS_OPT_SIENA */
971227569Sphilip
972227569Sphilip#if EFSYS_OPT_SIENA
973227569Sphilipextern			void
974227569Sphilipefx_filter_spec_tx_mac_full(
975227569Sphilip	__inout		efx_filter_spec_t *spec,
976227569Sphilip	__in		uint16_t vlan_id,
977227569Sphilip	__in		uint8_t *src_mac)
978227569Sphilip{
979227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
980227569Sphilip	EFSYS_ASSERT3P(src_mac, !=, NULL);
981227569Sphilip
982227569Sphilip	spec->efs_type = EFX_FILTER_TX_MAC_FULL;
983227569Sphilip	spec->efs_flags = 0;
984227569Sphilip	spec->efs_dword[0] = vlan_id;
985227569Sphilip	spec->efs_dword[1] =
986227569Sphilip	    src_mac[2] << 24 |
987227569Sphilip	    src_mac[3] << 16 |
988227569Sphilip	    src_mac[4] <<  8 |
989227569Sphilip	    src_mac[5];
990227569Sphilip 	spec->efs_dword[2] =
991227569Sphilip	    src_mac[0] <<  8 |
992227569Sphilip	    src_mac[1];
993227569Sphilip}
994227569Sphilip#endif	/* EFSYS_OPT_SIENA */
995227569Sphilip
996227569Sphilip#if EFSYS_OPT_SIENA
997227569Sphilipextern			void
998227569Sphilipefx_filter_spec_tx_mac_wild(
999227569Sphilip	__inout		efx_filter_spec_t *spec,
1000227569Sphilip	__in		uint8_t *src_mac)
1001227569Sphilip{
1002227569Sphilip	EFSYS_ASSERT3P(spec, !=, NULL);
1003227569Sphilip	EFSYS_ASSERT3P(src_mac, !=, NULL);
1004227569Sphilip
1005227569Sphilip	spec->efs_type = EFX_FILTER_TX_MAC_WILD;
1006227569Sphilip	spec->efs_flags = 0;
1007227569Sphilip	spec->efs_dword[0] = 0;
1008227569Sphilip	spec->efs_dword[1] =
1009227569Sphilip	    src_mac[2] << 24 |
1010227569Sphilip	    src_mac[3] << 16 |
1011227569Sphilip	    src_mac[4] <<  8 |
1012227569Sphilip	    src_mac[5];
1013227569Sphilip 	spec->efs_dword[2] =
1014227569Sphilip	    src_mac[0] <<  8 |
1015227569Sphilip	    src_mac[1];
1016227569Sphilip}
1017227569Sphilip#endif	/* EFSYS_OPT_SIENA */
1018227569Sphilip
1019227569Sphilip
1020227569Sphilip#endif /* EFSYS_OPT_FILTER */
1021