ef10_filter.c revision 293764
1283514Sarybchik/*- 2283514Sarybchik * Copyright (c) 2007-2015 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: head/sys/dev/sfxge/common/hunt_filter.c 293764 2016-01-12 15:24:13Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efsys.h" 35283514Sarybchik#include "efx.h" 36283514Sarybchik#include "efx_types.h" 37283514Sarybchik#include "efx_regs_mcdi.h" 38283514Sarybchik#include "efx_impl.h" 39283514Sarybchik 40283514Sarybchik#if EFSYS_OPT_HUNTINGTON 41283514Sarybchik 42283514Sarybchik#if EFSYS_OPT_FILTER 43283514Sarybchik 44293764Sarybchik#define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec) 45283514Sarybchik 46283514Sarybchikstatic efx_filter_spec_t * 47293764Sarybchikef10_filter_entry_spec( 48293764Sarybchik __in const ef10_filter_table_t *eftp, 49283514Sarybchik __in unsigned int index) 50283514Sarybchik{ 51293764Sarybchik return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) & 52293764Sarybchik ~(uintptr_t)EFX_EF10_FILTER_FLAGS)); 53283514Sarybchik} 54283514Sarybchik 55283514Sarybchikstatic boolean_t 56293764Sarybchikef10_filter_entry_is_busy( 57293764Sarybchik __in const ef10_filter_table_t *eftp, 58283514Sarybchik __in unsigned int index) 59283514Sarybchik{ 60293764Sarybchik if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY) 61283514Sarybchik return (B_TRUE); 62283514Sarybchik else 63283514Sarybchik return (B_FALSE); 64283514Sarybchik} 65283514Sarybchik 66283514Sarybchikstatic boolean_t 67293764Sarybchikef10_filter_entry_is_auto_old( 68293764Sarybchik __in const ef10_filter_table_t *eftp, 69283514Sarybchik __in unsigned int index) 70283514Sarybchik{ 71293764Sarybchik if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD) 72283514Sarybchik return (B_TRUE); 73283514Sarybchik else 74283514Sarybchik return (B_FALSE); 75283514Sarybchik} 76283514Sarybchik 77283514Sarybchikstatic void 78293764Sarybchikef10_filter_set_entry( 79293764Sarybchik __inout ef10_filter_table_t *eftp, 80283514Sarybchik __in unsigned int index, 81283514Sarybchik __in_opt const efx_filter_spec_t *efsp) 82283514Sarybchik{ 83293764Sarybchik EFE_SPEC(eftp, index) = (uintptr_t)efsp; 84283514Sarybchik} 85283514Sarybchik 86283514Sarybchikstatic void 87293764Sarybchikef10_filter_set_entry_busy( 88293764Sarybchik __inout ef10_filter_table_t *eftp, 89283514Sarybchik __in unsigned int index) 90283514Sarybchik{ 91293764Sarybchik EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 92283514Sarybchik} 93283514Sarybchik 94283514Sarybchikstatic void 95293764Sarybchikef10_filter_set_entry_not_busy( 96293764Sarybchik __inout ef10_filter_table_t *eftp, 97283514Sarybchik __in unsigned int index) 98283514Sarybchik{ 99293764Sarybchik EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 100283514Sarybchik} 101283514Sarybchik 102283514Sarybchikstatic void 103293764Sarybchikef10_filter_set_entry_auto_old( 104293764Sarybchik __inout ef10_filter_table_t *eftp, 105283514Sarybchik __in unsigned int index) 106283514Sarybchik{ 107293764Sarybchik EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 108293764Sarybchik EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 109283514Sarybchik} 110283514Sarybchik 111283514Sarybchikstatic void 112293764Sarybchikef10_filter_set_entry_not_auto_old( 113293764Sarybchik __inout ef10_filter_table_t *eftp, 114283514Sarybchik __in unsigned int index) 115283514Sarybchik{ 116293764Sarybchik EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 117293764Sarybchik EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 118283514Sarybchik} 119283514Sarybchik 120291436Sarybchik __checkReturn efx_rc_t 121293764Sarybchikef10_filter_init( 122283514Sarybchik __in efx_nic_t *enp) 123283514Sarybchik{ 124291436Sarybchik efx_rc_t rc; 125293764Sarybchik ef10_filter_table_t *eftp; 126283514Sarybchik 127293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 128293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 129283514Sarybchik 130283514Sarybchik#define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match)) 131283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST == 132283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_IP)); 133283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == 134283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_IP)); 135283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == 136283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_MAC)); 137283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == 138283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_PORT)); 139283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == 140283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_MAC)); 141283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == 142283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_PORT)); 143283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == 144283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_ETHER_TYPE)); 145283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == 146283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_INNER_VLAN)); 147283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == 148283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN)); 149283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == 150283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO)); 151283514Sarybchik#undef MATCH_MASK 152283514Sarybchik 153293764Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp); 154283514Sarybchik 155293764Sarybchik if (!eftp) { 156283514Sarybchik rc = ENOMEM; 157283514Sarybchik goto fail1; 158283514Sarybchik } 159283514Sarybchik 160293764Sarybchik enp->en_filter.ef_ef10_filter_table = eftp; 161283514Sarybchik 162283514Sarybchik return (0); 163283514Sarybchik 164283514Sarybchikfail1: 165291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 166283514Sarybchik 167283514Sarybchik return (rc); 168283514Sarybchik} 169283514Sarybchik 170283514Sarybchik void 171293764Sarybchikef10_filter_fini( 172283514Sarybchik __in efx_nic_t *enp) 173283514Sarybchik{ 174293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 175293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 176283514Sarybchik 177293764Sarybchik if (enp->en_filter.ef_ef10_filter_table != NULL) { 178293764Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t), 179293764Sarybchik enp->en_filter.ef_ef10_filter_table); 180283514Sarybchik } 181283514Sarybchik} 182283514Sarybchik 183291436Sarybchikstatic __checkReturn efx_rc_t 184283514Sarybchikefx_mcdi_filter_op_add( 185283514Sarybchik __in efx_nic_t *enp, 186283514Sarybchik __in efx_filter_spec_t *spec, 187283514Sarybchik __in unsigned int filter_op, 188293764Sarybchik __inout ef10_filter_handle_t *handle) 189283514Sarybchik{ 190283514Sarybchik efx_mcdi_req_t req; 191283514Sarybchik uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 192283514Sarybchik MC_CMD_FILTER_OP_OUT_LEN)]; 193283514Sarybchik uint32_t match_fields = 0; 194291436Sarybchik efx_rc_t rc; 195283514Sarybchik 196283514Sarybchik memset(payload, 0, sizeof (payload)); 197283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 198283514Sarybchik req.emr_in_buf = payload; 199283514Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 200283514Sarybchik req.emr_out_buf = payload; 201283514Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 202283514Sarybchik 203283514Sarybchik switch (filter_op) { 204283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REPLACE: 205283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, 206293764Sarybchik handle->efh_lo); 207283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, 208293764Sarybchik handle->efh_hi); 209283514Sarybchik /* Fall through */ 210283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_INSERT: 211283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: 212283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op); 213283514Sarybchik break; 214283514Sarybchik default: 215283514Sarybchik EFSYS_ASSERT(0); 216283514Sarybchik rc = EINVAL; 217283514Sarybchik goto fail1; 218283514Sarybchik } 219283514Sarybchik 220283514Sarybchik if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) { 221283514Sarybchik /* 222283514Sarybchik * The LOC_MAC_IG match flag can represent unknown unicast 223283514Sarybchik * or multicast filters - use the MAC address to distinguish 224283514Sarybchik * them. 225283514Sarybchik */ 226283514Sarybchik if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 227283514Sarybchik match_fields |= 1U << 228283514Sarybchik MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN; 229283514Sarybchik else 230283514Sarybchik match_fields |= 1U << 231283514Sarybchik MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN; 232283514Sarybchik } 233283514Sarybchik 234283514Sarybchik match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG); 235283514Sarybchik 236283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID, 237283514Sarybchik EVB_PORT_ID_ASSIGNED); 238283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS, 239283514Sarybchik match_fields); 240283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST, 241283514Sarybchik MC_CMD_FILTER_OP_IN_RX_DEST_HOST); 242283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE, 243283514Sarybchik spec->efs_dmaq_id); 244283514Sarybchik if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { 245283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT, 246283514Sarybchik spec->efs_rss_context); 247283514Sarybchik } 248283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE, 249283514Sarybchik spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? 250283514Sarybchik MC_CMD_FILTER_OP_IN_RX_MODE_RSS : 251283514Sarybchik MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE); 252283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST, 253283514Sarybchik MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT); 254283514Sarybchik 255283514Sarybchik if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { 256283514Sarybchik /* 257283514Sarybchik * NOTE: Unlike most MCDI requests, the filter fields 258283514Sarybchik * are presented in network (big endian) byte order. 259283514Sarybchik */ 260283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC), 261283514Sarybchik spec->efs_rem_mac, EFX_MAC_ADDR_LEN); 262283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC), 263283514Sarybchik spec->efs_loc_mac, EFX_MAC_ADDR_LEN); 264283514Sarybchik 265283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT, 266283514Sarybchik __CPU_TO_BE_16(spec->efs_rem_port)); 267283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT, 268283514Sarybchik __CPU_TO_BE_16(spec->efs_loc_port)); 269283514Sarybchik 270283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE, 271283514Sarybchik __CPU_TO_BE_16(spec->efs_ether_type)); 272283514Sarybchik 273283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN, 274283514Sarybchik __CPU_TO_BE_16(spec->efs_inner_vid)); 275283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN, 276283514Sarybchik __CPU_TO_BE_16(spec->efs_outer_vid)); 277283514Sarybchik 278283514Sarybchik /* IP protocol (in low byte, high byte is zero) */ 279283514Sarybchik MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO, 280283514Sarybchik spec->efs_ip_proto); 281283514Sarybchik 282283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == 283283514Sarybchik MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 284283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == 285283514Sarybchik MC_CMD_FILTER_OP_IN_DST_IP_LEN); 286283514Sarybchik 287283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP), 288283514Sarybchik &spec->efs_rem_host.eo_byte[0], 289283514Sarybchik MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 290283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP), 291283514Sarybchik &spec->efs_loc_host.eo_byte[0], 292283514Sarybchik MC_CMD_FILTER_OP_IN_DST_IP_LEN); 293283514Sarybchik } 294283514Sarybchik 295283514Sarybchik efx_mcdi_execute(enp, &req); 296283514Sarybchik 297283514Sarybchik if (req.emr_rc != 0) { 298283514Sarybchik rc = req.emr_rc; 299283514Sarybchik goto fail2; 300283514Sarybchik } 301283514Sarybchik 302283514Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 303283514Sarybchik rc = EMSGSIZE; 304283514Sarybchik goto fail3; 305283514Sarybchik } 306283514Sarybchik 307293764Sarybchik handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO); 308293764Sarybchik handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI); 309283514Sarybchik 310283514Sarybchik return (0); 311283514Sarybchik 312283514Sarybchikfail3: 313283514Sarybchik EFSYS_PROBE(fail3); 314283514Sarybchikfail2: 315283514Sarybchik EFSYS_PROBE(fail2); 316283514Sarybchikfail1: 317291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 318283514Sarybchik 319283514Sarybchik return (rc); 320283514Sarybchik 321283514Sarybchik} 322283514Sarybchik 323291436Sarybchikstatic __checkReturn efx_rc_t 324283514Sarybchikefx_mcdi_filter_op_delete( 325283514Sarybchik __in efx_nic_t *enp, 326283514Sarybchik __in unsigned int filter_op, 327293764Sarybchik __inout ef10_filter_handle_t *handle) 328283514Sarybchik{ 329283514Sarybchik efx_mcdi_req_t req; 330283514Sarybchik uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 331283514Sarybchik MC_CMD_FILTER_OP_OUT_LEN)]; 332291436Sarybchik efx_rc_t rc; 333283514Sarybchik 334283514Sarybchik memset(payload, 0, sizeof (payload)); 335283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 336283514Sarybchik req.emr_in_buf = payload; 337283514Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 338283514Sarybchik req.emr_out_buf = payload; 339283514Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 340283514Sarybchik 341283514Sarybchik switch (filter_op) { 342283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REMOVE: 343283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 344283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE); 345283514Sarybchik break; 346283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: 347283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 348283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); 349283514Sarybchik break; 350283514Sarybchik default: 351283514Sarybchik EFSYS_ASSERT(0); 352283514Sarybchik rc = EINVAL; 353283514Sarybchik goto fail1; 354283514Sarybchik } 355283514Sarybchik 356293764Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->efh_lo); 357293764Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->efh_hi); 358283514Sarybchik 359283514Sarybchik efx_mcdi_execute(enp, &req); 360283514Sarybchik 361283514Sarybchik if (req.emr_rc != 0) { 362283514Sarybchik rc = req.emr_rc; 363283514Sarybchik goto fail2; 364283514Sarybchik } 365283514Sarybchik 366283514Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 367283514Sarybchik rc = EMSGSIZE; 368283514Sarybchik goto fail3; 369283514Sarybchik } 370283514Sarybchik 371283514Sarybchik return (0); 372283514Sarybchik 373283514Sarybchikfail3: 374283514Sarybchik EFSYS_PROBE(fail3); 375283514Sarybchik 376283514Sarybchikfail2: 377283514Sarybchik EFSYS_PROBE(fail2); 378283514Sarybchikfail1: 379291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 380283514Sarybchik 381283514Sarybchik return (rc); 382283514Sarybchik} 383283514Sarybchik 384283514Sarybchikstatic __checkReturn boolean_t 385293764Sarybchikef10_filter_equal( 386283514Sarybchik __in const efx_filter_spec_t *left, 387283514Sarybchik __in const efx_filter_spec_t *right) 388283514Sarybchik{ 389283514Sarybchik /* FIXME: Consider rx vs tx filters (look at efs_flags) */ 390283514Sarybchik if (left->efs_match_flags != right->efs_match_flags) 391283514Sarybchik return (B_FALSE); 392283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) 393283514Sarybchik return (B_FALSE); 394283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) 395283514Sarybchik return (B_FALSE); 396283514Sarybchik if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) 397283514Sarybchik return (B_FALSE); 398283514Sarybchik if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) 399283514Sarybchik return (B_FALSE); 400283514Sarybchik if (left->efs_rem_port != right->efs_rem_port) 401283514Sarybchik return (B_FALSE); 402283514Sarybchik if (left->efs_loc_port != right->efs_loc_port) 403283514Sarybchik return (B_FALSE); 404283514Sarybchik if (left->efs_inner_vid != right->efs_inner_vid) 405283514Sarybchik return (B_FALSE); 406283514Sarybchik if (left->efs_outer_vid != right->efs_outer_vid) 407283514Sarybchik return (B_FALSE); 408283514Sarybchik if (left->efs_ether_type != right->efs_ether_type) 409283514Sarybchik return (B_FALSE); 410283514Sarybchik if (left->efs_ip_proto != right->efs_ip_proto) 411283514Sarybchik return (B_FALSE); 412283514Sarybchik 413283514Sarybchik return (B_TRUE); 414283514Sarybchik 415283514Sarybchik} 416283514Sarybchik 417283514Sarybchikstatic __checkReturn boolean_t 418293764Sarybchikef10_filter_same_dest( 419283514Sarybchik __in const efx_filter_spec_t *left, 420283514Sarybchik __in const efx_filter_spec_t *right) 421283514Sarybchik{ 422283514Sarybchik if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 423283514Sarybchik (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { 424283514Sarybchik if (left->efs_rss_context == right->efs_rss_context) 425283514Sarybchik return (B_TRUE); 426283514Sarybchik } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && 427283514Sarybchik (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { 428283514Sarybchik if (left->efs_dmaq_id == right->efs_dmaq_id) 429283514Sarybchik return (B_TRUE); 430283514Sarybchik } 431283514Sarybchik return (B_FALSE); 432283514Sarybchik} 433283514Sarybchik 434283514Sarybchikstatic __checkReturn uint32_t 435293764Sarybchikef10_filter_hash( 436283514Sarybchik __in efx_filter_spec_t *spec) 437283514Sarybchik{ 438283514Sarybchik EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) 439283514Sarybchik == 0); 440283514Sarybchik EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % 441283514Sarybchik sizeof (uint32_t)) == 0); 442283514Sarybchik 443283514Sarybchik /* 444283514Sarybchik * As the area of the efx_filter_spec_t we need to hash is DWORD 445283514Sarybchik * aligned and an exact number of DWORDs in size we can use the 446283514Sarybchik * optimised efx_hash_dwords() rather than efx_hash_bytes() 447283514Sarybchik */ 448283514Sarybchik return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid, 449283514Sarybchik (sizeof (efx_filter_spec_t) - 450283514Sarybchik EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / 451283514Sarybchik sizeof (uint32_t), 0)); 452283514Sarybchik} 453283514Sarybchik 454283514Sarybchik/* 455283514Sarybchik * Decide whether a filter should be exclusive or else should allow 456283514Sarybchik * delivery to additional recipients. Currently we decide that 457283514Sarybchik * filters for specific local unicast MAC and IP addresses are 458283514Sarybchik * exclusive. 459283514Sarybchik */ 460283514Sarybchikstatic __checkReturn boolean_t 461293764Sarybchikef10_filter_is_exclusive( 462283514Sarybchik __in efx_filter_spec_t *spec) 463283514Sarybchik{ 464283514Sarybchik if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && 465283514Sarybchik !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 466283514Sarybchik return (B_TRUE); 467283514Sarybchik 468283514Sarybchik if ((spec->efs_match_flags & 469283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == 470283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { 471283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && 472283514Sarybchik ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) 473283514Sarybchik return (B_TRUE); 474283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && 475283514Sarybchik (spec->efs_loc_host.eo_u8[0] != 0xff)) 476283514Sarybchik return (B_TRUE); 477283514Sarybchik } 478283514Sarybchik 479283514Sarybchik return (B_FALSE); 480283514Sarybchik} 481283514Sarybchik 482291436Sarybchik __checkReturn efx_rc_t 483293764Sarybchikef10_filter_restore( 484283514Sarybchik __in efx_nic_t *enp) 485283514Sarybchik{ 486283514Sarybchik int tbl_id; 487283514Sarybchik efx_filter_spec_t *spec; 488293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 489283514Sarybchik boolean_t restoring; 490283514Sarybchik int state; 491291436Sarybchik efx_rc_t rc; 492283514Sarybchik 493293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 494293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 495283514Sarybchik 496293764Sarybchik for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) { 497283514Sarybchik 498283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 499283514Sarybchik 500293764Sarybchik spec = ef10_filter_entry_spec(eftp, tbl_id); 501283514Sarybchik if (spec == NULL) { 502283514Sarybchik restoring = B_FALSE; 503293764Sarybchik } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) { 504283514Sarybchik /* Ignore busy entries. */ 505283514Sarybchik restoring = B_FALSE; 506283514Sarybchik } else { 507293764Sarybchik ef10_filter_set_entry_busy(eftp, tbl_id); 508283514Sarybchik restoring = B_TRUE; 509283514Sarybchik } 510283514Sarybchik 511283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 512283514Sarybchik 513283514Sarybchik if (restoring == B_FALSE) 514283514Sarybchik continue; 515283514Sarybchik 516293764Sarybchik if (ef10_filter_is_exclusive(spec)) { 517283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 518283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 519293764Sarybchik &eftp->eft_entry[tbl_id].efe_handle); 520283514Sarybchik } else { 521283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 522283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 523293764Sarybchik &eftp->eft_entry[tbl_id].efe_handle); 524283514Sarybchik } 525283514Sarybchik 526283514Sarybchik if (rc != 0) 527283514Sarybchik goto fail1; 528283514Sarybchik 529283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 530283514Sarybchik 531293764Sarybchik ef10_filter_set_entry_not_busy(eftp, tbl_id); 532283514Sarybchik 533283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 534283514Sarybchik } 535283514Sarybchik 536283514Sarybchik return (0); 537283514Sarybchik 538283514Sarybchikfail1: 539291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 540283514Sarybchik 541283514Sarybchik return (rc); 542283514Sarybchik} 543283514Sarybchik 544283514Sarybchik/* 545283514Sarybchik * An arbitrary search limit for the software hash table. As per the linux net 546283514Sarybchik * driver. 547283514Sarybchik */ 548293764Sarybchik#define EF10_FILTER_SEARCH_LIMIT 200 549283514Sarybchik 550291436Sarybchikstatic __checkReturn efx_rc_t 551293764Sarybchikef10_filter_add_internal( 552283514Sarybchik __in efx_nic_t *enp, 553283514Sarybchik __inout efx_filter_spec_t *spec, 554283514Sarybchik __in boolean_t may_replace, 555283514Sarybchik __out_opt uint32_t *filter_id) 556283514Sarybchik{ 557291436Sarybchik efx_rc_t rc; 558293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 559283514Sarybchik efx_filter_spec_t *saved_spec; 560283514Sarybchik uint32_t hash; 561283514Sarybchik unsigned int depth; 562283514Sarybchik int ins_index; 563283514Sarybchik boolean_t replacing = B_FALSE; 564283514Sarybchik unsigned int i; 565283514Sarybchik int state; 566283514Sarybchik boolean_t locked = B_FALSE; 567283514Sarybchik 568293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 569293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 570283514Sarybchik 571283514Sarybchik#if EFSYS_OPT_RX_SCALE 572283514Sarybchik spec->efs_rss_context = enp->en_rss_context; 573283514Sarybchik#endif 574283514Sarybchik 575293764Sarybchik hash = ef10_filter_hash(spec); 576283514Sarybchik 577283514Sarybchik /* 578283514Sarybchik * FIXME: Add support for inserting filters of different priorities 579283514Sarybchik * and removing lower priority multicast filters (bug 42378) 580283514Sarybchik */ 581283514Sarybchik 582283514Sarybchik /* 583283514Sarybchik * Find any existing filters with the same match tuple or 584283514Sarybchik * else a free slot to insert at. If any of them are busy, 585283514Sarybchik * we have to wait and retry. 586283514Sarybchik */ 587283514Sarybchik for (;;) { 588283514Sarybchik ins_index = -1; 589283514Sarybchik depth = 1; 590283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 591283514Sarybchik locked = B_TRUE; 592283514Sarybchik 593283514Sarybchik for (;;) { 594293764Sarybchik i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 595293764Sarybchik saved_spec = ef10_filter_entry_spec(eftp, i); 596283514Sarybchik 597283514Sarybchik if (!saved_spec) { 598283514Sarybchik if (ins_index < 0) { 599283514Sarybchik ins_index = i; 600283514Sarybchik } 601293764Sarybchik } else if (ef10_filter_equal(spec, saved_spec)) { 602293764Sarybchik if (ef10_filter_entry_is_busy(eftp, i)) 603283514Sarybchik break; 604283514Sarybchik if (saved_spec->efs_priority 605283514Sarybchik == EFX_FILTER_PRI_AUTO) { 606283514Sarybchik ins_index = i; 607283514Sarybchik goto found; 608293764Sarybchik } else if (ef10_filter_is_exclusive(spec)) { 609283514Sarybchik if (may_replace) { 610283514Sarybchik ins_index = i; 611283514Sarybchik goto found; 612283514Sarybchik } else { 613283514Sarybchik rc = EEXIST; 614283514Sarybchik goto fail1; 615283514Sarybchik } 616283514Sarybchik } 617283514Sarybchik 618283514Sarybchik /* Leave existing */ 619283514Sarybchik } 620283514Sarybchik 621283514Sarybchik /* 622283514Sarybchik * Once we reach the maximum search depth, use 623283514Sarybchik * the first suitable slot or return EBUSY if 624283514Sarybchik * there was none. 625283514Sarybchik */ 626293764Sarybchik if (depth == EF10_FILTER_SEARCH_LIMIT) { 627283514Sarybchik if (ins_index < 0) { 628283514Sarybchik rc = EBUSY; 629283514Sarybchik goto fail2; 630283514Sarybchik } 631283514Sarybchik goto found; 632283514Sarybchik } 633283514Sarybchik depth++; 634283514Sarybchik } 635283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 636283514Sarybchik locked = B_FALSE; 637283514Sarybchik } 638283514Sarybchik 639283514Sarybchikfound: 640283514Sarybchik /* 641283514Sarybchik * Create a software table entry if necessary, and mark it 642283514Sarybchik * busy. We might yet fail to insert, but any attempt to 643283514Sarybchik * insert a conflicting filter while we're waiting for the 644283514Sarybchik * firmware must find the busy entry. 645283514Sarybchik */ 646293764Sarybchik saved_spec = ef10_filter_entry_spec(eftp, ins_index); 647283514Sarybchik if (saved_spec) { 648283514Sarybchik if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { 649283514Sarybchik /* This is a filter we are refreshing */ 650293764Sarybchik ef10_filter_set_entry_not_auto_old(eftp, ins_index); 651283514Sarybchik goto out_unlock; 652283514Sarybchik 653283514Sarybchik } 654283514Sarybchik replacing = B_TRUE; 655283514Sarybchik } else { 656283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); 657283514Sarybchik if (!saved_spec) { 658283514Sarybchik rc = ENOMEM; 659283514Sarybchik goto fail3; 660283514Sarybchik } 661283514Sarybchik *saved_spec = *spec; 662293764Sarybchik ef10_filter_set_entry(eftp, ins_index, saved_spec); 663283514Sarybchik } 664293764Sarybchik ef10_filter_set_entry_busy(eftp, ins_index); 665283514Sarybchik 666283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 667283514Sarybchik locked = B_FALSE; 668283514Sarybchik 669283514Sarybchik /* 670283514Sarybchik * On replacing the filter handle may change after after a successful 671283514Sarybchik * replace operation. 672283514Sarybchik */ 673283514Sarybchik if (replacing) { 674283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 675283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REPLACE, 676293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 677293764Sarybchik } else if (ef10_filter_is_exclusive(spec)) { 678283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 679283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 680293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 681283514Sarybchik } else { 682283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 683283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 684293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 685283514Sarybchik } 686283514Sarybchik 687283514Sarybchik if (rc != 0) 688283514Sarybchik goto fail4; 689283514Sarybchik 690283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 691283514Sarybchik locked = B_TRUE; 692283514Sarybchik 693283514Sarybchik if (replacing) { 694283514Sarybchik /* Update the fields that may differ */ 695283514Sarybchik saved_spec->efs_priority = spec->efs_priority; 696283514Sarybchik saved_spec->efs_flags = spec->efs_flags; 697283514Sarybchik saved_spec->efs_rss_context = spec->efs_rss_context; 698283514Sarybchik saved_spec->efs_dmaq_id = spec->efs_dmaq_id; 699283514Sarybchik } 700283514Sarybchik 701293764Sarybchik ef10_filter_set_entry_not_busy(eftp, ins_index); 702283514Sarybchik 703283514Sarybchikout_unlock: 704283514Sarybchik 705283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 706283514Sarybchik locked = B_FALSE; 707283514Sarybchik 708283514Sarybchik if (filter_id) 709283514Sarybchik *filter_id = ins_index; 710283514Sarybchik 711283514Sarybchik return (0); 712283514Sarybchik 713283514Sarybchikfail4: 714283514Sarybchik EFSYS_PROBE(fail4); 715283514Sarybchik 716283514Sarybchik if (!replacing) { 717283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); 718283514Sarybchik saved_spec = NULL; 719283514Sarybchik } 720293764Sarybchik ef10_filter_set_entry_not_busy(eftp, ins_index); 721293764Sarybchik ef10_filter_set_entry(eftp, ins_index, NULL); 722283514Sarybchik 723283514Sarybchikfail3: 724283514Sarybchik EFSYS_PROBE(fail3); 725283514Sarybchik 726283514Sarybchikfail2: 727283514Sarybchik EFSYS_PROBE(fail2); 728283514Sarybchik 729283514Sarybchikfail1: 730291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 731283514Sarybchik 732283514Sarybchik if (locked) 733283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 734283514Sarybchik 735283514Sarybchik return (rc); 736283514Sarybchik} 737283514Sarybchik 738291436Sarybchik __checkReturn efx_rc_t 739293764Sarybchikef10_filter_add( 740283514Sarybchik __in efx_nic_t *enp, 741283514Sarybchik __inout efx_filter_spec_t *spec, 742283514Sarybchik __in boolean_t may_replace) 743283514Sarybchik{ 744291436Sarybchik efx_rc_t rc; 745283514Sarybchik 746293764Sarybchik rc = ef10_filter_add_internal(enp, spec, may_replace, NULL); 747283514Sarybchik if (rc != 0) 748283514Sarybchik goto fail1; 749283514Sarybchik 750283514Sarybchik return (0); 751283514Sarybchik 752283514Sarybchikfail1: 753291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 754283514Sarybchik 755283514Sarybchik return (rc); 756283514Sarybchik} 757283514Sarybchik 758283514Sarybchik 759291436Sarybchikstatic __checkReturn efx_rc_t 760293764Sarybchikef10_filter_delete_internal( 761283514Sarybchik __in efx_nic_t *enp, 762283514Sarybchik __in uint32_t filter_id) 763283514Sarybchik{ 764291436Sarybchik efx_rc_t rc; 765293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 766283514Sarybchik efx_filter_spec_t *spec; 767283514Sarybchik int state; 768293764Sarybchik uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS; 769283514Sarybchik 770283514Sarybchik /* 771283514Sarybchik * Find the software table entry and mark it busy. Don't 772283514Sarybchik * remove it yet; any attempt to update while we're waiting 773283514Sarybchik * for the firmware must find the busy entry. 774283514Sarybchik * 775283514Sarybchik * FIXME: What if the busy flag is never cleared? 776283514Sarybchik */ 777283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 778293764Sarybchik while (ef10_filter_entry_is_busy(table, filter_idx)) { 779283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 780283514Sarybchik EFSYS_SPIN(1); 781283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 782283514Sarybchik } 783293764Sarybchik if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) { 784293764Sarybchik ef10_filter_set_entry_busy(table, filter_idx); 785283514Sarybchik } 786283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 787283514Sarybchik 788283514Sarybchik if (spec == NULL) { 789283514Sarybchik rc = ENOENT; 790283514Sarybchik goto fail1; 791283514Sarybchik } 792283514Sarybchik 793283514Sarybchik /* 794283514Sarybchik * Try to remove the hardware filter. This may fail if the MC has 795283514Sarybchik * rebooted (which frees all hardware filter resources). 796283514Sarybchik */ 797293764Sarybchik if (ef10_filter_is_exclusive(spec)) { 798283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 799283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE, 800293764Sarybchik &table->eft_entry[filter_idx].efe_handle); 801283514Sarybchik } else { 802283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 803283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, 804293764Sarybchik &table->eft_entry[filter_idx].efe_handle); 805283514Sarybchik } 806283514Sarybchik 807283514Sarybchik /* Free the software table entry */ 808283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 809293764Sarybchik ef10_filter_set_entry_not_busy(table, filter_idx); 810293764Sarybchik ef10_filter_set_entry(table, filter_idx, NULL); 811283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 812283514Sarybchik 813283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 814283514Sarybchik 815283514Sarybchik /* Check result of hardware filter removal */ 816283514Sarybchik if (rc != 0) 817283514Sarybchik goto fail2; 818283514Sarybchik 819283514Sarybchik return (0); 820283514Sarybchik 821283514Sarybchikfail2: 822283514Sarybchik EFSYS_PROBE(fail2); 823283514Sarybchik 824283514Sarybchikfail1: 825291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 826283514Sarybchik 827283514Sarybchik return (rc); 828283514Sarybchik} 829283514Sarybchik 830291436Sarybchik __checkReturn efx_rc_t 831293764Sarybchikef10_filter_delete( 832283514Sarybchik __in efx_nic_t *enp, 833283514Sarybchik __inout efx_filter_spec_t *spec) 834283514Sarybchik{ 835291436Sarybchik efx_rc_t rc; 836293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 837283514Sarybchik efx_filter_spec_t *saved_spec; 838283514Sarybchik unsigned int hash; 839283514Sarybchik unsigned int depth; 840283514Sarybchik unsigned int i; 841283514Sarybchik int state; 842283514Sarybchik boolean_t locked = B_FALSE; 843283514Sarybchik 844293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 845293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 846283514Sarybchik 847293764Sarybchik hash = ef10_filter_hash(spec); 848283514Sarybchik 849283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 850283514Sarybchik locked = B_TRUE; 851283514Sarybchik 852283514Sarybchik depth = 1; 853283514Sarybchik for (;;) { 854293764Sarybchik i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 855293764Sarybchik saved_spec = ef10_filter_entry_spec(table, i); 856293764Sarybchik if (saved_spec && ef10_filter_equal(spec, saved_spec) && 857293764Sarybchik ef10_filter_same_dest(spec, saved_spec)) { 858283514Sarybchik break; 859283514Sarybchik } 860293764Sarybchik if (depth == EF10_FILTER_SEARCH_LIMIT) { 861283514Sarybchik rc = ENOENT; 862283514Sarybchik goto fail1; 863283514Sarybchik } 864283514Sarybchik depth++; 865283514Sarybchik } 866283514Sarybchik 867283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 868283514Sarybchik locked = B_FALSE; 869283514Sarybchik 870293764Sarybchik rc = ef10_filter_delete_internal(enp, i); 871283514Sarybchik if (rc != 0) 872283514Sarybchik goto fail2; 873283514Sarybchik 874283514Sarybchik return (0); 875283514Sarybchik 876283514Sarybchikfail2: 877283514Sarybchik EFSYS_PROBE(fail2); 878283514Sarybchik 879283514Sarybchikfail1: 880291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 881283514Sarybchik 882283514Sarybchik if (locked) 883283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 884283514Sarybchik 885283514Sarybchik return (rc); 886283514Sarybchik} 887283514Sarybchik 888291436Sarybchikstatic __checkReturn efx_rc_t 889283514Sarybchikefx_mcdi_get_parser_disp_info( 890283514Sarybchik __in efx_nic_t *enp, 891283514Sarybchik __out uint32_t *list, 892283514Sarybchik __out size_t *length) 893283514Sarybchik{ 894283514Sarybchik efx_mcdi_req_t req; 895283514Sarybchik uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, 896283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)]; 897291436Sarybchik efx_rc_t rc; 898283514Sarybchik uint32_t i; 899283514Sarybchik boolean_t support_unknown_ucast = B_FALSE; 900283514Sarybchik boolean_t support_unknown_mcast = B_FALSE; 901283514Sarybchik 902283514Sarybchik (void) memset(payload, 0, sizeof (payload)); 903283514Sarybchik req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; 904283514Sarybchik req.emr_in_buf = payload; 905283514Sarybchik req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; 906283514Sarybchik req.emr_out_buf = payload; 907283514Sarybchik req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; 908283514Sarybchik 909283514Sarybchik MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, 910283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); 911283514Sarybchik 912283514Sarybchik efx_mcdi_execute(enp, &req); 913283514Sarybchik 914283514Sarybchik if (req.emr_rc != 0) { 915283514Sarybchik rc = req.emr_rc; 916283514Sarybchik goto fail1; 917283514Sarybchik } 918283514Sarybchik 919283514Sarybchik *length = MCDI_OUT_DWORD(req, 920283514Sarybchik GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); 921283514Sarybchik 922283514Sarybchik if (req.emr_out_length_used < 923283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) { 924283514Sarybchik rc = EMSGSIZE; 925283514Sarybchik goto fail2; 926283514Sarybchik } 927283514Sarybchik 928283514Sarybchik memcpy(list, 929283514Sarybchik MCDI_OUT2(req, 930283514Sarybchik uint32_t, 931283514Sarybchik GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), 932283514Sarybchik (*length) * sizeof (uint32_t)); 933283514Sarybchik EFX_STATIC_ASSERT(sizeof (uint32_t) == 934283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); 935283514Sarybchik 936283514Sarybchik /* 937283514Sarybchik * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change 938283514Sarybchik * the lower priority one to LOC_MAC_IG. 939283514Sarybchik */ 940283514Sarybchik for (i = 0; i < *length; i++) { 941283514Sarybchik if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) { 942283514Sarybchik list[i] &= 943283514Sarybchik (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN); 944283514Sarybchik support_unknown_ucast = B_TRUE; 945283514Sarybchik } 946283514Sarybchik if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) { 947283514Sarybchik list[i] &= 948283514Sarybchik (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN); 949283514Sarybchik support_unknown_mcast = B_TRUE; 950283514Sarybchik } 951283514Sarybchik 952283514Sarybchik if (support_unknown_ucast && support_unknown_mcast) { 953283514Sarybchik list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG; 954283514Sarybchik break; 955283514Sarybchik } 956283514Sarybchik } 957283514Sarybchik 958283514Sarybchik return (0); 959283514Sarybchik 960283514Sarybchikfail2: 961283514Sarybchik EFSYS_PROBE(fail2); 962283514Sarybchikfail1: 963291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 964283514Sarybchik 965283514Sarybchik return (rc); 966283514Sarybchik} 967283514Sarybchik 968291436Sarybchik __checkReturn efx_rc_t 969293764Sarybchikef10_filter_supported_filters( 970283514Sarybchik __in efx_nic_t *enp, 971283514Sarybchik __out uint32_t *list, 972283514Sarybchik __out size_t *length) 973283514Sarybchik{ 974291436Sarybchik efx_rc_t rc; 975283514Sarybchik 976283514Sarybchik if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length) != 0)) 977283514Sarybchik goto fail1; 978283514Sarybchik 979283514Sarybchik return (0); 980283514Sarybchik 981283514Sarybchikfail1: 982291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 983283514Sarybchik 984283514Sarybchik return (rc); 985283514Sarybchik} 986283514Sarybchik 987291436Sarybchikstatic __checkReturn efx_rc_t 988293764Sarybchikef10_filter_unicast_refresh( 989283514Sarybchik __in efx_nic_t *enp, 990283514Sarybchik __in_ecount(6) uint8_t const *addr, 991283514Sarybchik __in boolean_t all_unicst, 992283514Sarybchik __in efx_filter_flag_t filter_flags) 993283514Sarybchik{ 994293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 995283514Sarybchik efx_filter_spec_t spec; 996291436Sarybchik efx_rc_t rc; 997283514Sarybchik 998283514Sarybchik if (all_unicst == B_TRUE) 999283514Sarybchik goto use_uc_def; 1000283514Sarybchik 1001283514Sarybchik /* Insert the filter for the local station address */ 1002283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1003283514Sarybchik filter_flags, 1004293764Sarybchik eftp->eft_default_rxq); 1005283514Sarybchik efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr); 1006283514Sarybchik 1007293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1008293764Sarybchik &eftp->eft_unicst_filter_index); 1009283514Sarybchik if (rc != 0) { 1010283514Sarybchik /* 1011283514Sarybchik * Fall back to an unknown filter. We may be able to subscribe 1012283514Sarybchik * to it even if we couldn't insert the unicast filter. 1013283514Sarybchik */ 1014283514Sarybchik goto use_uc_def; 1015283514Sarybchik } 1016293764Sarybchik eftp->eft_unicst_filter_set = B_TRUE; 1017283514Sarybchik 1018283514Sarybchik return (0); 1019283514Sarybchik 1020283514Sarybchikuse_uc_def: 1021283514Sarybchik /* Insert the unknown unicast filter */ 1022283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1023283514Sarybchik filter_flags, 1024293764Sarybchik eftp->eft_default_rxq); 1025283514Sarybchik efx_filter_spec_set_uc_def(&spec); 1026293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1027293764Sarybchik &eftp->eft_unicst_filter_index); 1028283514Sarybchik if (rc != 0) 1029283514Sarybchik goto fail1; 1030283514Sarybchik 1031293764Sarybchik eftp->eft_unicst_filter_set = B_TRUE; 1032283514Sarybchik 1033283514Sarybchik return (0); 1034283514Sarybchik 1035283514Sarybchikfail1: 1036291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1037283514Sarybchik 1038293764Sarybchik if (eftp->eft_unicst_filter_set != B_FALSE) { 1039293764Sarybchik (void) ef10_filter_delete_internal(enp, 1040293764Sarybchik eftp->eft_unicst_filter_index); 1041283514Sarybchik 1042293764Sarybchik eftp->eft_unicst_filter_set = B_FALSE; 1043283514Sarybchik } 1044283514Sarybchik 1045283514Sarybchik return (rc); 1046283514Sarybchik} 1047283514Sarybchik 1048291436Sarybchikstatic __checkReturn efx_rc_t 1049293764Sarybchikef10_filter_multicast_refresh( 1050283514Sarybchik __in efx_nic_t *enp, 1051283514Sarybchik __in boolean_t mulcst, 1052283514Sarybchik __in boolean_t all_mulcst, 1053283514Sarybchik __in boolean_t brdcst, 1054283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1055283514Sarybchik __in int count, 1056283514Sarybchik __in efx_filter_flag_t filter_flags) 1057283514Sarybchik{ 1058293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1059283514Sarybchik efx_filter_spec_t spec; 1060283514Sarybchik uint8_t addr[6]; 1061283514Sarybchik unsigned i; 1062291436Sarybchik efx_rc_t rc; 1063283514Sarybchik 1064283514Sarybchik if (all_mulcst == B_TRUE) 1065283514Sarybchik goto use_mc_def; 1066283514Sarybchik 1067283514Sarybchik if (mulcst == B_FALSE) 1068283514Sarybchik count = 0; 1069283514Sarybchik 1070283514Sarybchik if (count + (brdcst ? 1 : 0) > 1071293764Sarybchik EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) { 1072283514Sarybchik /* Too many MAC addresses; use unknown multicast filter */ 1073283514Sarybchik goto use_mc_def; 1074283514Sarybchik } 1075283514Sarybchik 1076283514Sarybchik /* Insert/renew multicast address list filters */ 1077293764Sarybchik eftp->eft_mulcst_filter_count = count; 1078293764Sarybchik for (i = 0; i < eftp->eft_mulcst_filter_count; i++) { 1079283514Sarybchik efx_filter_spec_init_rx(&spec, 1080283514Sarybchik EFX_FILTER_PRI_AUTO, 1081283514Sarybchik filter_flags, 1082293764Sarybchik eftp->eft_default_rxq); 1083283514Sarybchik 1084283514Sarybchik efx_filter_spec_set_eth_local(&spec, 1085283514Sarybchik EFX_FILTER_SPEC_VID_UNSPEC, 1086283514Sarybchik &addrs[i * EFX_MAC_ADDR_LEN]); 1087283514Sarybchik 1088293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1089293764Sarybchik &eftp->eft_mulcst_filter_indexes[i]); 1090283514Sarybchik if (rc != 0) { 1091283514Sarybchik /* Rollback, then use unknown multicast filter */ 1092283514Sarybchik goto rollback; 1093283514Sarybchik } 1094283514Sarybchik } 1095283514Sarybchik 1096283514Sarybchik if (brdcst == B_TRUE) { 1097283514Sarybchik /* Insert/renew broadcast address filter */ 1098293764Sarybchik eftp->eft_mulcst_filter_count++; 1099283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1100283514Sarybchik filter_flags, 1101293764Sarybchik eftp->eft_default_rxq); 1102283514Sarybchik 1103283514Sarybchik EFX_MAC_BROADCAST_ADDR_SET(addr); 1104283514Sarybchik efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, 1105283514Sarybchik addr); 1106283514Sarybchik 1107293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1108293764Sarybchik &eftp->eft_mulcst_filter_indexes[ 1109293764Sarybchik eftp->eft_mulcst_filter_count - 1]); 1110283514Sarybchik if (rc != 0) { 1111283514Sarybchik /* Rollback, then use unknown multicast filter */ 1112283514Sarybchik goto rollback; 1113283514Sarybchik } 1114283514Sarybchik } 1115283514Sarybchik 1116283514Sarybchik return (0); 1117283514Sarybchik 1118283514Sarybchikrollback: 1119283514Sarybchik /* 1120283514Sarybchik * Rollback by removing any filters we have inserted 1121283514Sarybchik * before inserting the unknown multicast filter. 1122283514Sarybchik */ 1123283514Sarybchik while (i--) { 1124293764Sarybchik (void) ef10_filter_delete_internal(enp, 1125293764Sarybchik eftp->eft_mulcst_filter_indexes[i]); 1126283514Sarybchik } 1127293764Sarybchik eftp->eft_mulcst_filter_count = 0; 1128283514Sarybchik 1129283514Sarybchikuse_mc_def: 1130283514Sarybchik /* Insert the unknown multicast filter */ 1131283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1132283514Sarybchik filter_flags, 1133293764Sarybchik eftp->eft_default_rxq); 1134283514Sarybchik efx_filter_spec_set_mc_def(&spec); 1135283514Sarybchik 1136293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1137293764Sarybchik &eftp->eft_mulcst_filter_indexes[0]); 1138283514Sarybchik if (rc != 0) 1139283514Sarybchik goto fail1; 1140283514Sarybchik 1141293764Sarybchik eftp->eft_mulcst_filter_count = 1; 1142283514Sarybchik 1143283514Sarybchik /* 1144283514Sarybchik * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. 1145283514Sarybchik */ 1146283514Sarybchik 1147283514Sarybchik return (0); 1148283514Sarybchik 1149283514Sarybchikfail1: 1150291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1151283514Sarybchik 1152283514Sarybchik return (rc); 1153283514Sarybchik 1154283514Sarybchik} 1155283514Sarybchik 1156283514Sarybchik 1157291436Sarybchikstatic __checkReturn efx_rc_t 1158283514Sarybchikhunt_filter_get_workarounds( 1159283514Sarybchik __in efx_nic_t *enp) 1160283514Sarybchik{ 1161283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1162283514Sarybchik uint32_t implemented = 0; 1163283514Sarybchik uint32_t enabled = 0; 1164291436Sarybchik efx_rc_t rc; 1165283514Sarybchik 1166283514Sarybchik rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); 1167283514Sarybchik if (rc == 0) { 1168283514Sarybchik /* Check if chained multicast filter support is enabled */ 1169283514Sarybchik if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) 1170283514Sarybchik encp->enc_bug26807_workaround = B_TRUE; 1171283514Sarybchik else 1172283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1173283514Sarybchik } else if (rc == ENOTSUP) { 1174283514Sarybchik /* 1175283514Sarybchik * Firmware is too old to support GET_WORKAROUNDS, and support 1176283514Sarybchik * for this workaround was implemented later. 1177283514Sarybchik */ 1178283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1179283514Sarybchik } else { 1180283514Sarybchik goto fail1; 1181283514Sarybchik } 1182283514Sarybchik 1183283514Sarybchik return (0); 1184283514Sarybchik 1185283514Sarybchikfail1: 1186291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1187283514Sarybchik 1188283514Sarybchik return (rc); 1189283514Sarybchik 1190283514Sarybchik} 1191283514Sarybchik 1192283514Sarybchik 1193283514Sarybchik/* 1194283514Sarybchik * Reconfigure all filters. 1195283514Sarybchik * If all_unicst and/or all mulcst filters cannot be applied then 1196283514Sarybchik * return ENOTSUP (Note the filters for the specified addresses are 1197283514Sarybchik * still applied in this case). 1198283514Sarybchik */ 1199291436Sarybchik __checkReturn efx_rc_t 1200293764Sarybchikef10_filter_reconfigure( 1201283514Sarybchik __in efx_nic_t *enp, 1202283514Sarybchik __in_ecount(6) uint8_t const *mac_addr, 1203283514Sarybchik __in boolean_t all_unicst, 1204283514Sarybchik __in boolean_t mulcst, 1205283514Sarybchik __in boolean_t all_mulcst, 1206283514Sarybchik __in boolean_t brdcst, 1207283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1208283514Sarybchik __in int count) 1209283514Sarybchik{ 1210293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1211283514Sarybchik efx_filter_flag_t filter_flags; 1212283514Sarybchik unsigned i; 1213283514Sarybchik int all_unicst_rc; 1214283514Sarybchik int all_mulcst_rc; 1215291436Sarybchik efx_rc_t rc; 1216283514Sarybchik 1217293764Sarybchik if (table->eft_default_rxq == NULL) { 1218283514Sarybchik /* 1219283514Sarybchik * Filters direct traffic to the default RXQ, and so cannot be 1220283514Sarybchik * inserted until it is available. Any currently configured 1221283514Sarybchik * filters must be removed (ignore errors in case the MC 1222283514Sarybchik * has rebooted, which removes hardware filters). 1223283514Sarybchik */ 1224293764Sarybchik if (table->eft_unicst_filter_set != B_FALSE) { 1225293764Sarybchik (void) ef10_filter_delete_internal(enp, 1226293764Sarybchik table->eft_unicst_filter_index); 1227293764Sarybchik table->eft_unicst_filter_set = B_FALSE; 1228283514Sarybchik } 1229293764Sarybchik for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1230293764Sarybchik (void) ef10_filter_delete_internal(enp, 1231293764Sarybchik table->eft_mulcst_filter_indexes[i]); 1232283514Sarybchik } 1233293764Sarybchik table->eft_mulcst_filter_count = 0; 1234283514Sarybchik 1235283514Sarybchik return (0); 1236283514Sarybchik } 1237283514Sarybchik 1238293764Sarybchik if (table->eft_using_rss) 1239283514Sarybchik filter_flags = EFX_FILTER_FLAG_RX_RSS; 1240283514Sarybchik else 1241283514Sarybchik filter_flags = 0; 1242283514Sarybchik 1243283514Sarybchik /* Mark old filters which may need to be removed */ 1244293764Sarybchik if (table->eft_unicst_filter_set != B_FALSE) { 1245293764Sarybchik ef10_filter_set_entry_auto_old(table, 1246293764Sarybchik table->eft_unicst_filter_index); 1247283514Sarybchik } 1248293764Sarybchik for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1249293764Sarybchik ef10_filter_set_entry_auto_old(table, 1250293764Sarybchik table->eft_mulcst_filter_indexes[i]); 1251283514Sarybchik } 1252283514Sarybchik 1253283514Sarybchik /* Insert or renew unicast filters */ 1254293764Sarybchik if ((all_unicst_rc = ef10_filter_unicast_refresh(enp, mac_addr, 1255283514Sarybchik all_unicst, filter_flags)) != 0) { 1256283514Sarybchik if (all_unicst == B_FALSE) { 1257283514Sarybchik rc = all_unicst_rc; 1258283514Sarybchik goto fail1; 1259283514Sarybchik } 1260283514Sarybchik /* Retry without all_unicast flag */ 1261293764Sarybchik rc = ef10_filter_unicast_refresh(enp, mac_addr, 1262283514Sarybchik B_FALSE, filter_flags); 1263283514Sarybchik if (rc != 0) 1264283514Sarybchik goto fail2; 1265283514Sarybchik } 1266283514Sarybchik 1267283514Sarybchik /* 1268283514Sarybchik * WORKAROUND_BUG26807 controls firmware support for chained multicast 1269283514Sarybchik * filters, and can only be enabled or disabled when the hardware filter 1270283514Sarybchik * table is empty. 1271283514Sarybchik * 1272283514Sarybchik * Firmware will reset (FLR) functions which have inserted filters in 1273283514Sarybchik * the hardware filter table when the workaround is enabled/disabled. 1274283514Sarybchik * Functions without any hardware filters are not reset. 1275283514Sarybchik * 1276283514Sarybchik * Re-check if the workaround is enabled after adding unicast hardware 1277283514Sarybchik * filters. This ensures that encp->enc_workaround_bug26807 matches the 1278283514Sarybchik * firmware state, and that later changes to enable/disable the 1279283514Sarybchik * workaround will result in this function seeing a reset (FLR). 1280293764Sarybchik * 1281293764Sarybchik * FIXME: On Medford mulicast chaining should always be on. 1282283514Sarybchik */ 1283283514Sarybchik if ((rc = hunt_filter_get_workarounds(enp)) != 0) 1284283514Sarybchik goto fail3; 1285283514Sarybchik 1286283514Sarybchik /* Insert or renew multicast filters */ 1287293764Sarybchik if ((all_mulcst_rc = ef10_filter_multicast_refresh(enp, mulcst, 1288283514Sarybchik all_mulcst, brdcst, 1289283514Sarybchik addrs, count, filter_flags)) != 0) { 1290283514Sarybchik if (all_mulcst == B_FALSE) { 1291283514Sarybchik rc = all_mulcst_rc; 1292283514Sarybchik goto fail4; 1293283514Sarybchik } 1294283514Sarybchik /* Retry without all_mulcast flag */ 1295293764Sarybchik rc = ef10_filter_multicast_refresh(enp, mulcst, 1296283514Sarybchik B_FALSE, brdcst, 1297283514Sarybchik addrs, count, filter_flags); 1298283514Sarybchik if (rc != 0) 1299283514Sarybchik goto fail5; 1300283514Sarybchik } 1301283514Sarybchik 1302283514Sarybchik /* Remove old filters which were not renewed */ 1303293764Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1304293764Sarybchik if (ef10_filter_entry_is_auto_old(table, i)) { 1305293764Sarybchik (void) ef10_filter_delete_internal(enp, i); 1306283514Sarybchik } 1307283514Sarybchik } 1308283514Sarybchik 1309283514Sarybchik /* report if any optional flags were rejected */ 1310283514Sarybchik if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || 1311283514Sarybchik ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { 1312283514Sarybchik rc = ENOTSUP; 1313283514Sarybchik } 1314283514Sarybchik 1315283514Sarybchik return (rc); 1316283514Sarybchik 1317283514Sarybchikfail5: 1318283514Sarybchik EFSYS_PROBE(fail5); 1319283514Sarybchikfail4: 1320283514Sarybchik EFSYS_PROBE(fail4); 1321283514Sarybchikfail3: 1322283514Sarybchik EFSYS_PROBE(fail3); 1323283514Sarybchikfail2: 1324283514Sarybchik EFSYS_PROBE(fail2); 1325283514Sarybchikfail1: 1326291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1327283514Sarybchik 1328283514Sarybchik /* Clear auto old flags */ 1329293764Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1330293764Sarybchik if (ef10_filter_entry_is_auto_old(table, i)) { 1331293764Sarybchik ef10_filter_set_entry_not_auto_old(table, i); 1332283514Sarybchik } 1333283514Sarybchik } 1334283514Sarybchik 1335283514Sarybchik return (rc); 1336283514Sarybchik} 1337283514Sarybchik 1338283514Sarybchik void 1339293764Sarybchikef10_filter_get_default_rxq( 1340283514Sarybchik __in efx_nic_t *enp, 1341283514Sarybchik __out efx_rxq_t **erpp, 1342283514Sarybchik __out boolean_t *using_rss) 1343283514Sarybchik{ 1344293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1345283514Sarybchik 1346293764Sarybchik *erpp = table->eft_default_rxq; 1347293764Sarybchik *using_rss = table->eft_using_rss; 1348283514Sarybchik} 1349283514Sarybchik 1350283514Sarybchik 1351283514Sarybchik void 1352293764Sarybchikef10_filter_default_rxq_set( 1353283514Sarybchik __in efx_nic_t *enp, 1354283514Sarybchik __in efx_rxq_t *erp, 1355283514Sarybchik __in boolean_t using_rss) 1356283514Sarybchik{ 1357293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1358283514Sarybchik 1359283514Sarybchik#if EFSYS_OPT_RX_SCALE 1360283514Sarybchik EFSYS_ASSERT((using_rss == B_FALSE) || 1361293754Sarybchik (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID)); 1362293764Sarybchik table->eft_using_rss = using_rss; 1363283514Sarybchik#else 1364283514Sarybchik EFSYS_ASSERT(using_rss == B_FALSE); 1365293764Sarybchik table->eft_using_rss = B_FALSE; 1366283514Sarybchik#endif 1367293764Sarybchik table->eft_default_rxq = erp; 1368283514Sarybchik} 1369283514Sarybchik 1370283514Sarybchik void 1371293764Sarybchikef10_filter_default_rxq_clear( 1372283514Sarybchik __in efx_nic_t *enp) 1373283514Sarybchik{ 1374293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1375283514Sarybchik 1376293764Sarybchik table->eft_default_rxq = NULL; 1377293764Sarybchik table->eft_using_rss = B_FALSE; 1378283514Sarybchik} 1379283514Sarybchik 1380283514Sarybchik 1381283514Sarybchik#endif /* EFSYS_OPT_FILTER */ 1382283514Sarybchik 1383283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 1384