1283514Sarybchik/*- 2300607Sarybchik * Copyright (c) 2007-2016 Solarflare Communications Inc. 3283514Sarybchik * All rights reserved. 4283514Sarybchik * 5283514Sarybchik * Redistribution and use in source and binary forms, with or without 6283514Sarybchik * modification, are permitted provided that the following conditions are met: 7283514Sarybchik * 8283514Sarybchik * 1. Redistributions of source code must retain the above copyright notice, 9283514Sarybchik * this list of conditions and the following disclaimer. 10283514Sarybchik * 2. Redistributions in binary form must reproduce the above copyright notice, 11283514Sarybchik * this list of conditions and the following disclaimer in the documentation 12283514Sarybchik * and/or other materials provided with the distribution. 13283514Sarybchik * 14283514Sarybchik * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15283514Sarybchik * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16283514Sarybchik * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17283514Sarybchik * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18283514Sarybchik * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19283514Sarybchik * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20283514Sarybchik * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21283514Sarybchik * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22283514Sarybchik * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23283514Sarybchik * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24283514Sarybchik * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25283514Sarybchik * 26283514Sarybchik * The views and conclusions contained in the software and documentation are 27283514Sarybchik * those of the authors and should not be interpreted as representing official 28283514Sarybchik * policies, either expressed or implied, of the FreeBSD Project. 29283514Sarybchik */ 30283514Sarybchik 31283514Sarybchik#include <sys/cdefs.h> 32283514Sarybchik__FBSDID("$FreeBSD: stable/11/sys/dev/sfxge/common/ef10_filter.c 342447 2018-12-25 07:30:53Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efx.h" 35283514Sarybchik#include "efx_impl.h" 36283514Sarybchik 37299597Sarybchik#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 38283514Sarybchik 39283514Sarybchik#if EFSYS_OPT_FILTER 40283514Sarybchik 41293764Sarybchik#define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec) 42283514Sarybchik 43283514Sarybchikstatic efx_filter_spec_t * 44293764Sarybchikef10_filter_entry_spec( 45293764Sarybchik __in const ef10_filter_table_t *eftp, 46283514Sarybchik __in unsigned int index) 47283514Sarybchik{ 48293764Sarybchik return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) & 49293764Sarybchik ~(uintptr_t)EFX_EF10_FILTER_FLAGS)); 50283514Sarybchik} 51283514Sarybchik 52283514Sarybchikstatic boolean_t 53293764Sarybchikef10_filter_entry_is_busy( 54293764Sarybchik __in const ef10_filter_table_t *eftp, 55283514Sarybchik __in unsigned int index) 56283514Sarybchik{ 57293764Sarybchik if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY) 58283514Sarybchik return (B_TRUE); 59283514Sarybchik else 60283514Sarybchik return (B_FALSE); 61283514Sarybchik} 62283514Sarybchik 63283514Sarybchikstatic boolean_t 64293764Sarybchikef10_filter_entry_is_auto_old( 65293764Sarybchik __in const ef10_filter_table_t *eftp, 66283514Sarybchik __in unsigned int index) 67283514Sarybchik{ 68293764Sarybchik if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD) 69283514Sarybchik return (B_TRUE); 70283514Sarybchik else 71283514Sarybchik return (B_FALSE); 72283514Sarybchik} 73283514Sarybchik 74283514Sarybchikstatic void 75293764Sarybchikef10_filter_set_entry( 76293764Sarybchik __inout ef10_filter_table_t *eftp, 77283514Sarybchik __in unsigned int index, 78283514Sarybchik __in_opt const efx_filter_spec_t *efsp) 79283514Sarybchik{ 80293764Sarybchik EFE_SPEC(eftp, index) = (uintptr_t)efsp; 81283514Sarybchik} 82283514Sarybchik 83283514Sarybchikstatic void 84293764Sarybchikef10_filter_set_entry_busy( 85293764Sarybchik __inout ef10_filter_table_t *eftp, 86283514Sarybchik __in unsigned int index) 87283514Sarybchik{ 88293764Sarybchik EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 89283514Sarybchik} 90283514Sarybchik 91283514Sarybchikstatic void 92293764Sarybchikef10_filter_set_entry_not_busy( 93293764Sarybchik __inout ef10_filter_table_t *eftp, 94283514Sarybchik __in unsigned int index) 95283514Sarybchik{ 96293764Sarybchik EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 97283514Sarybchik} 98283514Sarybchik 99283514Sarybchikstatic void 100293764Sarybchikef10_filter_set_entry_auto_old( 101293764Sarybchik __inout ef10_filter_table_t *eftp, 102283514Sarybchik __in unsigned int index) 103283514Sarybchik{ 104293764Sarybchik EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 105293764Sarybchik EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 106283514Sarybchik} 107283514Sarybchik 108283514Sarybchikstatic void 109293764Sarybchikef10_filter_set_entry_not_auto_old( 110293764Sarybchik __inout ef10_filter_table_t *eftp, 111283514Sarybchik __in unsigned int index) 112283514Sarybchik{ 113293764Sarybchik EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 114293764Sarybchik EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 115283514Sarybchik} 116283514Sarybchik 117291436Sarybchik __checkReturn efx_rc_t 118293764Sarybchikef10_filter_init( 119283514Sarybchik __in efx_nic_t *enp) 120283514Sarybchik{ 121291436Sarybchik efx_rc_t rc; 122293764Sarybchik ef10_filter_table_t *eftp; 123283514Sarybchik 124293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 125293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 126283514Sarybchik 127283514Sarybchik#define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match)) 128283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST == 129342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_IP)); 130283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == 131342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_IP)); 132283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == 133342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_MAC)); 134283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == 135342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_SRC_PORT)); 136283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == 137342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_MAC)); 138283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == 139342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_DST_PORT)); 140283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == 141342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_ETHER_TYPE)); 142283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == 143342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_INNER_VLAN)); 144283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == 145342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_OUTER_VLAN)); 146283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == 147342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IP_PROTO)); 148342415Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST == 149342415Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_MCAST_DST)); 150342415Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST == 151342415Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_IFRM_UNKNOWN_UCAST_DST)); 152311484Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_UNKNOWN_MCAST_DST == 153342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_MCAST_DST)); 154311484Sarybchik EFX_STATIC_ASSERT((uint32_t)EFX_FILTER_MATCH_UNKNOWN_UCAST_DST == 155342414Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_EXT_IN_MATCH_UNKNOWN_UCAST_DST)); 156283514Sarybchik#undef MATCH_MASK 157283514Sarybchik 158293764Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp); 159283514Sarybchik 160293764Sarybchik if (!eftp) { 161283514Sarybchik rc = ENOMEM; 162283514Sarybchik goto fail1; 163283514Sarybchik } 164283514Sarybchik 165293764Sarybchik enp->en_filter.ef_ef10_filter_table = eftp; 166283514Sarybchik 167283514Sarybchik return (0); 168283514Sarybchik 169283514Sarybchikfail1: 170291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 171283514Sarybchik 172283514Sarybchik return (rc); 173283514Sarybchik} 174283514Sarybchik 175283514Sarybchik void 176293764Sarybchikef10_filter_fini( 177283514Sarybchik __in efx_nic_t *enp) 178283514Sarybchik{ 179293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 180293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 181283514Sarybchik 182293764Sarybchik if (enp->en_filter.ef_ef10_filter_table != NULL) { 183293764Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t), 184293764Sarybchik enp->en_filter.ef_ef10_filter_table); 185283514Sarybchik } 186283514Sarybchik} 187283514Sarybchik 188291436Sarybchikstatic __checkReturn efx_rc_t 189283514Sarybchikefx_mcdi_filter_op_add( 190283514Sarybchik __in efx_nic_t *enp, 191283514Sarybchik __in efx_filter_spec_t *spec, 192283514Sarybchik __in unsigned int filter_op, 193293764Sarybchik __inout ef10_filter_handle_t *handle) 194283514Sarybchik{ 195283514Sarybchik efx_mcdi_req_t req; 196342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_EXT_IN_LEN, 197342445Sarybchik MC_CMD_FILTER_OP_EXT_OUT_LEN); 198291436Sarybchik efx_rc_t rc; 199283514Sarybchik 200283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 201283514Sarybchik req.emr_in_buf = payload; 202342414Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN; 203283514Sarybchik req.emr_out_buf = payload; 204342414Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN; 205283514Sarybchik 206283514Sarybchik switch (filter_op) { 207283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REPLACE: 208342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO, 209293764Sarybchik handle->efh_lo); 210342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI, 211293764Sarybchik handle->efh_hi); 212283514Sarybchik /* Fall through */ 213283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_INSERT: 214283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: 215342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, filter_op); 216283514Sarybchik break; 217283514Sarybchik default: 218283514Sarybchik EFSYS_ASSERT(0); 219283514Sarybchik rc = EINVAL; 220283514Sarybchik goto fail1; 221283514Sarybchik } 222283514Sarybchik 223342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_PORT_ID, 224283514Sarybchik EVB_PORT_ID_ASSIGNED); 225342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_MATCH_FIELDS, 226311484Sarybchik spec->efs_match_flags); 227342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_DEST, 228342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_RX_DEST_HOST); 229342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_QUEUE, 230283514Sarybchik spec->efs_dmaq_id); 231283514Sarybchik if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { 232342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_CONTEXT, 233283514Sarybchik spec->efs_rss_context); 234283514Sarybchik } 235342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_RX_MODE, 236283514Sarybchik spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? 237342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_RX_MODE_RSS : 238342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_RX_MODE_SIMPLE); 239342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_TX_DEST, 240342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_TX_DEST_DEFAULT); 241283514Sarybchik 242283514Sarybchik if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { 243283514Sarybchik /* 244283514Sarybchik * NOTE: Unlike most MCDI requests, the filter fields 245283514Sarybchik * are presented in network (big endian) byte order. 246283514Sarybchik */ 247342414Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_MAC), 248283514Sarybchik spec->efs_rem_mac, EFX_MAC_ADDR_LEN); 249342414Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_MAC), 250283514Sarybchik spec->efs_loc_mac, EFX_MAC_ADDR_LEN); 251283514Sarybchik 252342414Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_SRC_PORT, 253283514Sarybchik __CPU_TO_BE_16(spec->efs_rem_port)); 254342414Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_DST_PORT, 255283514Sarybchik __CPU_TO_BE_16(spec->efs_loc_port)); 256283514Sarybchik 257342414Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_ETHER_TYPE, 258283514Sarybchik __CPU_TO_BE_16(spec->efs_ether_type)); 259283514Sarybchik 260342414Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_INNER_VLAN, 261283514Sarybchik __CPU_TO_BE_16(spec->efs_inner_vid)); 262342414Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_EXT_IN_OUTER_VLAN, 263283514Sarybchik __CPU_TO_BE_16(spec->efs_outer_vid)); 264283514Sarybchik 265283514Sarybchik /* IP protocol (in low byte, high byte is zero) */ 266342414Sarybchik MCDI_IN_SET_BYTE(req, FILTER_OP_EXT_IN_IP_PROTO, 267283514Sarybchik spec->efs_ip_proto); 268283514Sarybchik 269283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == 270342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN); 271283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == 272342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN); 273283514Sarybchik 274342414Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_SRC_IP), 275283514Sarybchik &spec->efs_rem_host.eo_byte[0], 276342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_SRC_IP_LEN); 277342414Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_EXT_IN_DST_IP), 278283514Sarybchik &spec->efs_loc_host.eo_byte[0], 279342414Sarybchik MC_CMD_FILTER_OP_EXT_IN_DST_IP_LEN); 280342415Sarybchik 281342415Sarybchik /* 282342415Sarybchik * On Medford, filters for encapsulated packets match based on 283342415Sarybchik * the ether type and IP protocol in the outer frame. In 284342415Sarybchik * addition we need to fill in the VNI or VSID type field. 285342415Sarybchik */ 286342415Sarybchik switch (spec->efs_encap_type) { 287342415Sarybchik case EFX_TUNNEL_PROTOCOL_NONE: 288342415Sarybchik break; 289342415Sarybchik case EFX_TUNNEL_PROTOCOL_VXLAN: 290342415Sarybchik case EFX_TUNNEL_PROTOCOL_GENEVE: 291342415Sarybchik MCDI_IN_POPULATE_DWORD_1(req, 292342415Sarybchik FILTER_OP_EXT_IN_VNI_OR_VSID, 293342415Sarybchik FILTER_OP_EXT_IN_VNI_TYPE, 294342415Sarybchik spec->efs_encap_type == EFX_TUNNEL_PROTOCOL_VXLAN ? 295342415Sarybchik MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_VXLAN : 296342415Sarybchik MC_CMD_FILTER_OP_EXT_IN_VNI_TYPE_GENEVE); 297342415Sarybchik break; 298342415Sarybchik case EFX_TUNNEL_PROTOCOL_NVGRE: 299342415Sarybchik MCDI_IN_POPULATE_DWORD_1(req, 300342415Sarybchik FILTER_OP_EXT_IN_VNI_OR_VSID, 301342415Sarybchik FILTER_OP_EXT_IN_VSID_TYPE, 302342415Sarybchik MC_CMD_FILTER_OP_EXT_IN_VSID_TYPE_NVGRE); 303342415Sarybchik break; 304342415Sarybchik default: 305342415Sarybchik EFSYS_ASSERT(0); 306342415Sarybchik rc = EINVAL; 307342415Sarybchik goto fail2; 308342415Sarybchik } 309283514Sarybchik } 310283514Sarybchik 311283514Sarybchik efx_mcdi_execute(enp, &req); 312283514Sarybchik 313283514Sarybchik if (req.emr_rc != 0) { 314283514Sarybchik rc = req.emr_rc; 315342415Sarybchik goto fail3; 316283514Sarybchik } 317283514Sarybchik 318342414Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) { 319283514Sarybchik rc = EMSGSIZE; 320342415Sarybchik goto fail4; 321283514Sarybchik } 322283514Sarybchik 323342414Sarybchik handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_LO); 324342414Sarybchik handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_EXT_OUT_HANDLE_HI); 325283514Sarybchik 326283514Sarybchik return (0); 327283514Sarybchik 328342415Sarybchikfail4: 329342415Sarybchik EFSYS_PROBE(fail4); 330283514Sarybchikfail3: 331283514Sarybchik EFSYS_PROBE(fail3); 332283514Sarybchikfail2: 333283514Sarybchik EFSYS_PROBE(fail2); 334283514Sarybchikfail1: 335291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 336283514Sarybchik 337283514Sarybchik return (rc); 338283514Sarybchik 339283514Sarybchik} 340283514Sarybchik 341291436Sarybchikstatic __checkReturn efx_rc_t 342283514Sarybchikefx_mcdi_filter_op_delete( 343283514Sarybchik __in efx_nic_t *enp, 344283514Sarybchik __in unsigned int filter_op, 345293764Sarybchik __inout ef10_filter_handle_t *handle) 346283514Sarybchik{ 347283514Sarybchik efx_mcdi_req_t req; 348342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_FILTER_OP_EXT_IN_LEN, 349342445Sarybchik MC_CMD_FILTER_OP_EXT_OUT_LEN); 350291436Sarybchik efx_rc_t rc; 351283514Sarybchik 352283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 353283514Sarybchik req.emr_in_buf = payload; 354342414Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_EXT_IN_LEN; 355283514Sarybchik req.emr_out_buf = payload; 356342414Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_EXT_OUT_LEN; 357283514Sarybchik 358283514Sarybchik switch (filter_op) { 359283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REMOVE: 360342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, 361283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE); 362283514Sarybchik break; 363283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: 364342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_OP, 365283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); 366283514Sarybchik break; 367283514Sarybchik default: 368283514Sarybchik EFSYS_ASSERT(0); 369283514Sarybchik rc = EINVAL; 370283514Sarybchik goto fail1; 371283514Sarybchik } 372283514Sarybchik 373342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_LO, handle->efh_lo); 374342414Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_EXT_IN_HANDLE_HI, handle->efh_hi); 375283514Sarybchik 376299925Sarybchik efx_mcdi_execute_quiet(enp, &req); 377283514Sarybchik 378283514Sarybchik if (req.emr_rc != 0) { 379283514Sarybchik rc = req.emr_rc; 380283514Sarybchik goto fail2; 381283514Sarybchik } 382283514Sarybchik 383342414Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_EXT_OUT_LEN) { 384283514Sarybchik rc = EMSGSIZE; 385283514Sarybchik goto fail3; 386283514Sarybchik } 387283514Sarybchik 388283514Sarybchik return (0); 389283514Sarybchik 390283514Sarybchikfail3: 391283514Sarybchik EFSYS_PROBE(fail3); 392283514Sarybchik 393283514Sarybchikfail2: 394283514Sarybchik EFSYS_PROBE(fail2); 395283514Sarybchikfail1: 396291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 397283514Sarybchik 398283514Sarybchik return (rc); 399283514Sarybchik} 400283514Sarybchik 401283514Sarybchikstatic __checkReturn boolean_t 402293764Sarybchikef10_filter_equal( 403283514Sarybchik __in const efx_filter_spec_t *left, 404283514Sarybchik __in const efx_filter_spec_t *right) 405283514Sarybchik{ 406283514Sarybchik /* FIXME: Consider rx vs tx filters (look at efs_flags) */ 407283514Sarybchik if (left->efs_match_flags != right->efs_match_flags) 408283514Sarybchik return (B_FALSE); 409283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) 410283514Sarybchik return (B_FALSE); 411283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) 412283514Sarybchik return (B_FALSE); 413283514Sarybchik if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) 414283514Sarybchik return (B_FALSE); 415283514Sarybchik if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) 416283514Sarybchik return (B_FALSE); 417283514Sarybchik if (left->efs_rem_port != right->efs_rem_port) 418283514Sarybchik return (B_FALSE); 419283514Sarybchik if (left->efs_loc_port != right->efs_loc_port) 420283514Sarybchik return (B_FALSE); 421283514Sarybchik if (left->efs_inner_vid != right->efs_inner_vid) 422283514Sarybchik return (B_FALSE); 423283514Sarybchik if (left->efs_outer_vid != right->efs_outer_vid) 424283514Sarybchik return (B_FALSE); 425283514Sarybchik if (left->efs_ether_type != right->efs_ether_type) 426283514Sarybchik return (B_FALSE); 427283514Sarybchik if (left->efs_ip_proto != right->efs_ip_proto) 428283514Sarybchik return (B_FALSE); 429342415Sarybchik if (left->efs_encap_type != right->efs_encap_type) 430342415Sarybchik return (B_FALSE); 431283514Sarybchik 432283514Sarybchik return (B_TRUE); 433283514Sarybchik 434283514Sarybchik} 435283514Sarybchik 436283514Sarybchikstatic __checkReturn boolean_t 437293764Sarybchikef10_filter_same_dest( 438283514Sarybchik __in const efx_filter_spec_t *left, 439283514Sarybchik __in const efx_filter_spec_t *right) 440283514Sarybchik{ 441283514Sarybchik if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 442283514Sarybchik (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { 443283514Sarybchik if (left->efs_rss_context == right->efs_rss_context) 444283514Sarybchik return (B_TRUE); 445283514Sarybchik } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && 446283514Sarybchik (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { 447283514Sarybchik if (left->efs_dmaq_id == right->efs_dmaq_id) 448283514Sarybchik return (B_TRUE); 449283514Sarybchik } 450283514Sarybchik return (B_FALSE); 451283514Sarybchik} 452283514Sarybchik 453283514Sarybchikstatic __checkReturn uint32_t 454293764Sarybchikef10_filter_hash( 455283514Sarybchik __in efx_filter_spec_t *spec) 456283514Sarybchik{ 457283514Sarybchik EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) 458283514Sarybchik == 0); 459283514Sarybchik EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % 460283514Sarybchik sizeof (uint32_t)) == 0); 461283514Sarybchik 462283514Sarybchik /* 463283514Sarybchik * As the area of the efx_filter_spec_t we need to hash is DWORD 464283514Sarybchik * aligned and an exact number of DWORDs in size we can use the 465283514Sarybchik * optimised efx_hash_dwords() rather than efx_hash_bytes() 466283514Sarybchik */ 467283514Sarybchik return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid, 468283514Sarybchik (sizeof (efx_filter_spec_t) - 469283514Sarybchik EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / 470283514Sarybchik sizeof (uint32_t), 0)); 471283514Sarybchik} 472283514Sarybchik 473283514Sarybchik/* 474283514Sarybchik * Decide whether a filter should be exclusive or else should allow 475283514Sarybchik * delivery to additional recipients. Currently we decide that 476283514Sarybchik * filters for specific local unicast MAC and IP addresses are 477283514Sarybchik * exclusive. 478283514Sarybchik */ 479283514Sarybchikstatic __checkReturn boolean_t 480293764Sarybchikef10_filter_is_exclusive( 481283514Sarybchik __in efx_filter_spec_t *spec) 482283514Sarybchik{ 483283514Sarybchik if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && 484283514Sarybchik !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 485283514Sarybchik return (B_TRUE); 486283514Sarybchik 487283514Sarybchik if ((spec->efs_match_flags & 488283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == 489283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { 490283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && 491283514Sarybchik ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) 492283514Sarybchik return (B_TRUE); 493283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && 494283514Sarybchik (spec->efs_loc_host.eo_u8[0] != 0xff)) 495283514Sarybchik return (B_TRUE); 496283514Sarybchik } 497283514Sarybchik 498283514Sarybchik return (B_FALSE); 499283514Sarybchik} 500283514Sarybchik 501291436Sarybchik __checkReturn efx_rc_t 502293764Sarybchikef10_filter_restore( 503283514Sarybchik __in efx_nic_t *enp) 504283514Sarybchik{ 505283514Sarybchik int tbl_id; 506283514Sarybchik efx_filter_spec_t *spec; 507293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 508283514Sarybchik boolean_t restoring; 509311032Sarybchik efsys_lock_state_t state; 510291436Sarybchik efx_rc_t rc; 511283514Sarybchik 512293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 513293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 514283514Sarybchik 515293764Sarybchik for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) { 516283514Sarybchik 517283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 518283514Sarybchik 519293764Sarybchik spec = ef10_filter_entry_spec(eftp, tbl_id); 520283514Sarybchik if (spec == NULL) { 521283514Sarybchik restoring = B_FALSE; 522293764Sarybchik } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) { 523283514Sarybchik /* Ignore busy entries. */ 524283514Sarybchik restoring = B_FALSE; 525283514Sarybchik } else { 526293764Sarybchik ef10_filter_set_entry_busy(eftp, tbl_id); 527283514Sarybchik restoring = B_TRUE; 528283514Sarybchik } 529283514Sarybchik 530283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 531283514Sarybchik 532283514Sarybchik if (restoring == B_FALSE) 533283514Sarybchik continue; 534283514Sarybchik 535293764Sarybchik if (ef10_filter_is_exclusive(spec)) { 536283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 537283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 538293764Sarybchik &eftp->eft_entry[tbl_id].efe_handle); 539283514Sarybchik } else { 540283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 541283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 542293764Sarybchik &eftp->eft_entry[tbl_id].efe_handle); 543283514Sarybchik } 544283514Sarybchik 545283514Sarybchik if (rc != 0) 546283514Sarybchik goto fail1; 547283514Sarybchik 548283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 549283514Sarybchik 550293764Sarybchik ef10_filter_set_entry_not_busy(eftp, tbl_id); 551283514Sarybchik 552283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 553283514Sarybchik } 554283514Sarybchik 555283514Sarybchik return (0); 556283514Sarybchik 557283514Sarybchikfail1: 558291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 559283514Sarybchik 560283514Sarybchik return (rc); 561283514Sarybchik} 562283514Sarybchik 563283514Sarybchik/* 564283514Sarybchik * An arbitrary search limit for the software hash table. As per the linux net 565283514Sarybchik * driver. 566283514Sarybchik */ 567293764Sarybchik#define EF10_FILTER_SEARCH_LIMIT 200 568283514Sarybchik 569291436Sarybchikstatic __checkReturn efx_rc_t 570293764Sarybchikef10_filter_add_internal( 571283514Sarybchik __in efx_nic_t *enp, 572283514Sarybchik __inout efx_filter_spec_t *spec, 573283514Sarybchik __in boolean_t may_replace, 574283514Sarybchik __out_opt uint32_t *filter_id) 575283514Sarybchik{ 576291436Sarybchik efx_rc_t rc; 577293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 578283514Sarybchik efx_filter_spec_t *saved_spec; 579283514Sarybchik uint32_t hash; 580283514Sarybchik unsigned int depth; 581283514Sarybchik int ins_index; 582283514Sarybchik boolean_t replacing = B_FALSE; 583283514Sarybchik unsigned int i; 584311032Sarybchik efsys_lock_state_t state; 585283514Sarybchik boolean_t locked = B_FALSE; 586283514Sarybchik 587293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 588293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 589283514Sarybchik 590283514Sarybchik#if EFSYS_OPT_RX_SCALE 591283514Sarybchik spec->efs_rss_context = enp->en_rss_context; 592283514Sarybchik#endif 593283514Sarybchik 594293764Sarybchik hash = ef10_filter_hash(spec); 595283514Sarybchik 596283514Sarybchik /* 597283514Sarybchik * FIXME: Add support for inserting filters of different priorities 598283514Sarybchik * and removing lower priority multicast filters (bug 42378) 599283514Sarybchik */ 600283514Sarybchik 601283514Sarybchik /* 602283514Sarybchik * Find any existing filters with the same match tuple or 603283514Sarybchik * else a free slot to insert at. If any of them are busy, 604283514Sarybchik * we have to wait and retry. 605283514Sarybchik */ 606283514Sarybchik for (;;) { 607283514Sarybchik ins_index = -1; 608283514Sarybchik depth = 1; 609283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 610283514Sarybchik locked = B_TRUE; 611283514Sarybchik 612283514Sarybchik for (;;) { 613293764Sarybchik i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 614293764Sarybchik saved_spec = ef10_filter_entry_spec(eftp, i); 615283514Sarybchik 616283514Sarybchik if (!saved_spec) { 617283514Sarybchik if (ins_index < 0) { 618283514Sarybchik ins_index = i; 619283514Sarybchik } 620293764Sarybchik } else if (ef10_filter_equal(spec, saved_spec)) { 621293764Sarybchik if (ef10_filter_entry_is_busy(eftp, i)) 622283514Sarybchik break; 623283514Sarybchik if (saved_spec->efs_priority 624283514Sarybchik == EFX_FILTER_PRI_AUTO) { 625283514Sarybchik ins_index = i; 626283514Sarybchik goto found; 627293764Sarybchik } else if (ef10_filter_is_exclusive(spec)) { 628283514Sarybchik if (may_replace) { 629283514Sarybchik ins_index = i; 630283514Sarybchik goto found; 631283514Sarybchik } else { 632283514Sarybchik rc = EEXIST; 633283514Sarybchik goto fail1; 634283514Sarybchik } 635283514Sarybchik } 636283514Sarybchik 637283514Sarybchik /* Leave existing */ 638283514Sarybchik } 639283514Sarybchik 640283514Sarybchik /* 641283514Sarybchik * Once we reach the maximum search depth, use 642283514Sarybchik * the first suitable slot or return EBUSY if 643283514Sarybchik * there was none. 644283514Sarybchik */ 645293764Sarybchik if (depth == EF10_FILTER_SEARCH_LIMIT) { 646283514Sarybchik if (ins_index < 0) { 647283514Sarybchik rc = EBUSY; 648283514Sarybchik goto fail2; 649283514Sarybchik } 650283514Sarybchik goto found; 651283514Sarybchik } 652283514Sarybchik depth++; 653283514Sarybchik } 654283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 655283514Sarybchik locked = B_FALSE; 656283514Sarybchik } 657283514Sarybchik 658283514Sarybchikfound: 659283514Sarybchik /* 660283514Sarybchik * Create a software table entry if necessary, and mark it 661283514Sarybchik * busy. We might yet fail to insert, but any attempt to 662283514Sarybchik * insert a conflicting filter while we're waiting for the 663283514Sarybchik * firmware must find the busy entry. 664283514Sarybchik */ 665293764Sarybchik saved_spec = ef10_filter_entry_spec(eftp, ins_index); 666283514Sarybchik if (saved_spec) { 667283514Sarybchik if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { 668283514Sarybchik /* This is a filter we are refreshing */ 669293764Sarybchik ef10_filter_set_entry_not_auto_old(eftp, ins_index); 670283514Sarybchik goto out_unlock; 671283514Sarybchik 672283514Sarybchik } 673283514Sarybchik replacing = B_TRUE; 674283514Sarybchik } else { 675283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); 676283514Sarybchik if (!saved_spec) { 677283514Sarybchik rc = ENOMEM; 678283514Sarybchik goto fail3; 679283514Sarybchik } 680283514Sarybchik *saved_spec = *spec; 681293764Sarybchik ef10_filter_set_entry(eftp, ins_index, saved_spec); 682283514Sarybchik } 683293764Sarybchik ef10_filter_set_entry_busy(eftp, ins_index); 684283514Sarybchik 685283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 686283514Sarybchik locked = B_FALSE; 687283514Sarybchik 688283514Sarybchik /* 689283514Sarybchik * On replacing the filter handle may change after after a successful 690283514Sarybchik * replace operation. 691283514Sarybchik */ 692283514Sarybchik if (replacing) { 693283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 694283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REPLACE, 695293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 696293764Sarybchik } else if (ef10_filter_is_exclusive(spec)) { 697283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 698283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 699293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 700283514Sarybchik } else { 701283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 702283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 703293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 704283514Sarybchik } 705283514Sarybchik 706283514Sarybchik if (rc != 0) 707283514Sarybchik goto fail4; 708283514Sarybchik 709283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 710283514Sarybchik locked = B_TRUE; 711283514Sarybchik 712283514Sarybchik if (replacing) { 713283514Sarybchik /* Update the fields that may differ */ 714283514Sarybchik saved_spec->efs_priority = spec->efs_priority; 715283514Sarybchik saved_spec->efs_flags = spec->efs_flags; 716283514Sarybchik saved_spec->efs_rss_context = spec->efs_rss_context; 717283514Sarybchik saved_spec->efs_dmaq_id = spec->efs_dmaq_id; 718283514Sarybchik } 719283514Sarybchik 720293764Sarybchik ef10_filter_set_entry_not_busy(eftp, ins_index); 721283514Sarybchik 722283514Sarybchikout_unlock: 723283514Sarybchik 724283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 725283514Sarybchik locked = B_FALSE; 726283514Sarybchik 727283514Sarybchik if (filter_id) 728283514Sarybchik *filter_id = ins_index; 729283514Sarybchik 730283514Sarybchik return (0); 731283514Sarybchik 732283514Sarybchikfail4: 733283514Sarybchik EFSYS_PROBE(fail4); 734283514Sarybchik 735283514Sarybchik if (!replacing) { 736283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); 737283514Sarybchik saved_spec = NULL; 738283514Sarybchik } 739293764Sarybchik ef10_filter_set_entry_not_busy(eftp, ins_index); 740293764Sarybchik ef10_filter_set_entry(eftp, ins_index, NULL); 741283514Sarybchik 742283514Sarybchikfail3: 743283514Sarybchik EFSYS_PROBE(fail3); 744283514Sarybchik 745283514Sarybchikfail2: 746283514Sarybchik EFSYS_PROBE(fail2); 747283514Sarybchik 748283514Sarybchikfail1: 749291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 750283514Sarybchik 751283514Sarybchik if (locked) 752283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 753283514Sarybchik 754283514Sarybchik return (rc); 755283514Sarybchik} 756283514Sarybchik 757291436Sarybchik __checkReturn efx_rc_t 758293764Sarybchikef10_filter_add( 759283514Sarybchik __in efx_nic_t *enp, 760283514Sarybchik __inout efx_filter_spec_t *spec, 761283514Sarybchik __in boolean_t may_replace) 762283514Sarybchik{ 763291436Sarybchik efx_rc_t rc; 764283514Sarybchik 765293764Sarybchik rc = ef10_filter_add_internal(enp, spec, may_replace, NULL); 766283514Sarybchik if (rc != 0) 767283514Sarybchik goto fail1; 768283514Sarybchik 769283514Sarybchik return (0); 770283514Sarybchik 771283514Sarybchikfail1: 772291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 773283514Sarybchik 774283514Sarybchik return (rc); 775283514Sarybchik} 776283514Sarybchik 777283514Sarybchik 778291436Sarybchikstatic __checkReturn efx_rc_t 779293764Sarybchikef10_filter_delete_internal( 780283514Sarybchik __in efx_nic_t *enp, 781283514Sarybchik __in uint32_t filter_id) 782283514Sarybchik{ 783291436Sarybchik efx_rc_t rc; 784293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 785283514Sarybchik efx_filter_spec_t *spec; 786311032Sarybchik efsys_lock_state_t state; 787293764Sarybchik uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS; 788283514Sarybchik 789283514Sarybchik /* 790283514Sarybchik * Find the software table entry and mark it busy. Don't 791283514Sarybchik * remove it yet; any attempt to update while we're waiting 792283514Sarybchik * for the firmware must find the busy entry. 793283514Sarybchik * 794283514Sarybchik * FIXME: What if the busy flag is never cleared? 795283514Sarybchik */ 796283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 797293764Sarybchik while (ef10_filter_entry_is_busy(table, filter_idx)) { 798283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 799283514Sarybchik EFSYS_SPIN(1); 800283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 801283514Sarybchik } 802293764Sarybchik if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) { 803293764Sarybchik ef10_filter_set_entry_busy(table, filter_idx); 804283514Sarybchik } 805283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 806283514Sarybchik 807283514Sarybchik if (spec == NULL) { 808283514Sarybchik rc = ENOENT; 809283514Sarybchik goto fail1; 810283514Sarybchik } 811283514Sarybchik 812283514Sarybchik /* 813283514Sarybchik * Try to remove the hardware filter. This may fail if the MC has 814283514Sarybchik * rebooted (which frees all hardware filter resources). 815283514Sarybchik */ 816293764Sarybchik if (ef10_filter_is_exclusive(spec)) { 817283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 818283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE, 819293764Sarybchik &table->eft_entry[filter_idx].efe_handle); 820283514Sarybchik } else { 821283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 822283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, 823293764Sarybchik &table->eft_entry[filter_idx].efe_handle); 824283514Sarybchik } 825283514Sarybchik 826283514Sarybchik /* Free the software table entry */ 827283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 828293764Sarybchik ef10_filter_set_entry_not_busy(table, filter_idx); 829293764Sarybchik ef10_filter_set_entry(table, filter_idx, NULL); 830283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 831283514Sarybchik 832283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 833283514Sarybchik 834283514Sarybchik /* Check result of hardware filter removal */ 835283514Sarybchik if (rc != 0) 836283514Sarybchik goto fail2; 837283514Sarybchik 838283514Sarybchik return (0); 839283514Sarybchik 840283514Sarybchikfail2: 841283514Sarybchik EFSYS_PROBE(fail2); 842283514Sarybchik 843283514Sarybchikfail1: 844291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 845283514Sarybchik 846283514Sarybchik return (rc); 847283514Sarybchik} 848283514Sarybchik 849291436Sarybchik __checkReturn efx_rc_t 850293764Sarybchikef10_filter_delete( 851283514Sarybchik __in efx_nic_t *enp, 852283514Sarybchik __inout efx_filter_spec_t *spec) 853283514Sarybchik{ 854291436Sarybchik efx_rc_t rc; 855293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 856283514Sarybchik efx_filter_spec_t *saved_spec; 857283514Sarybchik unsigned int hash; 858283514Sarybchik unsigned int depth; 859283514Sarybchik unsigned int i; 860311032Sarybchik efsys_lock_state_t state; 861283514Sarybchik boolean_t locked = B_FALSE; 862283514Sarybchik 863293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 864293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 865283514Sarybchik 866293764Sarybchik hash = ef10_filter_hash(spec); 867283514Sarybchik 868283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 869283514Sarybchik locked = B_TRUE; 870283514Sarybchik 871283514Sarybchik depth = 1; 872283514Sarybchik for (;;) { 873293764Sarybchik i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 874293764Sarybchik saved_spec = ef10_filter_entry_spec(table, i); 875293764Sarybchik if (saved_spec && ef10_filter_equal(spec, saved_spec) && 876293764Sarybchik ef10_filter_same_dest(spec, saved_spec)) { 877283514Sarybchik break; 878283514Sarybchik } 879293764Sarybchik if (depth == EF10_FILTER_SEARCH_LIMIT) { 880283514Sarybchik rc = ENOENT; 881283514Sarybchik goto fail1; 882283514Sarybchik } 883283514Sarybchik depth++; 884283514Sarybchik } 885283514Sarybchik 886283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 887283514Sarybchik locked = B_FALSE; 888283514Sarybchik 889293764Sarybchik rc = ef10_filter_delete_internal(enp, i); 890283514Sarybchik if (rc != 0) 891283514Sarybchik goto fail2; 892283514Sarybchik 893283514Sarybchik return (0); 894283514Sarybchik 895283514Sarybchikfail2: 896283514Sarybchik EFSYS_PROBE(fail2); 897283514Sarybchik 898283514Sarybchikfail1: 899291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 900283514Sarybchik 901283514Sarybchik if (locked) 902283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 903283514Sarybchik 904283514Sarybchik return (rc); 905283514Sarybchik} 906283514Sarybchik 907291436Sarybchikstatic __checkReturn efx_rc_t 908283514Sarybchikefx_mcdi_get_parser_disp_info( 909311485Sarybchik __in efx_nic_t *enp, 910311485Sarybchik __out_ecount(buffer_length) uint32_t *buffer, 911311485Sarybchik __in size_t buffer_length, 912311485Sarybchik __out size_t *list_lengthp) 913283514Sarybchik{ 914283514Sarybchik efx_mcdi_req_t req; 915342445Sarybchik EFX_MCDI_DECLARE_BUF(payload, MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, 916342445Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX); 917311485Sarybchik size_t matches_count; 918311485Sarybchik size_t list_size; 919291436Sarybchik efx_rc_t rc; 920283514Sarybchik 921283514Sarybchik req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; 922283514Sarybchik req.emr_in_buf = payload; 923283514Sarybchik req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; 924283514Sarybchik req.emr_out_buf = payload; 925283514Sarybchik req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; 926283514Sarybchik 927283514Sarybchik MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, 928283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); 929283514Sarybchik 930283514Sarybchik efx_mcdi_execute(enp, &req); 931283514Sarybchik 932283514Sarybchik if (req.emr_rc != 0) { 933283514Sarybchik rc = req.emr_rc; 934283514Sarybchik goto fail1; 935283514Sarybchik } 936283514Sarybchik 937311485Sarybchik matches_count = MCDI_OUT_DWORD(req, 938283514Sarybchik GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); 939283514Sarybchik 940283514Sarybchik if (req.emr_out_length_used < 941311485Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(matches_count)) { 942283514Sarybchik rc = EMSGSIZE; 943283514Sarybchik goto fail2; 944283514Sarybchik } 945283514Sarybchik 946311485Sarybchik *list_lengthp = matches_count; 947311485Sarybchik 948311485Sarybchik if (buffer_length < matches_count) { 949311485Sarybchik rc = ENOSPC; 950311485Sarybchik goto fail3; 951311485Sarybchik } 952311485Sarybchik 953311485Sarybchik /* 954311485Sarybchik * Check that the elements in the list in the MCDI response are the size 955311485Sarybchik * we expect, so we can just copy them directly. Any conversion of the 956311485Sarybchik * flags is handled by the caller. 957311485Sarybchik */ 958283514Sarybchik EFX_STATIC_ASSERT(sizeof (uint32_t) == 959283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); 960283514Sarybchik 961311485Sarybchik list_size = matches_count * 962311485Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN; 963311485Sarybchik memcpy(buffer, 964311485Sarybchik MCDI_OUT2(req, uint32_t, 965311485Sarybchik GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), 966311485Sarybchik list_size); 967311485Sarybchik 968283514Sarybchik return (0); 969283514Sarybchik 970311485Sarybchikfail3: 971311485Sarybchik EFSYS_PROBE(fail3); 972283514Sarybchikfail2: 973283514Sarybchik EFSYS_PROBE(fail2); 974283514Sarybchikfail1: 975291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 976283514Sarybchik 977283514Sarybchik return (rc); 978283514Sarybchik} 979283514Sarybchik 980291436Sarybchik __checkReturn efx_rc_t 981293764Sarybchikef10_filter_supported_filters( 982311485Sarybchik __in efx_nic_t *enp, 983311485Sarybchik __out_ecount(buffer_length) uint32_t *buffer, 984311485Sarybchik __in size_t buffer_length, 985311485Sarybchik __out size_t *list_lengthp) 986283514Sarybchik{ 987311485Sarybchik 988311485Sarybchik size_t mcdi_list_length; 989311485Sarybchik size_t list_length; 990311485Sarybchik uint32_t i; 991291436Sarybchik efx_rc_t rc; 992342429Sarybchik efx_filter_match_flags_t all_filter_flags = 993311485Sarybchik (EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_LOC_HOST | 994311485Sarybchik EFX_FILTER_MATCH_REM_MAC | EFX_FILTER_MATCH_REM_PORT | 995311485Sarybchik EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_LOC_PORT | 996311485Sarybchik EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_INNER_VID | 997311485Sarybchik EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_IP_PROTO | 998311485Sarybchik EFX_FILTER_MATCH_UNKNOWN_MCAST_DST | 999311485Sarybchik EFX_FILTER_MATCH_UNKNOWN_UCAST_DST); 1000283514Sarybchik 1001311485Sarybchik rc = efx_mcdi_get_parser_disp_info(enp, buffer, buffer_length, 1002311485Sarybchik &mcdi_list_length); 1003311485Sarybchik if (rc != 0) { 1004311485Sarybchik if (rc == ENOSPC) { 1005311485Sarybchik /* Pass through mcdi_list_length for the list length */ 1006311485Sarybchik *list_lengthp = mcdi_list_length; 1007311485Sarybchik } 1008283514Sarybchik goto fail1; 1009311485Sarybchik } 1010283514Sarybchik 1011311485Sarybchik /* 1012311485Sarybchik * The static assertions in ef10_filter_init() ensure that the values of 1013311485Sarybchik * the EFX_FILTER_MATCH flags match those used by MCDI, so they don't 1014311485Sarybchik * need to be converted. 1015311485Sarybchik * 1016311485Sarybchik * In case support is added to MCDI for additional flags, remove any 1017311485Sarybchik * matches from the list which include flags we don't support. The order 1018311485Sarybchik * of the matches is preserved as they are ordered from highest to 1019311485Sarybchik * lowest priority. 1020311485Sarybchik */ 1021311485Sarybchik EFSYS_ASSERT(mcdi_list_length <= buffer_length); 1022311485Sarybchik list_length = 0; 1023311485Sarybchik for (i = 0; i < mcdi_list_length; i++) { 1024311485Sarybchik if ((buffer[i] & ~all_filter_flags) == 0) { 1025311485Sarybchik buffer[list_length] = buffer[i]; 1026311485Sarybchik list_length++; 1027311485Sarybchik } 1028311485Sarybchik } 1029311485Sarybchik 1030311485Sarybchik *list_lengthp = list_length; 1031311485Sarybchik 1032283514Sarybchik return (0); 1033283514Sarybchik 1034283514Sarybchikfail1: 1035291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1036283514Sarybchik 1037283514Sarybchik return (rc); 1038283514Sarybchik} 1039283514Sarybchik 1040291436Sarybchikstatic __checkReturn efx_rc_t 1041299411Sarybchikef10_filter_insert_unicast( 1042283514Sarybchik __in efx_nic_t *enp, 1043283514Sarybchik __in_ecount(6) uint8_t const *addr, 1044311022Sarybchik __in efx_filter_flags_t filter_flags) 1045283514Sarybchik{ 1046293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1047283514Sarybchik efx_filter_spec_t spec; 1048291436Sarybchik efx_rc_t rc; 1049283514Sarybchik 1050283514Sarybchik /* Insert the filter for the local station address */ 1051283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1052283514Sarybchik filter_flags, 1053293764Sarybchik eftp->eft_default_rxq); 1054342440Sarybchik rc = efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, 1055342440Sarybchik addr); 1056342440Sarybchik if (rc != 0) 1057342440Sarybchik goto fail1; 1058283514Sarybchik 1059293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1060299411Sarybchik &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1061299411Sarybchik if (rc != 0) 1062342440Sarybchik goto fail2; 1063283514Sarybchik 1064299411Sarybchik eftp->eft_unicst_filter_count++; 1065299411Sarybchik EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1066299411Sarybchik EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1067299411Sarybchik 1068283514Sarybchik return (0); 1069283514Sarybchik 1070342440Sarybchikfail2: 1071342440Sarybchik EFSYS_PROBE(fail2); 1072299411Sarybchikfail1: 1073299411Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1074299411Sarybchik return (rc); 1075299411Sarybchik} 1076299411Sarybchik 1077299411Sarybchikstatic __checkReturn efx_rc_t 1078299411Sarybchikef10_filter_insert_all_unicast( 1079299411Sarybchik __in efx_nic_t *enp, 1080311022Sarybchik __in efx_filter_flags_t filter_flags) 1081299411Sarybchik{ 1082299411Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1083299411Sarybchik efx_filter_spec_t spec; 1084299411Sarybchik efx_rc_t rc; 1085299411Sarybchik 1086283514Sarybchik /* Insert the unknown unicast filter */ 1087283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1088283514Sarybchik filter_flags, 1089293764Sarybchik eftp->eft_default_rxq); 1090342440Sarybchik rc = efx_filter_spec_set_uc_def(&spec); 1091342440Sarybchik if (rc != 0) 1092342440Sarybchik goto fail1; 1093293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1094299411Sarybchik &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1095283514Sarybchik if (rc != 0) 1096342440Sarybchik goto fail2; 1097283514Sarybchik 1098299411Sarybchik eftp->eft_unicst_filter_count++; 1099299411Sarybchik EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1100299411Sarybchik EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1101283514Sarybchik 1102283514Sarybchik return (0); 1103283514Sarybchik 1104342440Sarybchikfail2: 1105342440Sarybchik EFSYS_PROBE(fail2); 1106283514Sarybchikfail1: 1107291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1108283514Sarybchik return (rc); 1109283514Sarybchik} 1110283514Sarybchik 1111291436Sarybchikstatic __checkReturn efx_rc_t 1112299518Sarybchikef10_filter_insert_multicast_list( 1113283514Sarybchik __in efx_nic_t *enp, 1114283514Sarybchik __in boolean_t mulcst, 1115283514Sarybchik __in boolean_t brdcst, 1116283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1117299410Sarybchik __in uint32_t count, 1118311022Sarybchik __in efx_filter_flags_t filter_flags, 1119299518Sarybchik __in boolean_t rollback) 1120283514Sarybchik{ 1121293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1122283514Sarybchik efx_filter_spec_t spec; 1123283514Sarybchik uint8_t addr[6]; 1124299518Sarybchik uint32_t i; 1125299518Sarybchik uint32_t filter_index; 1126299518Sarybchik uint32_t filter_count; 1127291436Sarybchik efx_rc_t rc; 1128283514Sarybchik 1129283514Sarybchik if (mulcst == B_FALSE) 1130283514Sarybchik count = 0; 1131283514Sarybchik 1132283514Sarybchik if (count + (brdcst ? 1 : 0) > 1133293764Sarybchik EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) { 1134299518Sarybchik /* Too many MAC addresses */ 1135299518Sarybchik rc = EINVAL; 1136299518Sarybchik goto fail1; 1137283514Sarybchik } 1138283514Sarybchik 1139283514Sarybchik /* Insert/renew multicast address list filters */ 1140299518Sarybchik filter_count = 0; 1141299518Sarybchik for (i = 0; i < count; i++) { 1142283514Sarybchik efx_filter_spec_init_rx(&spec, 1143283514Sarybchik EFX_FILTER_PRI_AUTO, 1144283514Sarybchik filter_flags, 1145293764Sarybchik eftp->eft_default_rxq); 1146283514Sarybchik 1147342440Sarybchik rc = efx_filter_spec_set_eth_local(&spec, 1148283514Sarybchik EFX_FILTER_SPEC_VID_UNSPEC, 1149283514Sarybchik &addrs[i * EFX_MAC_ADDR_LEN]); 1150342440Sarybchik if (rc != 0) { 1151342440Sarybchik if (rollback == B_TRUE) { 1152342440Sarybchik /* Only stop upon failure if told to rollback */ 1153342440Sarybchik goto rollback; 1154342440Sarybchik } else { 1155342440Sarybchik /* 1156342440Sarybchik * Don't try to add a filter with a corrupt 1157342440Sarybchik * specification. 1158342440Sarybchik */ 1159342440Sarybchik continue; 1160342440Sarybchik } 1161342440Sarybchik } 1162283514Sarybchik 1163293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1164299518Sarybchik &filter_index); 1165299518Sarybchik 1166299518Sarybchik if (rc == 0) { 1167299518Sarybchik eftp->eft_mulcst_filter_indexes[filter_count] = 1168299518Sarybchik filter_index; 1169299518Sarybchik filter_count++; 1170299518Sarybchik } else if (rollback == B_TRUE) { 1171299518Sarybchik /* Only stop upon failure if told to rollback */ 1172283514Sarybchik goto rollback; 1173283514Sarybchik } 1174299518Sarybchik 1175283514Sarybchik } 1176283514Sarybchik 1177283514Sarybchik if (brdcst == B_TRUE) { 1178283514Sarybchik /* Insert/renew broadcast address filter */ 1179283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1180283514Sarybchik filter_flags, 1181293764Sarybchik eftp->eft_default_rxq); 1182283514Sarybchik 1183283514Sarybchik EFX_MAC_BROADCAST_ADDR_SET(addr); 1184342440Sarybchik rc = efx_filter_spec_set_eth_local(&spec, 1185342440Sarybchik EFX_FILTER_SPEC_VID_UNSPEC, addr); 1186342440Sarybchik if ((rc != 0) && (rollback == B_TRUE)) { 1187342440Sarybchik /* Only stop upon failure if told to rollback */ 1188342440Sarybchik goto rollback; 1189342440Sarybchik } 1190283514Sarybchik 1191293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1192299518Sarybchik &filter_index); 1193299518Sarybchik 1194299518Sarybchik if (rc == 0) { 1195299518Sarybchik eftp->eft_mulcst_filter_indexes[filter_count] = 1196299518Sarybchik filter_index; 1197299518Sarybchik filter_count++; 1198299518Sarybchik } else if (rollback == B_TRUE) { 1199299518Sarybchik /* Only stop upon failure if told to rollback */ 1200283514Sarybchik goto rollback; 1201283514Sarybchik } 1202283514Sarybchik } 1203283514Sarybchik 1204299518Sarybchik eftp->eft_mulcst_filter_count = filter_count; 1205299594Sarybchik eftp->eft_using_all_mulcst = B_FALSE; 1206299518Sarybchik 1207283514Sarybchik return (0); 1208283514Sarybchik 1209283514Sarybchikrollback: 1210299518Sarybchik /* Remove any filters we have inserted */ 1211299518Sarybchik i = filter_count; 1212283514Sarybchik while (i--) { 1213293764Sarybchik (void) ef10_filter_delete_internal(enp, 1214293764Sarybchik eftp->eft_mulcst_filter_indexes[i]); 1215283514Sarybchik } 1216293764Sarybchik eftp->eft_mulcst_filter_count = 0; 1217283514Sarybchik 1218299518Sarybchikfail1: 1219299518Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1220299518Sarybchik 1221299518Sarybchik return (rc); 1222299518Sarybchik} 1223299518Sarybchik 1224299518Sarybchikstatic __checkReturn efx_rc_t 1225299518Sarybchikef10_filter_insert_all_multicast( 1226299518Sarybchik __in efx_nic_t *enp, 1227311022Sarybchik __in efx_filter_flags_t filter_flags) 1228299518Sarybchik{ 1229299518Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1230299518Sarybchik efx_filter_spec_t spec; 1231299518Sarybchik efx_rc_t rc; 1232299518Sarybchik 1233283514Sarybchik /* Insert the unknown multicast filter */ 1234283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1235283514Sarybchik filter_flags, 1236293764Sarybchik eftp->eft_default_rxq); 1237342440Sarybchik rc = efx_filter_spec_set_mc_def(&spec); 1238342440Sarybchik if (rc != 0) 1239342440Sarybchik goto fail1; 1240283514Sarybchik 1241293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1242293764Sarybchik &eftp->eft_mulcst_filter_indexes[0]); 1243283514Sarybchik if (rc != 0) 1244342440Sarybchik goto fail2; 1245283514Sarybchik 1246293764Sarybchik eftp->eft_mulcst_filter_count = 1; 1247299594Sarybchik eftp->eft_using_all_mulcst = B_TRUE; 1248283514Sarybchik 1249283514Sarybchik /* 1250283514Sarybchik * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. 1251283514Sarybchik */ 1252283514Sarybchik 1253283514Sarybchik return (0); 1254283514Sarybchik 1255342440Sarybchikfail2: 1256342440Sarybchik EFSYS_PROBE(fail2); 1257283514Sarybchikfail1: 1258291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1259283514Sarybchik 1260283514Sarybchik return (rc); 1261283514Sarybchik} 1262283514Sarybchik 1263342416Sarybchiktypedef struct ef10_filter_encap_entry_s { 1264342416Sarybchik uint16_t ether_type; 1265342416Sarybchik efx_tunnel_protocol_t encap_type; 1266342416Sarybchik uint32_t inner_frame_match; 1267342416Sarybchik} ef10_filter_encap_entry_t; 1268342416Sarybchik 1269342416Sarybchik#define EF10_ENCAP_FILTER_ENTRY(ipv, encap_type, inner_frame_match) \ 1270342416Sarybchik { EFX_ETHER_TYPE_##ipv, EFX_TUNNEL_PROTOCOL_##encap_type, \ 1271342416Sarybchik EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_##inner_frame_match } 1272342416Sarybchik 1273342416Sarybchikstatic ef10_filter_encap_entry_t ef10_filter_encap_list[] = { 1274342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, UCAST_DST), 1275342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV4, VXLAN, MCAST_DST), 1276342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, UCAST_DST), 1277342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV6, VXLAN, MCAST_DST), 1278342416Sarybchik 1279342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, UCAST_DST), 1280342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV4, GENEVE, MCAST_DST), 1281342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, UCAST_DST), 1282342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV6, GENEVE, MCAST_DST), 1283342416Sarybchik 1284342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, UCAST_DST), 1285342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV4, NVGRE, MCAST_DST), 1286342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, UCAST_DST), 1287342416Sarybchik EF10_ENCAP_FILTER_ENTRY(IPV6, NVGRE, MCAST_DST), 1288342416Sarybchik}; 1289342416Sarybchik 1290342416Sarybchik#undef EF10_ENCAP_FILTER_ENTRY 1291342416Sarybchik 1292342416Sarybchikstatic __checkReturn efx_rc_t 1293342416Sarybchikef10_filter_insert_encap_filters( 1294342416Sarybchik __in efx_nic_t *enp, 1295342416Sarybchik __in boolean_t mulcst, 1296342416Sarybchik __in efx_filter_flags_t filter_flags) 1297342416Sarybchik{ 1298342416Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1299342416Sarybchik uint32_t i; 1300342416Sarybchik efx_rc_t rc; 1301342416Sarybchik 1302342416Sarybchik EFX_STATIC_ASSERT(EFX_ARRAY_SIZE(ef10_filter_encap_list) <= 1303342416Sarybchik EFX_ARRAY_SIZE(table->eft_encap_filter_indexes)); 1304342416Sarybchik 1305342416Sarybchik /* 1306342416Sarybchik * On Medford, full-featured firmware can identify packets as being 1307342416Sarybchik * tunnel encapsulated, even if no encapsulated packet offloads are in 1308342416Sarybchik * use. When packets are identified as such, ordinary filters are not 1309342416Sarybchik * applied, only ones specific to encapsulated packets. Hence we need to 1310342416Sarybchik * insert filters for encapsulated packets in order to receive them. 1311342416Sarybchik * 1312342416Sarybchik * Separate filters need to be inserted for each ether type, 1313342416Sarybchik * encapsulation type, and inner frame type (unicast or multicast). To 1314342416Sarybchik * keep things simple and reduce the number of filters needed, catch-all 1315342416Sarybchik * filters for all combinations of types are inserted, even if 1316342416Sarybchik * all_unicst or all_mulcst have not been set. (These catch-all filters 1317342416Sarybchik * may well, however, fail to insert on unprivileged functions.) 1318342416Sarybchik */ 1319342416Sarybchik table->eft_encap_filter_count = 0; 1320342416Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(ef10_filter_encap_list); i++) { 1321342416Sarybchik efx_filter_spec_t spec; 1322342416Sarybchik ef10_filter_encap_entry_t *encap_filter = 1323342416Sarybchik &ef10_filter_encap_list[i]; 1324342416Sarybchik 1325342416Sarybchik /* 1326342416Sarybchik * Skip multicast filters if we've not been asked for 1327342416Sarybchik * any multicast traffic. 1328342416Sarybchik */ 1329342416Sarybchik if ((mulcst == B_FALSE) && 1330342416Sarybchik (encap_filter->inner_frame_match == 1331342416Sarybchik EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST)) 1332342416Sarybchik continue; 1333342416Sarybchik 1334342416Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1335342416Sarybchik filter_flags, 1336342416Sarybchik table->eft_default_rxq); 1337342416Sarybchik efx_filter_spec_set_ether_type(&spec, encap_filter->ether_type); 1338342416Sarybchik rc = efx_filter_spec_set_encap_type(&spec, 1339342416Sarybchik encap_filter->encap_type, 1340342416Sarybchik encap_filter->inner_frame_match); 1341342416Sarybchik if (rc != 0) 1342342416Sarybchik goto fail1; 1343342416Sarybchik 1344342416Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1345342416Sarybchik &table->eft_encap_filter_indexes[ 1346342416Sarybchik table->eft_encap_filter_count]); 1347342416Sarybchik if (rc != 0) { 1348342416Sarybchik if (rc != EACCES) 1349342416Sarybchik goto fail2; 1350342416Sarybchik } else { 1351342416Sarybchik table->eft_encap_filter_count++; 1352342416Sarybchik } 1353342416Sarybchik } 1354342416Sarybchik 1355342416Sarybchik return (0); 1356342416Sarybchik 1357342416Sarybchikfail2: 1358342416Sarybchik EFSYS_PROBE(fail2); 1359342416Sarybchikfail1: 1360342416Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1361342416Sarybchik 1362342416Sarybchik return (rc); 1363342416Sarybchik} 1364342416Sarybchik 1365299594Sarybchikstatic void 1366299594Sarybchikef10_filter_remove_old( 1367299594Sarybchik __in efx_nic_t *enp) 1368299594Sarybchik{ 1369299594Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1370299594Sarybchik uint32_t i; 1371283514Sarybchik 1372299594Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1373299594Sarybchik if (ef10_filter_entry_is_auto_old(table, i)) { 1374299594Sarybchik (void) ef10_filter_delete_internal(enp, i); 1375299594Sarybchik } 1376299594Sarybchik } 1377299594Sarybchik} 1378299594Sarybchik 1379299594Sarybchik 1380291436Sarybchikstatic __checkReturn efx_rc_t 1381299595Sarybchikef10_filter_get_workarounds( 1382283514Sarybchik __in efx_nic_t *enp) 1383283514Sarybchik{ 1384283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1385283514Sarybchik uint32_t implemented = 0; 1386283514Sarybchik uint32_t enabled = 0; 1387291436Sarybchik efx_rc_t rc; 1388283514Sarybchik 1389283514Sarybchik rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); 1390283514Sarybchik if (rc == 0) { 1391283514Sarybchik /* Check if chained multicast filter support is enabled */ 1392283514Sarybchik if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) 1393283514Sarybchik encp->enc_bug26807_workaround = B_TRUE; 1394283514Sarybchik else 1395283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1396283514Sarybchik } else if (rc == ENOTSUP) { 1397283514Sarybchik /* 1398283514Sarybchik * Firmware is too old to support GET_WORKAROUNDS, and support 1399283514Sarybchik * for this workaround was implemented later. 1400283514Sarybchik */ 1401283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1402283514Sarybchik } else { 1403283514Sarybchik goto fail1; 1404283514Sarybchik } 1405283514Sarybchik 1406283514Sarybchik return (0); 1407283514Sarybchik 1408283514Sarybchikfail1: 1409291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1410283514Sarybchik 1411283514Sarybchik return (rc); 1412283514Sarybchik 1413283514Sarybchik} 1414283514Sarybchik 1415283514Sarybchik 1416283514Sarybchik/* 1417283514Sarybchik * Reconfigure all filters. 1418283514Sarybchik * If all_unicst and/or all mulcst filters cannot be applied then 1419283514Sarybchik * return ENOTSUP (Note the filters for the specified addresses are 1420283514Sarybchik * still applied in this case). 1421283514Sarybchik */ 1422291436Sarybchik __checkReturn efx_rc_t 1423293764Sarybchikef10_filter_reconfigure( 1424283514Sarybchik __in efx_nic_t *enp, 1425283514Sarybchik __in_ecount(6) uint8_t const *mac_addr, 1426283514Sarybchik __in boolean_t all_unicst, 1427283514Sarybchik __in boolean_t mulcst, 1428283514Sarybchik __in boolean_t all_mulcst, 1429283514Sarybchik __in boolean_t brdcst, 1430283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1431299410Sarybchik __in uint32_t count) 1432283514Sarybchik{ 1433299594Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1434293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1435311022Sarybchik efx_filter_flags_t filter_flags; 1436310930Sarybchik unsigned int i; 1437299518Sarybchik efx_rc_t all_unicst_rc = 0; 1438299518Sarybchik efx_rc_t all_mulcst_rc = 0; 1439291436Sarybchik efx_rc_t rc; 1440283514Sarybchik 1441293764Sarybchik if (table->eft_default_rxq == NULL) { 1442283514Sarybchik /* 1443283514Sarybchik * Filters direct traffic to the default RXQ, and so cannot be 1444283514Sarybchik * inserted until it is available. Any currently configured 1445283514Sarybchik * filters must be removed (ignore errors in case the MC 1446283514Sarybchik * has rebooted, which removes hardware filters). 1447283514Sarybchik */ 1448299411Sarybchik for (i = 0; i < table->eft_unicst_filter_count; i++) { 1449293764Sarybchik (void) ef10_filter_delete_internal(enp, 1450299411Sarybchik table->eft_unicst_filter_indexes[i]); 1451283514Sarybchik } 1452299411Sarybchik table->eft_unicst_filter_count = 0; 1453299411Sarybchik 1454293764Sarybchik for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1455293764Sarybchik (void) ef10_filter_delete_internal(enp, 1456293764Sarybchik table->eft_mulcst_filter_indexes[i]); 1457283514Sarybchik } 1458293764Sarybchik table->eft_mulcst_filter_count = 0; 1459283514Sarybchik 1460342416Sarybchik for (i = 0; i < table->eft_encap_filter_count; i++) { 1461342416Sarybchik (void) ef10_filter_delete_internal(enp, 1462342416Sarybchik table->eft_encap_filter_indexes[i]); 1463342416Sarybchik } 1464342416Sarybchik table->eft_encap_filter_count = 0; 1465342416Sarybchik 1466283514Sarybchik return (0); 1467283514Sarybchik } 1468283514Sarybchik 1469293764Sarybchik if (table->eft_using_rss) 1470283514Sarybchik filter_flags = EFX_FILTER_FLAG_RX_RSS; 1471283514Sarybchik else 1472283514Sarybchik filter_flags = 0; 1473283514Sarybchik 1474283514Sarybchik /* Mark old filters which may need to be removed */ 1475299411Sarybchik for (i = 0; i < table->eft_unicst_filter_count; i++) { 1476293764Sarybchik ef10_filter_set_entry_auto_old(table, 1477299411Sarybchik table->eft_unicst_filter_indexes[i]); 1478283514Sarybchik } 1479293764Sarybchik for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1480293764Sarybchik ef10_filter_set_entry_auto_old(table, 1481293764Sarybchik table->eft_mulcst_filter_indexes[i]); 1482283514Sarybchik } 1483342416Sarybchik for (i = 0; i < table->eft_encap_filter_count; i++) { 1484342416Sarybchik ef10_filter_set_entry_auto_old(table, 1485342416Sarybchik table->eft_encap_filter_indexes[i]); 1486342416Sarybchik } 1487283514Sarybchik 1488299411Sarybchik /* 1489299411Sarybchik * Insert or renew unicast filters. 1490299411Sarybchik * 1491342447Sarybchik * Firmware does not perform chaining on unicast filters. As traffic is 1492299411Sarybchik * therefore only delivered to the first matching filter, we should 1493299411Sarybchik * always insert the specific filter for our MAC address, to try and 1494299411Sarybchik * ensure we get that traffic. 1495299411Sarybchik * 1496299411Sarybchik * (If the filter for our MAC address has already been inserted by 1497299411Sarybchik * another function, we won't receive traffic sent to us, even if we 1498299411Sarybchik * insert a unicast mismatch filter. To prevent traffic stealing, this 1499299411Sarybchik * therefore relies on the privilege model only allowing functions to 1500299411Sarybchik * insert filters for their own MAC address unless explicitly given 1501299411Sarybchik * additional privileges by the user. This also means that, even on a 1502299411Sarybchik * priviliged function, inserting a unicast mismatch filter may not 1503299411Sarybchik * catch all traffic in multi PCI function scenarios.) 1504299411Sarybchik */ 1505299411Sarybchik table->eft_unicst_filter_count = 0; 1506299411Sarybchik rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags); 1507299411Sarybchik if (all_unicst || (rc != 0)) { 1508299411Sarybchik all_unicst_rc = ef10_filter_insert_all_unicast(enp, 1509299411Sarybchik filter_flags); 1510299411Sarybchik if ((rc != 0) && (all_unicst_rc != 0)) 1511283514Sarybchik goto fail1; 1512283514Sarybchik } 1513283514Sarybchik 1514283514Sarybchik /* 1515283514Sarybchik * WORKAROUND_BUG26807 controls firmware support for chained multicast 1516283514Sarybchik * filters, and can only be enabled or disabled when the hardware filter 1517283514Sarybchik * table is empty. 1518283514Sarybchik * 1519299595Sarybchik * Chained multicast filters require support from the datapath firmware, 1520299595Sarybchik * and may not be available (e.g. low-latency variants or old Huntington 1521299595Sarybchik * firmware). 1522299595Sarybchik * 1523283514Sarybchik * Firmware will reset (FLR) functions which have inserted filters in 1524283514Sarybchik * the hardware filter table when the workaround is enabled/disabled. 1525283514Sarybchik * Functions without any hardware filters are not reset. 1526283514Sarybchik * 1527283514Sarybchik * Re-check if the workaround is enabled after adding unicast hardware 1528299595Sarybchik * filters. This ensures that encp->enc_bug26807_workaround matches the 1529283514Sarybchik * firmware state, and that later changes to enable/disable the 1530283514Sarybchik * workaround will result in this function seeing a reset (FLR). 1531293764Sarybchik * 1532299595Sarybchik * In common-code drivers, we only support multiple PCI function 1533299595Sarybchik * scenarios with firmware that supports multicast chaining, so we can 1534299595Sarybchik * assume it is enabled for such cases and hence simplify the filter 1535299595Sarybchik * insertion logic. Firmware that does not support multicast chaining 1536299595Sarybchik * does not support multiple PCI function configurations either, so 1537299595Sarybchik * filter insertion is much simpler and the same strategies can still be 1538299595Sarybchik * used. 1539283514Sarybchik */ 1540299595Sarybchik if ((rc = ef10_filter_get_workarounds(enp)) != 0) 1541299411Sarybchik goto fail2; 1542283514Sarybchik 1543299594Sarybchik if ((table->eft_using_all_mulcst != all_mulcst) && 1544299594Sarybchik (encp->enc_bug26807_workaround == B_TRUE)) { 1545299594Sarybchik /* 1546299594Sarybchik * Multicast filter chaining is enabled, so traffic that matches 1547299594Sarybchik * more than one multicast filter will be replicated and 1548299594Sarybchik * delivered to multiple recipients. To avoid this duplicate 1549299594Sarybchik * delivery, remove old multicast filters before inserting new 1550299594Sarybchik * multicast filters. 1551299594Sarybchik */ 1552299594Sarybchik ef10_filter_remove_old(enp); 1553299594Sarybchik } 1554299594Sarybchik 1555283514Sarybchik /* Insert or renew multicast filters */ 1556299518Sarybchik if (all_mulcst == B_TRUE) { 1557299518Sarybchik /* 1558299518Sarybchik * Insert the all multicast filter. If that fails, try to insert 1559299518Sarybchik * all of our multicast filters (but without rollback on 1560299518Sarybchik * failure). 1561299518Sarybchik */ 1562299518Sarybchik all_mulcst_rc = ef10_filter_insert_all_multicast(enp, 1563299518Sarybchik filter_flags); 1564299518Sarybchik if (all_mulcst_rc != 0) { 1565299518Sarybchik rc = ef10_filter_insert_multicast_list(enp, B_TRUE, 1566299518Sarybchik brdcst, addrs, count, filter_flags, B_FALSE); 1567299518Sarybchik if (rc != 0) 1568299518Sarybchik goto fail3; 1569283514Sarybchik } 1570299518Sarybchik } else { 1571299518Sarybchik /* 1572299518Sarybchik * Insert filters for multicast addresses. 1573299518Sarybchik * If any insertion fails, then rollback and try to insert the 1574299518Sarybchik * all multicast filter instead. 1575299518Sarybchik * If that also fails, try to insert all of the multicast 1576299518Sarybchik * filters (but without rollback on failure). 1577299518Sarybchik */ 1578299518Sarybchik rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst, 1579299518Sarybchik addrs, count, filter_flags, B_TRUE); 1580299518Sarybchik if (rc != 0) { 1581299594Sarybchik if ((table->eft_using_all_mulcst == B_FALSE) && 1582299594Sarybchik (encp->enc_bug26807_workaround == B_TRUE)) { 1583299594Sarybchik /* 1584299594Sarybchik * Multicast filter chaining is on, so remove 1585299594Sarybchik * old filters before inserting the multicast 1586299594Sarybchik * all filter to avoid duplicate delivery caused 1587299594Sarybchik * by packets matching multiple filters. 1588299594Sarybchik */ 1589299594Sarybchik ef10_filter_remove_old(enp); 1590299594Sarybchik } 1591299594Sarybchik 1592299518Sarybchik rc = ef10_filter_insert_all_multicast(enp, 1593299518Sarybchik filter_flags); 1594299518Sarybchik if (rc != 0) { 1595299518Sarybchik rc = ef10_filter_insert_multicast_list(enp, 1596299518Sarybchik mulcst, brdcst, 1597299518Sarybchik addrs, count, filter_flags, B_FALSE); 1598299518Sarybchik if (rc != 0) 1599299518Sarybchik goto fail4; 1600299518Sarybchik } 1601299518Sarybchik } 1602283514Sarybchik } 1603283514Sarybchik 1604342416Sarybchik if (encp->enc_tunnel_encapsulations_supported != 0) { 1605342416Sarybchik /* Try to insert filters for encapsulated packets. */ 1606342416Sarybchik (void) ef10_filter_insert_encap_filters(enp, 1607342416Sarybchik mulcst || all_mulcst || brdcst, 1608342416Sarybchik filter_flags); 1609342416Sarybchik } 1610342416Sarybchik 1611283514Sarybchik /* Remove old filters which were not renewed */ 1612299594Sarybchik ef10_filter_remove_old(enp); 1613283514Sarybchik 1614283514Sarybchik /* report if any optional flags were rejected */ 1615283514Sarybchik if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || 1616283514Sarybchik ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { 1617283514Sarybchik rc = ENOTSUP; 1618283514Sarybchik } 1619283514Sarybchik 1620283514Sarybchik return (rc); 1621283514Sarybchik 1622283514Sarybchikfail4: 1623283514Sarybchik EFSYS_PROBE(fail4); 1624283514Sarybchikfail3: 1625283514Sarybchik EFSYS_PROBE(fail3); 1626283514Sarybchikfail2: 1627283514Sarybchik EFSYS_PROBE(fail2); 1628283514Sarybchikfail1: 1629291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1630283514Sarybchik 1631283514Sarybchik /* Clear auto old flags */ 1632293764Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1633293764Sarybchik if (ef10_filter_entry_is_auto_old(table, i)) { 1634293764Sarybchik ef10_filter_set_entry_not_auto_old(table, i); 1635283514Sarybchik } 1636283514Sarybchik } 1637283514Sarybchik 1638283514Sarybchik return (rc); 1639283514Sarybchik} 1640283514Sarybchik 1641283514Sarybchik void 1642293764Sarybchikef10_filter_get_default_rxq( 1643283514Sarybchik __in efx_nic_t *enp, 1644283514Sarybchik __out efx_rxq_t **erpp, 1645283514Sarybchik __out boolean_t *using_rss) 1646283514Sarybchik{ 1647293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1648283514Sarybchik 1649293764Sarybchik *erpp = table->eft_default_rxq; 1650293764Sarybchik *using_rss = table->eft_using_rss; 1651283514Sarybchik} 1652283514Sarybchik 1653283514Sarybchik 1654283514Sarybchik void 1655293764Sarybchikef10_filter_default_rxq_set( 1656283514Sarybchik __in efx_nic_t *enp, 1657283514Sarybchik __in efx_rxq_t *erp, 1658283514Sarybchik __in boolean_t using_rss) 1659283514Sarybchik{ 1660293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1661283514Sarybchik 1662283514Sarybchik#if EFSYS_OPT_RX_SCALE 1663283514Sarybchik EFSYS_ASSERT((using_rss == B_FALSE) || 1664293754Sarybchik (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID)); 1665293764Sarybchik table->eft_using_rss = using_rss; 1666283514Sarybchik#else 1667283514Sarybchik EFSYS_ASSERT(using_rss == B_FALSE); 1668293764Sarybchik table->eft_using_rss = B_FALSE; 1669283514Sarybchik#endif 1670293764Sarybchik table->eft_default_rxq = erp; 1671283514Sarybchik} 1672283514Sarybchik 1673283514Sarybchik void 1674293764Sarybchikef10_filter_default_rxq_clear( 1675283514Sarybchik __in efx_nic_t *enp) 1676283514Sarybchik{ 1677293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1678283514Sarybchik 1679293764Sarybchik table->eft_default_rxq = NULL; 1680293764Sarybchik table->eft_using_rss = B_FALSE; 1681283514Sarybchik} 1682283514Sarybchik 1683283514Sarybchik 1684283514Sarybchik#endif /* EFSYS_OPT_FILTER */ 1685283514Sarybchik 1686299597Sarybchik#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 1687