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