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: releng/10.2/sys/dev/sfxge/common/hunt_filter.c 284555 2015-06-18 15:46:39Z 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 44283514Sarybchik#define HFE_SPEC(hftp, index) ((hftp)->hft_entry[(index)].hfe_spec) 45283514Sarybchik 46283514Sarybchikstatic efx_filter_spec_t * 47283514Sarybchikhunt_filter_entry_spec( 48283514Sarybchik __in const hunt_filter_table_t *hftp, 49283514Sarybchik __in unsigned int index) 50283514Sarybchik{ 51283514Sarybchik return ((efx_filter_spec_t *)(HFE_SPEC(hftp, index) & 52283514Sarybchik ~(uintptr_t)EFX_HUNT_FILTER_FLAGS)); 53283514Sarybchik} 54283514Sarybchik 55283514Sarybchikstatic boolean_t 56283514Sarybchikhunt_filter_entry_is_busy( 57283514Sarybchik __in const hunt_filter_table_t *hftp, 58283514Sarybchik __in unsigned int index) 59283514Sarybchik{ 60283514Sarybchik if (HFE_SPEC(hftp, index) & EFX_HUNT_FILTER_FLAG_BUSY) 61283514Sarybchik return (B_TRUE); 62283514Sarybchik else 63283514Sarybchik return (B_FALSE); 64283514Sarybchik} 65283514Sarybchik 66283514Sarybchikstatic boolean_t 67283514Sarybchikhunt_filter_entry_is_auto_old( 68283514Sarybchik __in const hunt_filter_table_t *hftp, 69283514Sarybchik __in unsigned int index) 70283514Sarybchik{ 71283514Sarybchik if (HFE_SPEC(hftp, index) & EFX_HUNT_FILTER_FLAG_AUTO_OLD) 72283514Sarybchik return (B_TRUE); 73283514Sarybchik else 74283514Sarybchik return (B_FALSE); 75283514Sarybchik} 76283514Sarybchik 77283514Sarybchikstatic void 78283514Sarybchikhunt_filter_set_entry( 79283514Sarybchik __inout hunt_filter_table_t *hftp, 80283514Sarybchik __in unsigned int index, 81283514Sarybchik __in_opt const efx_filter_spec_t *efsp) 82283514Sarybchik{ 83283514Sarybchik HFE_SPEC(hftp, index) = (uintptr_t)efsp; 84283514Sarybchik} 85283514Sarybchik 86283514Sarybchikstatic void 87283514Sarybchikhunt_filter_set_entry_busy( 88283514Sarybchik __inout hunt_filter_table_t *hftp, 89283514Sarybchik __in unsigned int index) 90283514Sarybchik{ 91283514Sarybchik HFE_SPEC(hftp, index) |= (uintptr_t)EFX_HUNT_FILTER_FLAG_BUSY; 92283514Sarybchik} 93283514Sarybchik 94283514Sarybchikstatic void 95283514Sarybchikhunt_filter_set_entry_not_busy( 96283514Sarybchik __inout hunt_filter_table_t *hftp, 97283514Sarybchik __in unsigned int index) 98283514Sarybchik{ 99283514Sarybchik HFE_SPEC(hftp, index) &= ~(uintptr_t)EFX_HUNT_FILTER_FLAG_BUSY; 100283514Sarybchik} 101283514Sarybchik 102283514Sarybchikstatic void 103283514Sarybchikhunt_filter_set_entry_auto_old( 104283514Sarybchik __inout hunt_filter_table_t *hftp, 105283514Sarybchik __in unsigned int index) 106283514Sarybchik{ 107283514Sarybchik EFSYS_ASSERT(hunt_filter_entry_spec(hftp, index) != NULL); 108283514Sarybchik HFE_SPEC(hftp, index) |= (uintptr_t)EFX_HUNT_FILTER_FLAG_AUTO_OLD; 109283514Sarybchik} 110283514Sarybchik 111283514Sarybchikstatic void 112283514Sarybchikhunt_filter_set_entry_not_auto_old( 113283514Sarybchik __inout hunt_filter_table_t *hftp, 114283514Sarybchik __in unsigned int index) 115283514Sarybchik{ 116283514Sarybchik HFE_SPEC(hftp, index) &= ~(uintptr_t)EFX_HUNT_FILTER_FLAG_AUTO_OLD; 117283514Sarybchik EFSYS_ASSERT(hunt_filter_entry_spec(hftp, index) != NULL); 118283514Sarybchik} 119283514Sarybchik 120283514Sarybchik __checkReturn int 121283514Sarybchikhunt_filter_init( 122283514Sarybchik __in efx_nic_t *enp) 123283514Sarybchik{ 124283514Sarybchik int rc; 125283514Sarybchik hunt_filter_table_t *hftp; 126283514Sarybchik 127283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 128283514Sarybchik 129283514Sarybchik#define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match)) 130283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST == 131283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_IP)); 132283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == 133283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_IP)); 134283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == 135283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_MAC)); 136283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == 137283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_PORT)); 138283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == 139283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_MAC)); 140283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == 141283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_PORT)); 142283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == 143283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_ETHER_TYPE)); 144283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == 145283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_INNER_VLAN)); 146283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == 147283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN)); 148283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == 149283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO)); 150283514Sarybchik#undef MATCH_MASK 151283514Sarybchik 152283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (hunt_filter_table_t), hftp); 153283514Sarybchik 154283514Sarybchik if (!hftp) { 155283514Sarybchik rc = ENOMEM; 156283514Sarybchik goto fail1; 157283514Sarybchik } 158283514Sarybchik 159283514Sarybchik enp->en_filter.ef_hunt_filter_table = hftp; 160283514Sarybchik 161283514Sarybchik return (0); 162283514Sarybchik 163283514Sarybchikfail1: 164283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 165283514Sarybchik 166283514Sarybchik return (rc); 167283514Sarybchik} 168283514Sarybchik 169283514Sarybchik void 170283514Sarybchikhunt_filter_fini( 171283514Sarybchik __in efx_nic_t *enp) 172283514Sarybchik{ 173283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 174283514Sarybchik 175283514Sarybchik if (enp->en_filter.ef_hunt_filter_table != NULL) { 176283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (hunt_filter_table_t), 177283514Sarybchik enp->en_filter.ef_hunt_filter_table); 178283514Sarybchik } 179283514Sarybchik} 180283514Sarybchik 181283514Sarybchikstatic __checkReturn int 182283514Sarybchikefx_mcdi_filter_op_add( 183283514Sarybchik __in efx_nic_t *enp, 184283514Sarybchik __in efx_filter_spec_t *spec, 185283514Sarybchik __in unsigned int filter_op, 186283514Sarybchik __inout hunt_filter_handle_t *handle) 187283514Sarybchik{ 188283514Sarybchik efx_mcdi_req_t req; 189283514Sarybchik uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 190283514Sarybchik MC_CMD_FILTER_OP_OUT_LEN)]; 191283514Sarybchik uint32_t match_fields = 0; 192283514Sarybchik int rc; 193283514Sarybchik 194283514Sarybchik memset(payload, 0, sizeof (payload)); 195283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 196283514Sarybchik req.emr_in_buf = payload; 197283514Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 198283514Sarybchik req.emr_out_buf = payload; 199283514Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 200283514Sarybchik 201283514Sarybchik switch (filter_op) { 202283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REPLACE: 203283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, 204283514Sarybchik handle->hfh_lo); 205283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, 206283514Sarybchik handle->hfh_hi); 207283514Sarybchik /* Fall through */ 208283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_INSERT: 209283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: 210283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op); 211283514Sarybchik break; 212283514Sarybchik default: 213283514Sarybchik EFSYS_ASSERT(0); 214283514Sarybchik rc = EINVAL; 215283514Sarybchik goto fail1; 216283514Sarybchik } 217283514Sarybchik 218283514Sarybchik if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) { 219283514Sarybchik /* 220283514Sarybchik * The LOC_MAC_IG match flag can represent unknown unicast 221283514Sarybchik * or multicast filters - use the MAC address to distinguish 222283514Sarybchik * them. 223283514Sarybchik */ 224283514Sarybchik if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 225283514Sarybchik match_fields |= 1U << 226283514Sarybchik MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN; 227283514Sarybchik else 228283514Sarybchik match_fields |= 1U << 229283514Sarybchik MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN; 230283514Sarybchik } 231283514Sarybchik 232283514Sarybchik match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG); 233283514Sarybchik 234283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID, 235283514Sarybchik EVB_PORT_ID_ASSIGNED); 236283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS, 237283514Sarybchik match_fields); 238283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST, 239283514Sarybchik MC_CMD_FILTER_OP_IN_RX_DEST_HOST); 240283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE, 241283514Sarybchik spec->efs_dmaq_id); 242283514Sarybchik if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { 243283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT, 244283514Sarybchik spec->efs_rss_context); 245283514Sarybchik } 246283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE, 247283514Sarybchik spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? 248283514Sarybchik MC_CMD_FILTER_OP_IN_RX_MODE_RSS : 249283514Sarybchik MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE); 250283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST, 251283514Sarybchik MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT); 252283514Sarybchik 253283514Sarybchik if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { 254283514Sarybchik /* 255283514Sarybchik * NOTE: Unlike most MCDI requests, the filter fields 256283514Sarybchik * are presented in network (big endian) byte order. 257283514Sarybchik */ 258283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC), 259283514Sarybchik spec->efs_rem_mac, EFX_MAC_ADDR_LEN); 260283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC), 261283514Sarybchik spec->efs_loc_mac, EFX_MAC_ADDR_LEN); 262283514Sarybchik 263283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT, 264283514Sarybchik __CPU_TO_BE_16(spec->efs_rem_port)); 265283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT, 266283514Sarybchik __CPU_TO_BE_16(spec->efs_loc_port)); 267283514Sarybchik 268283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE, 269283514Sarybchik __CPU_TO_BE_16(spec->efs_ether_type)); 270283514Sarybchik 271283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN, 272283514Sarybchik __CPU_TO_BE_16(spec->efs_inner_vid)); 273283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN, 274283514Sarybchik __CPU_TO_BE_16(spec->efs_outer_vid)); 275283514Sarybchik 276283514Sarybchik /* IP protocol (in low byte, high byte is zero) */ 277283514Sarybchik MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO, 278283514Sarybchik spec->efs_ip_proto); 279283514Sarybchik 280283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == 281283514Sarybchik MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 282283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == 283283514Sarybchik MC_CMD_FILTER_OP_IN_DST_IP_LEN); 284283514Sarybchik 285283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP), 286283514Sarybchik &spec->efs_rem_host.eo_byte[0], 287283514Sarybchik MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 288283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP), 289283514Sarybchik &spec->efs_loc_host.eo_byte[0], 290283514Sarybchik MC_CMD_FILTER_OP_IN_DST_IP_LEN); 291283514Sarybchik } 292283514Sarybchik 293283514Sarybchik efx_mcdi_execute(enp, &req); 294283514Sarybchik 295283514Sarybchik if (req.emr_rc != 0) { 296283514Sarybchik rc = req.emr_rc; 297283514Sarybchik goto fail2; 298283514Sarybchik } 299283514Sarybchik 300283514Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 301283514Sarybchik rc = EMSGSIZE; 302283514Sarybchik goto fail3; 303283514Sarybchik } 304283514Sarybchik 305283514Sarybchik handle->hfh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO); 306283514Sarybchik handle->hfh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI); 307283514Sarybchik 308283514Sarybchik return (0); 309283514Sarybchik 310283514Sarybchikfail3: 311283514Sarybchik EFSYS_PROBE(fail3); 312283514Sarybchikfail2: 313283514Sarybchik EFSYS_PROBE(fail2); 314283514Sarybchikfail1: 315283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 316283514Sarybchik 317283514Sarybchik return (rc); 318283514Sarybchik 319283514Sarybchik} 320283514Sarybchik 321283514Sarybchikstatic __checkReturn int 322283514Sarybchikefx_mcdi_filter_op_delete( 323283514Sarybchik __in efx_nic_t *enp, 324283514Sarybchik __in unsigned int filter_op, 325283514Sarybchik __inout hunt_filter_handle_t *handle) 326283514Sarybchik{ 327283514Sarybchik efx_mcdi_req_t req; 328283514Sarybchik uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 329283514Sarybchik MC_CMD_FILTER_OP_OUT_LEN)]; 330283514Sarybchik int rc; 331283514Sarybchik 332283514Sarybchik memset(payload, 0, sizeof (payload)); 333283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 334283514Sarybchik req.emr_in_buf = payload; 335283514Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 336283514Sarybchik req.emr_out_buf = payload; 337283514Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 338283514Sarybchik 339283514Sarybchik switch (filter_op) { 340283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REMOVE: 341283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 342283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE); 343283514Sarybchik break; 344283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: 345283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 346283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); 347283514Sarybchik break; 348283514Sarybchik default: 349283514Sarybchik EFSYS_ASSERT(0); 350283514Sarybchik rc = EINVAL; 351283514Sarybchik goto fail1; 352283514Sarybchik } 353283514Sarybchik 354283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->hfh_lo); 355283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->hfh_hi); 356283514Sarybchik 357283514Sarybchik efx_mcdi_execute(enp, &req); 358283514Sarybchik 359283514Sarybchik if (req.emr_rc != 0) { 360283514Sarybchik rc = req.emr_rc; 361283514Sarybchik goto fail2; 362283514Sarybchik } 363283514Sarybchik 364283514Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 365283514Sarybchik rc = EMSGSIZE; 366283514Sarybchik goto fail3; 367283514Sarybchik } 368283514Sarybchik 369283514Sarybchik return (0); 370283514Sarybchik 371283514Sarybchikfail3: 372283514Sarybchik EFSYS_PROBE(fail3); 373283514Sarybchik 374283514Sarybchikfail2: 375283514Sarybchik EFSYS_PROBE(fail2); 376283514Sarybchikfail1: 377283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 378283514Sarybchik 379283514Sarybchik return (rc); 380283514Sarybchik} 381283514Sarybchik 382283514Sarybchikstatic __checkReturn boolean_t 383283514Sarybchikhunt_filter_equal( 384283514Sarybchik __in const efx_filter_spec_t *left, 385283514Sarybchik __in const efx_filter_spec_t *right) 386283514Sarybchik{ 387283514Sarybchik /* FIXME: Consider rx vs tx filters (look at efs_flags) */ 388283514Sarybchik if (left->efs_match_flags != right->efs_match_flags) 389283514Sarybchik return (B_FALSE); 390283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) 391283514Sarybchik return (B_FALSE); 392283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) 393283514Sarybchik return (B_FALSE); 394283514Sarybchik if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) 395283514Sarybchik return (B_FALSE); 396283514Sarybchik if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) 397283514Sarybchik return (B_FALSE); 398283514Sarybchik if (left->efs_rem_port != right->efs_rem_port) 399283514Sarybchik return (B_FALSE); 400283514Sarybchik if (left->efs_loc_port != right->efs_loc_port) 401283514Sarybchik return (B_FALSE); 402283514Sarybchik if (left->efs_inner_vid != right->efs_inner_vid) 403283514Sarybchik return (B_FALSE); 404283514Sarybchik if (left->efs_outer_vid != right->efs_outer_vid) 405283514Sarybchik return (B_FALSE); 406283514Sarybchik if (left->efs_ether_type != right->efs_ether_type) 407283514Sarybchik return (B_FALSE); 408283514Sarybchik if (left->efs_ip_proto != right->efs_ip_proto) 409283514Sarybchik return (B_FALSE); 410283514Sarybchik 411283514Sarybchik return (B_TRUE); 412283514Sarybchik 413283514Sarybchik} 414283514Sarybchik 415283514Sarybchikstatic __checkReturn boolean_t 416283514Sarybchikhunt_filter_same_dest( 417283514Sarybchik __in const efx_filter_spec_t *left, 418283514Sarybchik __in const efx_filter_spec_t *right) 419283514Sarybchik{ 420283514Sarybchik if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 421283514Sarybchik (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { 422283514Sarybchik if (left->efs_rss_context == right->efs_rss_context) 423283514Sarybchik return (B_TRUE); 424283514Sarybchik } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && 425283514Sarybchik (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { 426283514Sarybchik if (left->efs_dmaq_id == right->efs_dmaq_id) 427283514Sarybchik return (B_TRUE); 428283514Sarybchik } 429283514Sarybchik return (B_FALSE); 430283514Sarybchik} 431283514Sarybchik 432283514Sarybchikstatic __checkReturn uint32_t 433283514Sarybchikhunt_filter_hash( 434283514Sarybchik __in efx_filter_spec_t *spec) 435283514Sarybchik{ 436283514Sarybchik EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) 437283514Sarybchik == 0); 438283514Sarybchik EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % 439283514Sarybchik sizeof (uint32_t)) == 0); 440283514Sarybchik 441283514Sarybchik /* 442283514Sarybchik * As the area of the efx_filter_spec_t we need to hash is DWORD 443283514Sarybchik * aligned and an exact number of DWORDs in size we can use the 444283514Sarybchik * optimised efx_hash_dwords() rather than efx_hash_bytes() 445283514Sarybchik */ 446283514Sarybchik return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid, 447283514Sarybchik (sizeof (efx_filter_spec_t) - 448283514Sarybchik EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / 449283514Sarybchik sizeof (uint32_t), 0)); 450283514Sarybchik} 451283514Sarybchik 452283514Sarybchik/* 453283514Sarybchik * Decide whether a filter should be exclusive or else should allow 454283514Sarybchik * delivery to additional recipients. Currently we decide that 455283514Sarybchik * filters for specific local unicast MAC and IP addresses are 456283514Sarybchik * exclusive. 457283514Sarybchik */ 458283514Sarybchikstatic __checkReturn boolean_t 459283514Sarybchikhunt_filter_is_exclusive( 460283514Sarybchik __in efx_filter_spec_t *spec) 461283514Sarybchik{ 462283514Sarybchik if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && 463283514Sarybchik !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 464283514Sarybchik return (B_TRUE); 465283514Sarybchik 466283514Sarybchik if ((spec->efs_match_flags & 467283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == 468283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { 469283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && 470283514Sarybchik ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) 471283514Sarybchik return (B_TRUE); 472283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && 473283514Sarybchik (spec->efs_loc_host.eo_u8[0] != 0xff)) 474283514Sarybchik return (B_TRUE); 475283514Sarybchik } 476283514Sarybchik 477283514Sarybchik return (B_FALSE); 478283514Sarybchik} 479283514Sarybchik 480283514Sarybchik __checkReturn int 481283514Sarybchikhunt_filter_restore( 482283514Sarybchik __in efx_nic_t *enp) 483283514Sarybchik{ 484283514Sarybchik int tbl_id; 485283514Sarybchik efx_filter_spec_t *spec; 486283514Sarybchik hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table; 487283514Sarybchik boolean_t restoring; 488283514Sarybchik int state; 489283514Sarybchik int rc; 490283514Sarybchik 491283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 492283514Sarybchik 493283514Sarybchik for (tbl_id = 0; tbl_id < EFX_HUNT_FILTER_TBL_ROWS; tbl_id++) { 494283514Sarybchik 495283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 496283514Sarybchik 497283514Sarybchik spec = hunt_filter_entry_spec(hftp, tbl_id); 498283514Sarybchik if (spec == NULL) { 499283514Sarybchik restoring = B_FALSE; 500283514Sarybchik } else if (hunt_filter_entry_is_busy(hftp, tbl_id)) { 501283514Sarybchik /* Ignore busy entries. */ 502283514Sarybchik restoring = B_FALSE; 503283514Sarybchik } else { 504283514Sarybchik hunt_filter_set_entry_busy(hftp, tbl_id); 505283514Sarybchik restoring = B_TRUE; 506283514Sarybchik } 507283514Sarybchik 508283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 509283514Sarybchik 510283514Sarybchik if (restoring == B_FALSE) 511283514Sarybchik continue; 512283514Sarybchik 513283514Sarybchik if (hunt_filter_is_exclusive(spec)) { 514283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 515283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 516283514Sarybchik &hftp->hft_entry[tbl_id].hfe_handle); 517283514Sarybchik } else { 518283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 519283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 520283514Sarybchik &hftp->hft_entry[tbl_id].hfe_handle); 521283514Sarybchik } 522283514Sarybchik 523283514Sarybchik if (rc != 0) 524283514Sarybchik goto fail1; 525283514Sarybchik 526283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 527283514Sarybchik 528283514Sarybchik hunt_filter_set_entry_not_busy(hftp, tbl_id); 529283514Sarybchik 530283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 531283514Sarybchik } 532283514Sarybchik 533283514Sarybchik return (0); 534283514Sarybchik 535283514Sarybchikfail1: 536283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 537283514Sarybchik 538283514Sarybchik return (rc); 539283514Sarybchik} 540283514Sarybchik 541283514Sarybchik/* 542283514Sarybchik * An arbitrary search limit for the software hash table. As per the linux net 543283514Sarybchik * driver. 544283514Sarybchik */ 545283514Sarybchik#define EFX_HUNT_FILTER_SEARCH_LIMIT 200 546283514Sarybchik 547283514Sarybchikstatic __checkReturn int 548283514Sarybchikhunt_filter_add_internal( 549283514Sarybchik __in efx_nic_t *enp, 550283514Sarybchik __inout efx_filter_spec_t *spec, 551283514Sarybchik __in boolean_t may_replace, 552283514Sarybchik __out_opt uint32_t *filter_id) 553283514Sarybchik{ 554283514Sarybchik int rc; 555283514Sarybchik hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table; 556283514Sarybchik efx_filter_spec_t *saved_spec; 557283514Sarybchik uint32_t hash; 558283514Sarybchik unsigned int depth; 559283514Sarybchik int ins_index; 560283514Sarybchik boolean_t replacing = B_FALSE; 561283514Sarybchik unsigned int i; 562283514Sarybchik int state; 563283514Sarybchik boolean_t locked = B_FALSE; 564283514Sarybchik 565283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 566283514Sarybchik 567283514Sarybchik#if EFSYS_OPT_RX_SCALE 568283514Sarybchik spec->efs_rss_context = enp->en_rss_context; 569283514Sarybchik#endif 570283514Sarybchik 571283514Sarybchik hash = hunt_filter_hash(spec); 572283514Sarybchik 573283514Sarybchik /* 574283514Sarybchik * FIXME: Add support for inserting filters of different priorities 575283514Sarybchik * and removing lower priority multicast filters (bug 42378) 576283514Sarybchik */ 577283514Sarybchik 578283514Sarybchik /* 579283514Sarybchik * Find any existing filters with the same match tuple or 580283514Sarybchik * else a free slot to insert at. If any of them are busy, 581283514Sarybchik * we have to wait and retry. 582283514Sarybchik */ 583283514Sarybchik for (;;) { 584283514Sarybchik ins_index = -1; 585283514Sarybchik depth = 1; 586283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 587283514Sarybchik locked = B_TRUE; 588283514Sarybchik 589283514Sarybchik for (;;) { 590283514Sarybchik i = (hash + depth) & (EFX_HUNT_FILTER_TBL_ROWS - 1); 591283514Sarybchik saved_spec = hunt_filter_entry_spec(hftp, i); 592283514Sarybchik 593283514Sarybchik if (!saved_spec) { 594283514Sarybchik if (ins_index < 0) { 595283514Sarybchik ins_index = i; 596283514Sarybchik } 597283514Sarybchik } else if (hunt_filter_equal(spec, saved_spec)) { 598283514Sarybchik if (hunt_filter_entry_is_busy(hftp, i)) 599283514Sarybchik break; 600283514Sarybchik if (saved_spec->efs_priority 601283514Sarybchik == EFX_FILTER_PRI_AUTO) { 602283514Sarybchik ins_index = i; 603283514Sarybchik goto found; 604283514Sarybchik } else if (hunt_filter_is_exclusive(spec)) { 605283514Sarybchik if (may_replace) { 606283514Sarybchik ins_index = i; 607283514Sarybchik goto found; 608283514Sarybchik } else { 609283514Sarybchik rc = EEXIST; 610283514Sarybchik goto fail1; 611283514Sarybchik } 612283514Sarybchik } 613283514Sarybchik 614283514Sarybchik /* Leave existing */ 615283514Sarybchik } 616283514Sarybchik 617283514Sarybchik /* 618283514Sarybchik * Once we reach the maximum search depth, use 619283514Sarybchik * the first suitable slot or return EBUSY if 620283514Sarybchik * there was none. 621283514Sarybchik */ 622283514Sarybchik if (depth == EFX_HUNT_FILTER_SEARCH_LIMIT) { 623283514Sarybchik if (ins_index < 0) { 624283514Sarybchik rc = EBUSY; 625283514Sarybchik goto fail2; 626283514Sarybchik } 627283514Sarybchik goto found; 628283514Sarybchik } 629283514Sarybchik depth++; 630283514Sarybchik } 631283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 632283514Sarybchik locked = B_FALSE; 633283514Sarybchik } 634283514Sarybchik 635283514Sarybchikfound: 636283514Sarybchik /* 637283514Sarybchik * Create a software table entry if necessary, and mark it 638283514Sarybchik * busy. We might yet fail to insert, but any attempt to 639283514Sarybchik * insert a conflicting filter while we're waiting for the 640283514Sarybchik * firmware must find the busy entry. 641283514Sarybchik */ 642283514Sarybchik saved_spec = hunt_filter_entry_spec(hftp, ins_index); 643283514Sarybchik if (saved_spec) { 644283514Sarybchik if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { 645283514Sarybchik /* This is a filter we are refreshing */ 646283514Sarybchik hunt_filter_set_entry_not_auto_old(hftp, ins_index); 647283514Sarybchik goto out_unlock; 648283514Sarybchik 649283514Sarybchik } 650283514Sarybchik replacing = B_TRUE; 651283514Sarybchik } else { 652283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); 653283514Sarybchik if (!saved_spec) { 654283514Sarybchik rc = ENOMEM; 655283514Sarybchik goto fail3; 656283514Sarybchik } 657283514Sarybchik *saved_spec = *spec; 658283514Sarybchik hunt_filter_set_entry(hftp, ins_index, saved_spec); 659283514Sarybchik } 660283514Sarybchik hunt_filter_set_entry_busy(hftp, ins_index); 661283514Sarybchik 662283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 663283514Sarybchik locked = B_FALSE; 664283514Sarybchik 665283514Sarybchik /* 666283514Sarybchik * On replacing the filter handle may change after after a successful 667283514Sarybchik * replace operation. 668283514Sarybchik */ 669283514Sarybchik if (replacing) { 670283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 671283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REPLACE, 672283514Sarybchik &hftp->hft_entry[ins_index].hfe_handle); 673283514Sarybchik } else if (hunt_filter_is_exclusive(spec)) { 674283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 675283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 676283514Sarybchik &hftp->hft_entry[ins_index].hfe_handle); 677283514Sarybchik } else { 678283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 679283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 680283514Sarybchik &hftp->hft_entry[ins_index].hfe_handle); 681283514Sarybchik } 682283514Sarybchik 683283514Sarybchik if (rc != 0) 684283514Sarybchik goto fail4; 685283514Sarybchik 686283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 687283514Sarybchik locked = B_TRUE; 688283514Sarybchik 689283514Sarybchik if (replacing) { 690283514Sarybchik /* Update the fields that may differ */ 691283514Sarybchik saved_spec->efs_priority = spec->efs_priority; 692283514Sarybchik saved_spec->efs_flags = spec->efs_flags; 693283514Sarybchik saved_spec->efs_rss_context = spec->efs_rss_context; 694283514Sarybchik saved_spec->efs_dmaq_id = spec->efs_dmaq_id; 695283514Sarybchik } 696283514Sarybchik 697283514Sarybchik hunt_filter_set_entry_not_busy(hftp, ins_index); 698283514Sarybchik 699283514Sarybchikout_unlock: 700283514Sarybchik 701283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 702283514Sarybchik locked = B_FALSE; 703283514Sarybchik 704283514Sarybchik if (filter_id) 705283514Sarybchik *filter_id = ins_index; 706283514Sarybchik 707283514Sarybchik return (0); 708283514Sarybchik 709283514Sarybchikfail4: 710283514Sarybchik EFSYS_PROBE(fail4); 711283514Sarybchik 712283514Sarybchik if (!replacing) { 713283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); 714283514Sarybchik saved_spec = NULL; 715283514Sarybchik } 716283514Sarybchik hunt_filter_set_entry_not_busy(hftp, ins_index); 717283514Sarybchik hunt_filter_set_entry(hftp, ins_index, NULL); 718283514Sarybchik 719283514Sarybchikfail3: 720283514Sarybchik EFSYS_PROBE(fail3); 721283514Sarybchik 722283514Sarybchikfail2: 723283514Sarybchik EFSYS_PROBE(fail2); 724283514Sarybchik 725283514Sarybchikfail1: 726283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 727283514Sarybchik 728283514Sarybchik if (locked) 729283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 730283514Sarybchik 731283514Sarybchik return (rc); 732283514Sarybchik} 733283514Sarybchik 734283514Sarybchik __checkReturn int 735283514Sarybchikhunt_filter_add( 736283514Sarybchik __in efx_nic_t *enp, 737283514Sarybchik __inout efx_filter_spec_t *spec, 738283514Sarybchik __in boolean_t may_replace) 739283514Sarybchik{ 740283514Sarybchik int rc; 741283514Sarybchik 742283514Sarybchik rc = hunt_filter_add_internal(enp, spec, may_replace, NULL); 743283514Sarybchik if (rc != 0) 744283514Sarybchik goto fail1; 745283514Sarybchik 746283514Sarybchik return (0); 747283514Sarybchik 748283514Sarybchikfail1: 749283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 750283514Sarybchik 751283514Sarybchik return (rc); 752283514Sarybchik} 753283514Sarybchik 754283514Sarybchik 755283514Sarybchikstatic __checkReturn int 756283514Sarybchikhunt_filter_delete_internal( 757283514Sarybchik __in efx_nic_t *enp, 758283514Sarybchik __in uint32_t filter_id) 759283514Sarybchik{ 760283514Sarybchik int rc; 761283514Sarybchik hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table; 762283514Sarybchik efx_filter_spec_t *spec; 763283514Sarybchik int state; 764283514Sarybchik uint32_t filter_idx = filter_id % EFX_HUNT_FILTER_TBL_ROWS; 765283514Sarybchik 766283514Sarybchik /* 767283514Sarybchik * Find the software table entry and mark it busy. Don't 768283514Sarybchik * remove it yet; any attempt to update while we're waiting 769283514Sarybchik * for the firmware must find the busy entry. 770283514Sarybchik * 771283514Sarybchik * FIXME: What if the busy flag is never cleared? 772283514Sarybchik */ 773283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 774283514Sarybchik while (hunt_filter_entry_is_busy(table, filter_idx)) { 775283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 776283514Sarybchik EFSYS_SPIN(1); 777283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 778283514Sarybchik } 779283514Sarybchik if ((spec = hunt_filter_entry_spec(table, filter_idx)) != NULL) { 780283514Sarybchik hunt_filter_set_entry_busy(table, filter_idx); 781283514Sarybchik } 782283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 783283514Sarybchik 784283514Sarybchik if (spec == NULL) { 785283514Sarybchik rc = ENOENT; 786283514Sarybchik goto fail1; 787283514Sarybchik } 788283514Sarybchik 789283514Sarybchik /* 790283514Sarybchik * Try to remove the hardware filter. This may fail if the MC has 791283514Sarybchik * rebooted (which frees all hardware filter resources). 792283514Sarybchik */ 793283514Sarybchik if (hunt_filter_is_exclusive(spec)) { 794283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 795283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE, 796283514Sarybchik &table->hft_entry[filter_idx].hfe_handle); 797283514Sarybchik } else { 798283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 799283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, 800283514Sarybchik &table->hft_entry[filter_idx].hfe_handle); 801283514Sarybchik } 802283514Sarybchik 803283514Sarybchik /* Free the software table entry */ 804283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 805283514Sarybchik hunt_filter_set_entry_not_busy(table, filter_idx); 806283514Sarybchik hunt_filter_set_entry(table, filter_idx, NULL); 807283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 808283514Sarybchik 809283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 810283514Sarybchik 811283514Sarybchik /* Check result of hardware filter removal */ 812283514Sarybchik if (rc != 0) 813283514Sarybchik goto fail2; 814283514Sarybchik 815283514Sarybchik return (0); 816283514Sarybchik 817283514Sarybchikfail2: 818283514Sarybchik EFSYS_PROBE(fail2); 819283514Sarybchik 820283514Sarybchikfail1: 821283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 822283514Sarybchik 823283514Sarybchik return (rc); 824283514Sarybchik} 825283514Sarybchik 826283514Sarybchik __checkReturn int 827283514Sarybchikhunt_filter_delete( 828283514Sarybchik __in efx_nic_t *enp, 829283514Sarybchik __inout efx_filter_spec_t *spec) 830283514Sarybchik{ 831283514Sarybchik int rc; 832283514Sarybchik hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table; 833283514Sarybchik efx_filter_spec_t *saved_spec; 834283514Sarybchik unsigned int hash; 835283514Sarybchik unsigned int depth; 836283514Sarybchik unsigned int i; 837283514Sarybchik int state; 838283514Sarybchik boolean_t locked = B_FALSE; 839283514Sarybchik 840283514Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON); 841283514Sarybchik 842283514Sarybchik hash = hunt_filter_hash(spec); 843283514Sarybchik 844283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 845283514Sarybchik locked = B_TRUE; 846283514Sarybchik 847283514Sarybchik depth = 1; 848283514Sarybchik for (;;) { 849283514Sarybchik i = (hash + depth) & (EFX_HUNT_FILTER_TBL_ROWS - 1); 850283514Sarybchik saved_spec = hunt_filter_entry_spec(table, i); 851283514Sarybchik if (saved_spec && hunt_filter_equal(spec, saved_spec) && 852283514Sarybchik hunt_filter_same_dest(spec, saved_spec)) { 853283514Sarybchik break; 854283514Sarybchik } 855283514Sarybchik if (depth == EFX_HUNT_FILTER_SEARCH_LIMIT) { 856283514Sarybchik rc = ENOENT; 857283514Sarybchik goto fail1; 858283514Sarybchik } 859283514Sarybchik depth++; 860283514Sarybchik } 861283514Sarybchik 862283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 863283514Sarybchik locked = B_FALSE; 864283514Sarybchik 865283514Sarybchik rc = hunt_filter_delete_internal(enp, i); 866283514Sarybchik if (rc != 0) 867283514Sarybchik goto fail2; 868283514Sarybchik 869283514Sarybchik return (0); 870283514Sarybchik 871283514Sarybchikfail2: 872283514Sarybchik EFSYS_PROBE(fail2); 873283514Sarybchik 874283514Sarybchikfail1: 875283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 876283514Sarybchik 877283514Sarybchik if (locked) 878283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 879283514Sarybchik 880283514Sarybchik return (rc); 881283514Sarybchik} 882283514Sarybchik 883283514Sarybchikstatic __checkReturn int 884283514Sarybchikefx_mcdi_get_parser_disp_info( 885283514Sarybchik __in efx_nic_t *enp, 886283514Sarybchik __out uint32_t *list, 887283514Sarybchik __out size_t *length) 888283514Sarybchik{ 889283514Sarybchik efx_mcdi_req_t req; 890283514Sarybchik uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, 891283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)]; 892283514Sarybchik int rc; 893283514Sarybchik uint32_t i; 894283514Sarybchik boolean_t support_unknown_ucast = B_FALSE; 895283514Sarybchik boolean_t support_unknown_mcast = B_FALSE; 896283514Sarybchik 897283514Sarybchik (void) memset(payload, 0, sizeof (payload)); 898283514Sarybchik req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; 899283514Sarybchik req.emr_in_buf = payload; 900283514Sarybchik req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; 901283514Sarybchik req.emr_out_buf = payload; 902283514Sarybchik req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; 903283514Sarybchik 904283514Sarybchik MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, 905283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); 906283514Sarybchik 907283514Sarybchik efx_mcdi_execute(enp, &req); 908283514Sarybchik 909283514Sarybchik if (req.emr_rc != 0) { 910283514Sarybchik rc = req.emr_rc; 911283514Sarybchik goto fail1; 912283514Sarybchik } 913283514Sarybchik 914283514Sarybchik *length = MCDI_OUT_DWORD(req, 915283514Sarybchik GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); 916283514Sarybchik 917283514Sarybchik if (req.emr_out_length_used < 918283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) { 919283514Sarybchik rc = EMSGSIZE; 920283514Sarybchik goto fail2; 921283514Sarybchik } 922283514Sarybchik 923283514Sarybchik memcpy(list, 924283514Sarybchik MCDI_OUT2(req, 925283514Sarybchik uint32_t, 926283514Sarybchik GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), 927283514Sarybchik (*length) * sizeof (uint32_t)); 928283514Sarybchik EFX_STATIC_ASSERT(sizeof (uint32_t) == 929283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); 930283514Sarybchik 931283514Sarybchik /* 932283514Sarybchik * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change 933283514Sarybchik * the lower priority one to LOC_MAC_IG. 934283514Sarybchik */ 935283514Sarybchik for (i = 0; i < *length; i++) { 936283514Sarybchik if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) { 937283514Sarybchik list[i] &= 938283514Sarybchik (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN); 939283514Sarybchik support_unknown_ucast = B_TRUE; 940283514Sarybchik } 941283514Sarybchik if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) { 942283514Sarybchik list[i] &= 943283514Sarybchik (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN); 944283514Sarybchik support_unknown_mcast = B_TRUE; 945283514Sarybchik } 946283514Sarybchik 947283514Sarybchik if (support_unknown_ucast && support_unknown_mcast) { 948283514Sarybchik list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG; 949283514Sarybchik break; 950283514Sarybchik } 951283514Sarybchik } 952283514Sarybchik 953283514Sarybchik return (0); 954283514Sarybchik 955283514Sarybchikfail2: 956283514Sarybchik EFSYS_PROBE(fail2); 957283514Sarybchikfail1: 958283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 959283514Sarybchik 960283514Sarybchik return (rc); 961283514Sarybchik} 962283514Sarybchik 963283514Sarybchik __checkReturn int 964283514Sarybchikhunt_filter_supported_filters( 965283514Sarybchik __in efx_nic_t *enp, 966283514Sarybchik __out uint32_t *list, 967283514Sarybchik __out size_t *length) 968283514Sarybchik{ 969283514Sarybchik int rc; 970283514Sarybchik 971283514Sarybchik if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length) != 0)) 972283514Sarybchik goto fail1; 973283514Sarybchik 974283514Sarybchik return (0); 975283514Sarybchik 976283514Sarybchikfail1: 977283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 978283514Sarybchik 979283514Sarybchik return (rc); 980283514Sarybchik} 981283514Sarybchik 982283514Sarybchikstatic __checkReturn int 983283514Sarybchikhunt_filter_unicast_refresh( 984283514Sarybchik __in efx_nic_t *enp, 985283514Sarybchik __in_ecount(6) uint8_t const *addr, 986283514Sarybchik __in boolean_t all_unicst, 987283514Sarybchik __in efx_filter_flag_t filter_flags) 988283514Sarybchik{ 989283514Sarybchik hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table; 990283514Sarybchik efx_filter_spec_t spec; 991283514Sarybchik int rc; 992283514Sarybchik 993283514Sarybchik if (all_unicst == B_TRUE) 994283514Sarybchik goto use_uc_def; 995283514Sarybchik 996283514Sarybchik /* Insert the filter for the local station address */ 997283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 998283514Sarybchik filter_flags, 999283514Sarybchik hftp->hft_default_rxq); 1000283514Sarybchik efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr); 1001283514Sarybchik 1002283514Sarybchik rc = hunt_filter_add_internal(enp, &spec, B_TRUE, 1003283514Sarybchik &hftp->hft_unicst_filter_index); 1004283514Sarybchik if (rc != 0) { 1005283514Sarybchik /* 1006283514Sarybchik * Fall back to an unknown filter. We may be able to subscribe 1007283514Sarybchik * to it even if we couldn't insert the unicast filter. 1008283514Sarybchik */ 1009283514Sarybchik goto use_uc_def; 1010283514Sarybchik } 1011283514Sarybchik hftp->hft_unicst_filter_set = B_TRUE; 1012283514Sarybchik 1013283514Sarybchik return (0); 1014283514Sarybchik 1015283514Sarybchikuse_uc_def: 1016283514Sarybchik /* Insert the unknown unicast filter */ 1017283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1018283514Sarybchik filter_flags, 1019283514Sarybchik hftp->hft_default_rxq); 1020283514Sarybchik efx_filter_spec_set_uc_def(&spec); 1021283514Sarybchik rc = hunt_filter_add_internal(enp, &spec, B_TRUE, 1022283514Sarybchik &hftp->hft_unicst_filter_index); 1023283514Sarybchik if (rc != 0) 1024283514Sarybchik goto fail1; 1025283514Sarybchik 1026283514Sarybchik hftp->hft_unicst_filter_set = B_TRUE; 1027283514Sarybchik 1028283514Sarybchik return (0); 1029283514Sarybchik 1030283514Sarybchikfail1: 1031283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 1032283514Sarybchik 1033283514Sarybchik if (hftp->hft_unicst_filter_set != B_FALSE) { 1034283514Sarybchik (void) hunt_filter_delete_internal(enp, 1035283514Sarybchik hftp->hft_unicst_filter_index); 1036283514Sarybchik 1037283514Sarybchik hftp->hft_unicst_filter_set = B_FALSE; 1038283514Sarybchik } 1039283514Sarybchik 1040283514Sarybchik return (rc); 1041283514Sarybchik} 1042283514Sarybchik 1043283514Sarybchikstatic __checkReturn int 1044283514Sarybchikhunt_filter_multicast_refresh( 1045283514Sarybchik __in efx_nic_t *enp, 1046283514Sarybchik __in boolean_t mulcst, 1047283514Sarybchik __in boolean_t all_mulcst, 1048283514Sarybchik __in boolean_t brdcst, 1049283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1050283514Sarybchik __in int count, 1051283514Sarybchik __in efx_filter_flag_t filter_flags) 1052283514Sarybchik{ 1053283514Sarybchik hunt_filter_table_t *hftp = enp->en_filter.ef_hunt_filter_table; 1054283514Sarybchik efx_filter_spec_t spec; 1055283514Sarybchik uint8_t addr[6]; 1056283514Sarybchik unsigned i; 1057283514Sarybchik int rc; 1058283514Sarybchik 1059283514Sarybchik if (all_mulcst == B_TRUE) 1060283514Sarybchik goto use_mc_def; 1061283514Sarybchik 1062283514Sarybchik if (mulcst == B_FALSE) 1063283514Sarybchik count = 0; 1064283514Sarybchik 1065283514Sarybchik if (count + (brdcst ? 1 : 0) > 1066283514Sarybchik EFX_ARRAY_SIZE(hftp->hft_mulcst_filter_indexes)) { 1067283514Sarybchik /* Too many MAC addresses; use unknown multicast filter */ 1068283514Sarybchik goto use_mc_def; 1069283514Sarybchik } 1070283514Sarybchik 1071283514Sarybchik /* Insert/renew multicast address list filters */ 1072283514Sarybchik hftp->hft_mulcst_filter_count = count; 1073283514Sarybchik for (i = 0; i < hftp->hft_mulcst_filter_count; i++) { 1074283514Sarybchik efx_filter_spec_init_rx(&spec, 1075283514Sarybchik EFX_FILTER_PRI_AUTO, 1076283514Sarybchik filter_flags, 1077283514Sarybchik hftp->hft_default_rxq); 1078283514Sarybchik 1079283514Sarybchik efx_filter_spec_set_eth_local(&spec, 1080283514Sarybchik EFX_FILTER_SPEC_VID_UNSPEC, 1081283514Sarybchik &addrs[i * EFX_MAC_ADDR_LEN]); 1082283514Sarybchik 1083283514Sarybchik rc = hunt_filter_add_internal(enp, &spec, B_TRUE, 1084283514Sarybchik &hftp->hft_mulcst_filter_indexes[i]); 1085283514Sarybchik if (rc != 0) { 1086283514Sarybchik /* Rollback, then use unknown multicast filter */ 1087283514Sarybchik goto rollback; 1088283514Sarybchik } 1089283514Sarybchik } 1090283514Sarybchik 1091283514Sarybchik if (brdcst == B_TRUE) { 1092283514Sarybchik /* Insert/renew broadcast address filter */ 1093283514Sarybchik hftp->hft_mulcst_filter_count++; 1094283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1095283514Sarybchik filter_flags, 1096283514Sarybchik hftp->hft_default_rxq); 1097283514Sarybchik 1098283514Sarybchik EFX_MAC_BROADCAST_ADDR_SET(addr); 1099283514Sarybchik efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, 1100283514Sarybchik addr); 1101283514Sarybchik 1102283514Sarybchik rc = hunt_filter_add_internal(enp, &spec, B_TRUE, 1103283514Sarybchik &hftp->hft_mulcst_filter_indexes[ 1104283514Sarybchik hftp->hft_mulcst_filter_count - 1]); 1105283514Sarybchik if (rc != 0) { 1106283514Sarybchik /* Rollback, then use unknown multicast filter */ 1107283514Sarybchik goto rollback; 1108283514Sarybchik } 1109283514Sarybchik } 1110283514Sarybchik 1111283514Sarybchik return (0); 1112283514Sarybchik 1113283514Sarybchikrollback: 1114283514Sarybchik /* 1115283514Sarybchik * Rollback by removing any filters we have inserted 1116283514Sarybchik * before inserting the unknown multicast filter. 1117283514Sarybchik */ 1118283514Sarybchik while (i--) { 1119283514Sarybchik (void) hunt_filter_delete_internal(enp, 1120283514Sarybchik hftp->hft_mulcst_filter_indexes[i]); 1121283514Sarybchik } 1122283514Sarybchik hftp->hft_mulcst_filter_count = 0; 1123283514Sarybchik 1124283514Sarybchikuse_mc_def: 1125283514Sarybchik /* Insert the unknown multicast filter */ 1126283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1127283514Sarybchik filter_flags, 1128283514Sarybchik hftp->hft_default_rxq); 1129283514Sarybchik efx_filter_spec_set_mc_def(&spec); 1130283514Sarybchik 1131283514Sarybchik rc = hunt_filter_add_internal(enp, &spec, B_TRUE, 1132283514Sarybchik &hftp->hft_mulcst_filter_indexes[0]); 1133283514Sarybchik if (rc != 0) 1134283514Sarybchik goto fail1; 1135283514Sarybchik 1136283514Sarybchik hftp->hft_mulcst_filter_count = 1; 1137283514Sarybchik 1138283514Sarybchik /* 1139283514Sarybchik * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. 1140283514Sarybchik */ 1141283514Sarybchik 1142283514Sarybchik return (0); 1143283514Sarybchik 1144283514Sarybchikfail1: 1145283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 1146283514Sarybchik 1147283514Sarybchik return (rc); 1148283514Sarybchik 1149283514Sarybchik} 1150283514Sarybchik 1151283514Sarybchik 1152283514Sarybchikstatic __checkReturn int 1153283514Sarybchikhunt_filter_get_workarounds( 1154283514Sarybchik __in efx_nic_t *enp) 1155283514Sarybchik{ 1156283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1157283514Sarybchik uint32_t implemented = 0; 1158283514Sarybchik uint32_t enabled = 0; 1159283514Sarybchik int rc; 1160283514Sarybchik 1161283514Sarybchik rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); 1162283514Sarybchik if (rc == 0) { 1163283514Sarybchik /* Check if chained multicast filter support is enabled */ 1164283514Sarybchik if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) 1165283514Sarybchik encp->enc_bug26807_workaround = B_TRUE; 1166283514Sarybchik else 1167283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1168283514Sarybchik } else if (rc == ENOTSUP) { 1169283514Sarybchik /* 1170283514Sarybchik * Firmware is too old to support GET_WORKAROUNDS, and support 1171283514Sarybchik * for this workaround was implemented later. 1172283514Sarybchik */ 1173283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1174283514Sarybchik } else { 1175283514Sarybchik goto fail1; 1176283514Sarybchik } 1177283514Sarybchik 1178283514Sarybchik return (0); 1179283514Sarybchik 1180283514Sarybchikfail1: 1181283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 1182283514Sarybchik 1183283514Sarybchik return (rc); 1184283514Sarybchik 1185283514Sarybchik} 1186283514Sarybchik 1187283514Sarybchik 1188283514Sarybchik/* 1189283514Sarybchik * Reconfigure all filters. 1190283514Sarybchik * If all_unicst and/or all mulcst filters cannot be applied then 1191283514Sarybchik * return ENOTSUP (Note the filters for the specified addresses are 1192283514Sarybchik * still applied in this case). 1193283514Sarybchik */ 1194283514Sarybchik __checkReturn int 1195283514Sarybchikhunt_filter_reconfigure( 1196283514Sarybchik __in efx_nic_t *enp, 1197283514Sarybchik __in_ecount(6) uint8_t const *mac_addr, 1198283514Sarybchik __in boolean_t all_unicst, 1199283514Sarybchik __in boolean_t mulcst, 1200283514Sarybchik __in boolean_t all_mulcst, 1201283514Sarybchik __in boolean_t brdcst, 1202283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1203283514Sarybchik __in int count) 1204283514Sarybchik{ 1205283514Sarybchik hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table; 1206283514Sarybchik efx_filter_flag_t filter_flags; 1207283514Sarybchik unsigned i; 1208283514Sarybchik int all_unicst_rc; 1209283514Sarybchik int all_mulcst_rc; 1210283514Sarybchik int rc; 1211283514Sarybchik 1212283514Sarybchik if (table->hft_default_rxq == NULL) { 1213283514Sarybchik /* 1214283514Sarybchik * Filters direct traffic to the default RXQ, and so cannot be 1215283514Sarybchik * inserted until it is available. Any currently configured 1216283514Sarybchik * filters must be removed (ignore errors in case the MC 1217283514Sarybchik * has rebooted, which removes hardware filters). 1218283514Sarybchik */ 1219283514Sarybchik if (table->hft_unicst_filter_set != B_FALSE) { 1220283514Sarybchik (void) hunt_filter_delete_internal(enp, 1221283514Sarybchik table->hft_unicst_filter_index); 1222283514Sarybchik table->hft_unicst_filter_set = B_FALSE; 1223283514Sarybchik } 1224283514Sarybchik for (i = 0; i < table->hft_mulcst_filter_count; i++) { 1225283514Sarybchik (void) hunt_filter_delete_internal(enp, 1226283514Sarybchik table->hft_mulcst_filter_indexes[i]); 1227283514Sarybchik } 1228283514Sarybchik table->hft_mulcst_filter_count = 0; 1229283514Sarybchik 1230283514Sarybchik return (0); 1231283514Sarybchik } 1232283514Sarybchik 1233283514Sarybchik if (table->hft_using_rss) 1234283514Sarybchik filter_flags = EFX_FILTER_FLAG_RX_RSS; 1235283514Sarybchik else 1236283514Sarybchik filter_flags = 0; 1237283514Sarybchik 1238283514Sarybchik /* Mark old filters which may need to be removed */ 1239283514Sarybchik if (table->hft_unicst_filter_set != B_FALSE) { 1240283514Sarybchik hunt_filter_set_entry_auto_old(table, 1241283514Sarybchik table->hft_unicst_filter_index); 1242283514Sarybchik } 1243283514Sarybchik for (i = 0; i < table->hft_mulcst_filter_count; i++) { 1244283514Sarybchik hunt_filter_set_entry_auto_old(table, 1245283514Sarybchik table->hft_mulcst_filter_indexes[i]); 1246283514Sarybchik } 1247283514Sarybchik 1248283514Sarybchik /* Insert or renew unicast filters */ 1249283514Sarybchik if ((all_unicst_rc = hunt_filter_unicast_refresh(enp, mac_addr, 1250283514Sarybchik all_unicst, filter_flags)) != 0) { 1251283514Sarybchik if (all_unicst == B_FALSE) { 1252283514Sarybchik rc = all_unicst_rc; 1253283514Sarybchik goto fail1; 1254283514Sarybchik } 1255283514Sarybchik /* Retry without all_unicast flag */ 1256283514Sarybchik rc = hunt_filter_unicast_refresh(enp, mac_addr, 1257283514Sarybchik B_FALSE, filter_flags); 1258283514Sarybchik if (rc != 0) 1259283514Sarybchik goto fail2; 1260283514Sarybchik } 1261283514Sarybchik 1262283514Sarybchik /* 1263283514Sarybchik * WORKAROUND_BUG26807 controls firmware support for chained multicast 1264283514Sarybchik * filters, and can only be enabled or disabled when the hardware filter 1265283514Sarybchik * table is empty. 1266283514Sarybchik * 1267283514Sarybchik * Firmware will reset (FLR) functions which have inserted filters in 1268283514Sarybchik * the hardware filter table when the workaround is enabled/disabled. 1269283514Sarybchik * Functions without any hardware filters are not reset. 1270283514Sarybchik * 1271283514Sarybchik * Re-check if the workaround is enabled after adding unicast hardware 1272283514Sarybchik * filters. This ensures that encp->enc_workaround_bug26807 matches the 1273283514Sarybchik * firmware state, and that later changes to enable/disable the 1274283514Sarybchik * workaround will result in this function seeing a reset (FLR). 1275283514Sarybchik */ 1276283514Sarybchik if ((rc = hunt_filter_get_workarounds(enp)) != 0) 1277283514Sarybchik goto fail3; 1278283514Sarybchik 1279283514Sarybchik /* Insert or renew multicast filters */ 1280283514Sarybchik if ((all_mulcst_rc = hunt_filter_multicast_refresh(enp, mulcst, 1281283514Sarybchik all_mulcst, brdcst, 1282283514Sarybchik addrs, count, filter_flags)) != 0) { 1283283514Sarybchik if (all_mulcst == B_FALSE) { 1284283514Sarybchik rc = all_mulcst_rc; 1285283514Sarybchik goto fail4; 1286283514Sarybchik } 1287283514Sarybchik /* Retry without all_mulcast flag */ 1288283514Sarybchik rc = hunt_filter_multicast_refresh(enp, mulcst, 1289283514Sarybchik B_FALSE, brdcst, 1290283514Sarybchik addrs, count, filter_flags); 1291283514Sarybchik if (rc != 0) 1292283514Sarybchik goto fail5; 1293283514Sarybchik } 1294283514Sarybchik 1295283514Sarybchik /* Remove old filters which were not renewed */ 1296283514Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->hft_entry); i++) { 1297283514Sarybchik if (hunt_filter_entry_is_auto_old(table, i)) { 1298283514Sarybchik (void) hunt_filter_delete_internal(enp, i); 1299283514Sarybchik } 1300283514Sarybchik } 1301283514Sarybchik 1302283514Sarybchik /* report if any optional flags were rejected */ 1303283514Sarybchik if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || 1304283514Sarybchik ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { 1305283514Sarybchik rc = ENOTSUP; 1306283514Sarybchik } 1307283514Sarybchik 1308283514Sarybchik return (rc); 1309283514Sarybchik 1310283514Sarybchikfail5: 1311283514Sarybchik EFSYS_PROBE(fail5); 1312283514Sarybchikfail4: 1313283514Sarybchik EFSYS_PROBE(fail4); 1314283514Sarybchikfail3: 1315283514Sarybchik EFSYS_PROBE(fail3); 1316283514Sarybchikfail2: 1317283514Sarybchik EFSYS_PROBE(fail2); 1318283514Sarybchikfail1: 1319283514Sarybchik EFSYS_PROBE1(fail1, int, rc); 1320283514Sarybchik 1321283514Sarybchik /* Clear auto old flags */ 1322283514Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->hft_entry); i++) { 1323283514Sarybchik if (hunt_filter_entry_is_auto_old(table, i)) { 1324283514Sarybchik hunt_filter_set_entry_not_auto_old(table, i); 1325283514Sarybchik } 1326283514Sarybchik } 1327283514Sarybchik 1328283514Sarybchik return (rc); 1329283514Sarybchik} 1330283514Sarybchik 1331283514Sarybchik void 1332283514Sarybchikhunt_filter_get_default_rxq( 1333283514Sarybchik __in efx_nic_t *enp, 1334283514Sarybchik __out efx_rxq_t **erpp, 1335283514Sarybchik __out boolean_t *using_rss) 1336283514Sarybchik{ 1337283514Sarybchik hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table; 1338283514Sarybchik 1339283514Sarybchik *erpp = table->hft_default_rxq; 1340283514Sarybchik *using_rss = table->hft_using_rss; 1341283514Sarybchik} 1342283514Sarybchik 1343283514Sarybchik 1344283514Sarybchik void 1345283514Sarybchikhunt_filter_default_rxq_set( 1346283514Sarybchik __in efx_nic_t *enp, 1347283514Sarybchik __in efx_rxq_t *erp, 1348283514Sarybchik __in boolean_t using_rss) 1349283514Sarybchik{ 1350283514Sarybchik hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table; 1351283514Sarybchik 1352283514Sarybchik#if EFSYS_OPT_RX_SCALE 1353283514Sarybchik EFSYS_ASSERT((using_rss == B_FALSE) || 1354283514Sarybchik (enp->en_rss_context != HUNTINGTON_RSS_CONTEXT_INVALID)); 1355283514Sarybchik table->hft_using_rss = using_rss; 1356283514Sarybchik#else 1357283514Sarybchik EFSYS_ASSERT(using_rss == B_FALSE); 1358283514Sarybchik table->hft_using_rss = B_FALSE; 1359283514Sarybchik#endif 1360283514Sarybchik table->hft_default_rxq = erp; 1361283514Sarybchik} 1362283514Sarybchik 1363283514Sarybchik void 1364283514Sarybchikhunt_filter_default_rxq_clear( 1365283514Sarybchik __in efx_nic_t *enp) 1366283514Sarybchik{ 1367283514Sarybchik hunt_filter_table_t *table = enp->en_filter.ef_hunt_filter_table; 1368283514Sarybchik 1369283514Sarybchik table->hft_default_rxq = NULL; 1370283514Sarybchik table->hft_using_rss = B_FALSE; 1371283514Sarybchik} 1372283514Sarybchik 1373283514Sarybchik 1374283514Sarybchik#endif /* EFSYS_OPT_FILTER */ 1375283514Sarybchik 1376283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 1377