ef10_filter.c revision 299594
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 299594 2016-05-13 06:47:07Z arybchik $"); 33283514Sarybchik 34283514Sarybchik#include "efx.h" 35283514Sarybchik#include "efx_impl.h" 36283514Sarybchik 37283514Sarybchik#if EFSYS_OPT_HUNTINGTON 38283514Sarybchik 39283514Sarybchik#if EFSYS_OPT_FILTER 40283514Sarybchik 41293764Sarybchik#define EFE_SPEC(eftp, index) ((eftp)->eft_entry[(index)].efe_spec) 42283514Sarybchik 43283514Sarybchikstatic efx_filter_spec_t * 44293764Sarybchikef10_filter_entry_spec( 45293764Sarybchik __in const ef10_filter_table_t *eftp, 46283514Sarybchik __in unsigned int index) 47283514Sarybchik{ 48293764Sarybchik return ((efx_filter_spec_t *)(EFE_SPEC(eftp, index) & 49293764Sarybchik ~(uintptr_t)EFX_EF10_FILTER_FLAGS)); 50283514Sarybchik} 51283514Sarybchik 52283514Sarybchikstatic boolean_t 53293764Sarybchikef10_filter_entry_is_busy( 54293764Sarybchik __in const ef10_filter_table_t *eftp, 55283514Sarybchik __in unsigned int index) 56283514Sarybchik{ 57293764Sarybchik if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_BUSY) 58283514Sarybchik return (B_TRUE); 59283514Sarybchik else 60283514Sarybchik return (B_FALSE); 61283514Sarybchik} 62283514Sarybchik 63283514Sarybchikstatic boolean_t 64293764Sarybchikef10_filter_entry_is_auto_old( 65293764Sarybchik __in const ef10_filter_table_t *eftp, 66283514Sarybchik __in unsigned int index) 67283514Sarybchik{ 68293764Sarybchik if (EFE_SPEC(eftp, index) & EFX_EF10_FILTER_FLAG_AUTO_OLD) 69283514Sarybchik return (B_TRUE); 70283514Sarybchik else 71283514Sarybchik return (B_FALSE); 72283514Sarybchik} 73283514Sarybchik 74283514Sarybchikstatic void 75293764Sarybchikef10_filter_set_entry( 76293764Sarybchik __inout ef10_filter_table_t *eftp, 77283514Sarybchik __in unsigned int index, 78283514Sarybchik __in_opt const efx_filter_spec_t *efsp) 79283514Sarybchik{ 80293764Sarybchik EFE_SPEC(eftp, index) = (uintptr_t)efsp; 81283514Sarybchik} 82283514Sarybchik 83283514Sarybchikstatic void 84293764Sarybchikef10_filter_set_entry_busy( 85293764Sarybchik __inout ef10_filter_table_t *eftp, 86283514Sarybchik __in unsigned int index) 87283514Sarybchik{ 88293764Sarybchik EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 89283514Sarybchik} 90283514Sarybchik 91283514Sarybchikstatic void 92293764Sarybchikef10_filter_set_entry_not_busy( 93293764Sarybchik __inout ef10_filter_table_t *eftp, 94283514Sarybchik __in unsigned int index) 95283514Sarybchik{ 96293764Sarybchik EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_BUSY; 97283514Sarybchik} 98283514Sarybchik 99283514Sarybchikstatic void 100293764Sarybchikef10_filter_set_entry_auto_old( 101293764Sarybchik __inout ef10_filter_table_t *eftp, 102283514Sarybchik __in unsigned int index) 103283514Sarybchik{ 104293764Sarybchik EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 105293764Sarybchik EFE_SPEC(eftp, index) |= (uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 106283514Sarybchik} 107283514Sarybchik 108283514Sarybchikstatic void 109293764Sarybchikef10_filter_set_entry_not_auto_old( 110293764Sarybchik __inout ef10_filter_table_t *eftp, 111283514Sarybchik __in unsigned int index) 112283514Sarybchik{ 113293764Sarybchik EFE_SPEC(eftp, index) &= ~(uintptr_t)EFX_EF10_FILTER_FLAG_AUTO_OLD; 114293764Sarybchik EFSYS_ASSERT(ef10_filter_entry_spec(eftp, index) != NULL); 115283514Sarybchik} 116283514Sarybchik 117291436Sarybchik __checkReturn efx_rc_t 118293764Sarybchikef10_filter_init( 119283514Sarybchik __in efx_nic_t *enp) 120283514Sarybchik{ 121291436Sarybchik efx_rc_t rc; 122293764Sarybchik ef10_filter_table_t *eftp; 123283514Sarybchik 124293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 125293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 126283514Sarybchik 127283514Sarybchik#define MATCH_MASK(match) (EFX_MASK32(match) << EFX_LOW_BIT(match)) 128283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_HOST == 129283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_IP)); 130283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_HOST == 131283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_IP)); 132283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_MAC == 133283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_MAC)); 134283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_REM_PORT == 135283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_SRC_PORT)); 136283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_MAC == 137283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_MAC)); 138283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_LOC_PORT == 139283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_DST_PORT)); 140283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_ETHER_TYPE == 141283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_ETHER_TYPE)); 142283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_INNER_VID == 143283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_INNER_VLAN)); 144283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_OUTER_VID == 145283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_OUTER_VLAN)); 146283514Sarybchik EFX_STATIC_ASSERT(EFX_FILTER_MATCH_IP_PROTO == 147283514Sarybchik MATCH_MASK(MC_CMD_FILTER_OP_IN_MATCH_IP_PROTO)); 148283514Sarybchik#undef MATCH_MASK 149283514Sarybchik 150293764Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (ef10_filter_table_t), eftp); 151283514Sarybchik 152293764Sarybchik if (!eftp) { 153283514Sarybchik rc = ENOMEM; 154283514Sarybchik goto fail1; 155283514Sarybchik } 156283514Sarybchik 157293764Sarybchik enp->en_filter.ef_ef10_filter_table = eftp; 158283514Sarybchik 159283514Sarybchik return (0); 160283514Sarybchik 161283514Sarybchikfail1: 162291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 163283514Sarybchik 164283514Sarybchik return (rc); 165283514Sarybchik} 166283514Sarybchik 167283514Sarybchik void 168293764Sarybchikef10_filter_fini( 169283514Sarybchik __in efx_nic_t *enp) 170283514Sarybchik{ 171293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 172293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 173283514Sarybchik 174293764Sarybchik if (enp->en_filter.ef_ef10_filter_table != NULL) { 175293764Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (ef10_filter_table_t), 176293764Sarybchik enp->en_filter.ef_ef10_filter_table); 177283514Sarybchik } 178283514Sarybchik} 179283514Sarybchik 180291436Sarybchikstatic __checkReturn efx_rc_t 181283514Sarybchikefx_mcdi_filter_op_add( 182283514Sarybchik __in efx_nic_t *enp, 183283514Sarybchik __in efx_filter_spec_t *spec, 184283514Sarybchik __in unsigned int filter_op, 185293764Sarybchik __inout ef10_filter_handle_t *handle) 186283514Sarybchik{ 187283514Sarybchik efx_mcdi_req_t req; 188283514Sarybchik uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 189283514Sarybchik MC_CMD_FILTER_OP_OUT_LEN)]; 190283514Sarybchik uint32_t match_fields = 0; 191291436Sarybchik efx_rc_t rc; 192283514Sarybchik 193283514Sarybchik memset(payload, 0, sizeof (payload)); 194283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 195283514Sarybchik req.emr_in_buf = payload; 196283514Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 197283514Sarybchik req.emr_out_buf = payload; 198283514Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 199283514Sarybchik 200283514Sarybchik switch (filter_op) { 201283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REPLACE: 202283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, 203293764Sarybchik handle->efh_lo); 204283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, 205293764Sarybchik handle->efh_hi); 206283514Sarybchik /* Fall through */ 207283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_INSERT: 208283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE: 209283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, filter_op); 210283514Sarybchik break; 211283514Sarybchik default: 212283514Sarybchik EFSYS_ASSERT(0); 213283514Sarybchik rc = EINVAL; 214283514Sarybchik goto fail1; 215283514Sarybchik } 216283514Sarybchik 217283514Sarybchik if (spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC_IG) { 218283514Sarybchik /* 219283514Sarybchik * The LOC_MAC_IG match flag can represent unknown unicast 220283514Sarybchik * or multicast filters - use the MAC address to distinguish 221283514Sarybchik * them. 222283514Sarybchik */ 223283514Sarybchik if (EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 224283514Sarybchik match_fields |= 1U << 225283514Sarybchik MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN; 226283514Sarybchik else 227283514Sarybchik match_fields |= 1U << 228283514Sarybchik MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN; 229283514Sarybchik } 230283514Sarybchik 231283514Sarybchik match_fields |= spec->efs_match_flags & (~EFX_FILTER_MATCH_LOC_MAC_IG); 232283514Sarybchik 233283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_PORT_ID, 234283514Sarybchik EVB_PORT_ID_ASSIGNED); 235283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_MATCH_FIELDS, 236283514Sarybchik match_fields); 237283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_DEST, 238283514Sarybchik MC_CMD_FILTER_OP_IN_RX_DEST_HOST); 239283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_QUEUE, 240283514Sarybchik spec->efs_dmaq_id); 241283514Sarybchik if (spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) { 242283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_CONTEXT, 243283514Sarybchik spec->efs_rss_context); 244283514Sarybchik } 245283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_RX_MODE, 246283514Sarybchik spec->efs_flags & EFX_FILTER_FLAG_RX_RSS ? 247283514Sarybchik MC_CMD_FILTER_OP_IN_RX_MODE_RSS : 248283514Sarybchik MC_CMD_FILTER_OP_IN_RX_MODE_SIMPLE); 249283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_TX_DEST, 250283514Sarybchik MC_CMD_FILTER_OP_IN_TX_DEST_DEFAULT); 251283514Sarybchik 252283514Sarybchik if (filter_op != MC_CMD_FILTER_OP_IN_OP_REPLACE) { 253283514Sarybchik /* 254283514Sarybchik * NOTE: Unlike most MCDI requests, the filter fields 255283514Sarybchik * are presented in network (big endian) byte order. 256283514Sarybchik */ 257283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_MAC), 258283514Sarybchik spec->efs_rem_mac, EFX_MAC_ADDR_LEN); 259283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_MAC), 260283514Sarybchik spec->efs_loc_mac, EFX_MAC_ADDR_LEN); 261283514Sarybchik 262283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_SRC_PORT, 263283514Sarybchik __CPU_TO_BE_16(spec->efs_rem_port)); 264283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_DST_PORT, 265283514Sarybchik __CPU_TO_BE_16(spec->efs_loc_port)); 266283514Sarybchik 267283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_ETHER_TYPE, 268283514Sarybchik __CPU_TO_BE_16(spec->efs_ether_type)); 269283514Sarybchik 270283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_INNER_VLAN, 271283514Sarybchik __CPU_TO_BE_16(spec->efs_inner_vid)); 272283514Sarybchik MCDI_IN_SET_WORD(req, FILTER_OP_IN_OUTER_VLAN, 273283514Sarybchik __CPU_TO_BE_16(spec->efs_outer_vid)); 274283514Sarybchik 275283514Sarybchik /* IP protocol (in low byte, high byte is zero) */ 276283514Sarybchik MCDI_IN_SET_BYTE(req, FILTER_OP_IN_IP_PROTO, 277283514Sarybchik spec->efs_ip_proto); 278283514Sarybchik 279283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_rem_host) == 280283514Sarybchik MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 281283514Sarybchik EFX_STATIC_ASSERT(sizeof (spec->efs_loc_host) == 282283514Sarybchik MC_CMD_FILTER_OP_IN_DST_IP_LEN); 283283514Sarybchik 284283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_SRC_IP), 285283514Sarybchik &spec->efs_rem_host.eo_byte[0], 286283514Sarybchik MC_CMD_FILTER_OP_IN_SRC_IP_LEN); 287283514Sarybchik memcpy(MCDI_IN2(req, uint8_t, FILTER_OP_IN_DST_IP), 288283514Sarybchik &spec->efs_loc_host.eo_byte[0], 289283514Sarybchik MC_CMD_FILTER_OP_IN_DST_IP_LEN); 290283514Sarybchik } 291283514Sarybchik 292283514Sarybchik efx_mcdi_execute(enp, &req); 293283514Sarybchik 294283514Sarybchik if (req.emr_rc != 0) { 295283514Sarybchik rc = req.emr_rc; 296283514Sarybchik goto fail2; 297283514Sarybchik } 298283514Sarybchik 299283514Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 300283514Sarybchik rc = EMSGSIZE; 301283514Sarybchik goto fail3; 302283514Sarybchik } 303283514Sarybchik 304293764Sarybchik handle->efh_lo = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_LO); 305293764Sarybchik handle->efh_hi = MCDI_OUT_DWORD(req, FILTER_OP_OUT_HANDLE_HI); 306283514Sarybchik 307283514Sarybchik return (0); 308283514Sarybchik 309283514Sarybchikfail3: 310283514Sarybchik EFSYS_PROBE(fail3); 311283514Sarybchikfail2: 312283514Sarybchik EFSYS_PROBE(fail2); 313283514Sarybchikfail1: 314291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 315283514Sarybchik 316283514Sarybchik return (rc); 317283514Sarybchik 318283514Sarybchik} 319283514Sarybchik 320291436Sarybchikstatic __checkReturn efx_rc_t 321283514Sarybchikefx_mcdi_filter_op_delete( 322283514Sarybchik __in efx_nic_t *enp, 323283514Sarybchik __in unsigned int filter_op, 324293764Sarybchik __inout ef10_filter_handle_t *handle) 325283514Sarybchik{ 326283514Sarybchik efx_mcdi_req_t req; 327283514Sarybchik uint8_t payload[MAX(MC_CMD_FILTER_OP_IN_LEN, 328283514Sarybchik MC_CMD_FILTER_OP_OUT_LEN)]; 329291436Sarybchik efx_rc_t rc; 330283514Sarybchik 331283514Sarybchik memset(payload, 0, sizeof (payload)); 332283514Sarybchik req.emr_cmd = MC_CMD_FILTER_OP; 333283514Sarybchik req.emr_in_buf = payload; 334283514Sarybchik req.emr_in_length = MC_CMD_FILTER_OP_IN_LEN; 335283514Sarybchik req.emr_out_buf = payload; 336283514Sarybchik req.emr_out_length = MC_CMD_FILTER_OP_OUT_LEN; 337283514Sarybchik 338283514Sarybchik switch (filter_op) { 339283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_REMOVE: 340283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 341283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE); 342283514Sarybchik break; 343283514Sarybchik case MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE: 344283514Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_OP, 345283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE); 346283514Sarybchik break; 347283514Sarybchik default: 348283514Sarybchik EFSYS_ASSERT(0); 349283514Sarybchik rc = EINVAL; 350283514Sarybchik goto fail1; 351283514Sarybchik } 352283514Sarybchik 353293764Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_LO, handle->efh_lo); 354293764Sarybchik MCDI_IN_SET_DWORD(req, FILTER_OP_IN_HANDLE_HI, handle->efh_hi); 355283514Sarybchik 356283514Sarybchik efx_mcdi_execute(enp, &req); 357283514Sarybchik 358283514Sarybchik if (req.emr_rc != 0) { 359283514Sarybchik rc = req.emr_rc; 360283514Sarybchik goto fail2; 361283514Sarybchik } 362283514Sarybchik 363283514Sarybchik if (req.emr_out_length_used < MC_CMD_FILTER_OP_OUT_LEN) { 364283514Sarybchik rc = EMSGSIZE; 365283514Sarybchik goto fail3; 366283514Sarybchik } 367283514Sarybchik 368283514Sarybchik return (0); 369283514Sarybchik 370283514Sarybchikfail3: 371283514Sarybchik EFSYS_PROBE(fail3); 372283514Sarybchik 373283514Sarybchikfail2: 374283514Sarybchik EFSYS_PROBE(fail2); 375283514Sarybchikfail1: 376291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 377283514Sarybchik 378283514Sarybchik return (rc); 379283514Sarybchik} 380283514Sarybchik 381283514Sarybchikstatic __checkReturn boolean_t 382293764Sarybchikef10_filter_equal( 383283514Sarybchik __in const efx_filter_spec_t *left, 384283514Sarybchik __in const efx_filter_spec_t *right) 385283514Sarybchik{ 386283514Sarybchik /* FIXME: Consider rx vs tx filters (look at efs_flags) */ 387283514Sarybchik if (left->efs_match_flags != right->efs_match_flags) 388283514Sarybchik return (B_FALSE); 389283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_rem_host, right->efs_rem_host)) 390283514Sarybchik return (B_FALSE); 391283514Sarybchik if (!EFX_OWORD_IS_EQUAL(left->efs_loc_host, right->efs_loc_host)) 392283514Sarybchik return (B_FALSE); 393283514Sarybchik if (memcmp(left->efs_rem_mac, right->efs_rem_mac, EFX_MAC_ADDR_LEN)) 394283514Sarybchik return (B_FALSE); 395283514Sarybchik if (memcmp(left->efs_loc_mac, right->efs_loc_mac, EFX_MAC_ADDR_LEN)) 396283514Sarybchik return (B_FALSE); 397283514Sarybchik if (left->efs_rem_port != right->efs_rem_port) 398283514Sarybchik return (B_FALSE); 399283514Sarybchik if (left->efs_loc_port != right->efs_loc_port) 400283514Sarybchik return (B_FALSE); 401283514Sarybchik if (left->efs_inner_vid != right->efs_inner_vid) 402283514Sarybchik return (B_FALSE); 403283514Sarybchik if (left->efs_outer_vid != right->efs_outer_vid) 404283514Sarybchik return (B_FALSE); 405283514Sarybchik if (left->efs_ether_type != right->efs_ether_type) 406283514Sarybchik return (B_FALSE); 407283514Sarybchik if (left->efs_ip_proto != right->efs_ip_proto) 408283514Sarybchik return (B_FALSE); 409283514Sarybchik 410283514Sarybchik return (B_TRUE); 411283514Sarybchik 412283514Sarybchik} 413283514Sarybchik 414283514Sarybchikstatic __checkReturn boolean_t 415293764Sarybchikef10_filter_same_dest( 416283514Sarybchik __in const efx_filter_spec_t *left, 417283514Sarybchik __in const efx_filter_spec_t *right) 418283514Sarybchik{ 419283514Sarybchik if ((left->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 420283514Sarybchik (right->efs_flags & EFX_FILTER_FLAG_RX_RSS)) { 421283514Sarybchik if (left->efs_rss_context == right->efs_rss_context) 422283514Sarybchik return (B_TRUE); 423283514Sarybchik } else if ((~(left->efs_flags) & EFX_FILTER_FLAG_RX_RSS) && 424283514Sarybchik (~(right->efs_flags) & EFX_FILTER_FLAG_RX_RSS)) { 425283514Sarybchik if (left->efs_dmaq_id == right->efs_dmaq_id) 426283514Sarybchik return (B_TRUE); 427283514Sarybchik } 428283514Sarybchik return (B_FALSE); 429283514Sarybchik} 430283514Sarybchik 431283514Sarybchikstatic __checkReturn uint32_t 432293764Sarybchikef10_filter_hash( 433283514Sarybchik __in efx_filter_spec_t *spec) 434283514Sarybchik{ 435283514Sarybchik EFX_STATIC_ASSERT((sizeof (efx_filter_spec_t) % sizeof (uint32_t)) 436283514Sarybchik == 0); 437283514Sarybchik EFX_STATIC_ASSERT((EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid) % 438283514Sarybchik sizeof (uint32_t)) == 0); 439283514Sarybchik 440283514Sarybchik /* 441283514Sarybchik * As the area of the efx_filter_spec_t we need to hash is DWORD 442283514Sarybchik * aligned and an exact number of DWORDs in size we can use the 443283514Sarybchik * optimised efx_hash_dwords() rather than efx_hash_bytes() 444283514Sarybchik */ 445283514Sarybchik return (efx_hash_dwords((const uint32_t *)&spec->efs_outer_vid, 446283514Sarybchik (sizeof (efx_filter_spec_t) - 447283514Sarybchik EFX_FIELD_OFFSET(efx_filter_spec_t, efs_outer_vid)) / 448283514Sarybchik sizeof (uint32_t), 0)); 449283514Sarybchik} 450283514Sarybchik 451283514Sarybchik/* 452283514Sarybchik * Decide whether a filter should be exclusive or else should allow 453283514Sarybchik * delivery to additional recipients. Currently we decide that 454283514Sarybchik * filters for specific local unicast MAC and IP addresses are 455283514Sarybchik * exclusive. 456283514Sarybchik */ 457283514Sarybchikstatic __checkReturn boolean_t 458293764Sarybchikef10_filter_is_exclusive( 459283514Sarybchik __in efx_filter_spec_t *spec) 460283514Sarybchik{ 461283514Sarybchik if ((spec->efs_match_flags & EFX_FILTER_MATCH_LOC_MAC) && 462283514Sarybchik !EFX_MAC_ADDR_IS_MULTICAST(spec->efs_loc_mac)) 463283514Sarybchik return (B_TRUE); 464283514Sarybchik 465283514Sarybchik if ((spec->efs_match_flags & 466283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) == 467283514Sarybchik (EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_LOC_HOST)) { 468283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV4) && 469283514Sarybchik ((spec->efs_loc_host.eo_u8[0] & 0xf) != 0xe)) 470283514Sarybchik return (B_TRUE); 471283514Sarybchik if ((spec->efs_ether_type == EFX_ETHER_TYPE_IPV6) && 472283514Sarybchik (spec->efs_loc_host.eo_u8[0] != 0xff)) 473283514Sarybchik return (B_TRUE); 474283514Sarybchik } 475283514Sarybchik 476283514Sarybchik return (B_FALSE); 477283514Sarybchik} 478283514Sarybchik 479291436Sarybchik __checkReturn efx_rc_t 480293764Sarybchikef10_filter_restore( 481283514Sarybchik __in efx_nic_t *enp) 482283514Sarybchik{ 483283514Sarybchik int tbl_id; 484283514Sarybchik efx_filter_spec_t *spec; 485293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 486283514Sarybchik boolean_t restoring; 487283514Sarybchik int state; 488291436Sarybchik efx_rc_t rc; 489283514Sarybchik 490293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 491293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 492283514Sarybchik 493293764Sarybchik for (tbl_id = 0; tbl_id < EFX_EF10_FILTER_TBL_ROWS; tbl_id++) { 494283514Sarybchik 495283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 496283514Sarybchik 497293764Sarybchik spec = ef10_filter_entry_spec(eftp, tbl_id); 498283514Sarybchik if (spec == NULL) { 499283514Sarybchik restoring = B_FALSE; 500293764Sarybchik } else if (ef10_filter_entry_is_busy(eftp, tbl_id)) { 501283514Sarybchik /* Ignore busy entries. */ 502283514Sarybchik restoring = B_FALSE; 503283514Sarybchik } else { 504293764Sarybchik ef10_filter_set_entry_busy(eftp, tbl_id); 505283514Sarybchik restoring = B_TRUE; 506283514Sarybchik } 507283514Sarybchik 508283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 509283514Sarybchik 510283514Sarybchik if (restoring == B_FALSE) 511283514Sarybchik continue; 512283514Sarybchik 513293764Sarybchik if (ef10_filter_is_exclusive(spec)) { 514283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 515283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 516293764Sarybchik &eftp->eft_entry[tbl_id].efe_handle); 517283514Sarybchik } else { 518283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 519283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 520293764Sarybchik &eftp->eft_entry[tbl_id].efe_handle); 521283514Sarybchik } 522283514Sarybchik 523283514Sarybchik if (rc != 0) 524283514Sarybchik goto fail1; 525283514Sarybchik 526283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 527283514Sarybchik 528293764Sarybchik ef10_filter_set_entry_not_busy(eftp, tbl_id); 529283514Sarybchik 530283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 531283514Sarybchik } 532283514Sarybchik 533283514Sarybchik return (0); 534283514Sarybchik 535283514Sarybchikfail1: 536291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, 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 */ 545293764Sarybchik#define EF10_FILTER_SEARCH_LIMIT 200 546283514Sarybchik 547291436Sarybchikstatic __checkReturn efx_rc_t 548293764Sarybchikef10_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{ 554291436Sarybchik efx_rc_t rc; 555293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_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 565293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 566293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 567283514Sarybchik 568283514Sarybchik#if EFSYS_OPT_RX_SCALE 569283514Sarybchik spec->efs_rss_context = enp->en_rss_context; 570283514Sarybchik#endif 571283514Sarybchik 572293764Sarybchik hash = ef10_filter_hash(spec); 573283514Sarybchik 574283514Sarybchik /* 575283514Sarybchik * FIXME: Add support for inserting filters of different priorities 576283514Sarybchik * and removing lower priority multicast filters (bug 42378) 577283514Sarybchik */ 578283514Sarybchik 579283514Sarybchik /* 580283514Sarybchik * Find any existing filters with the same match tuple or 581283514Sarybchik * else a free slot to insert at. If any of them are busy, 582283514Sarybchik * we have to wait and retry. 583283514Sarybchik */ 584283514Sarybchik for (;;) { 585283514Sarybchik ins_index = -1; 586283514Sarybchik depth = 1; 587283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 588283514Sarybchik locked = B_TRUE; 589283514Sarybchik 590283514Sarybchik for (;;) { 591293764Sarybchik i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 592293764Sarybchik saved_spec = ef10_filter_entry_spec(eftp, i); 593283514Sarybchik 594283514Sarybchik if (!saved_spec) { 595283514Sarybchik if (ins_index < 0) { 596283514Sarybchik ins_index = i; 597283514Sarybchik } 598293764Sarybchik } else if (ef10_filter_equal(spec, saved_spec)) { 599293764Sarybchik if (ef10_filter_entry_is_busy(eftp, i)) 600283514Sarybchik break; 601283514Sarybchik if (saved_spec->efs_priority 602283514Sarybchik == EFX_FILTER_PRI_AUTO) { 603283514Sarybchik ins_index = i; 604283514Sarybchik goto found; 605293764Sarybchik } else if (ef10_filter_is_exclusive(spec)) { 606283514Sarybchik if (may_replace) { 607283514Sarybchik ins_index = i; 608283514Sarybchik goto found; 609283514Sarybchik } else { 610283514Sarybchik rc = EEXIST; 611283514Sarybchik goto fail1; 612283514Sarybchik } 613283514Sarybchik } 614283514Sarybchik 615283514Sarybchik /* Leave existing */ 616283514Sarybchik } 617283514Sarybchik 618283514Sarybchik /* 619283514Sarybchik * Once we reach the maximum search depth, use 620283514Sarybchik * the first suitable slot or return EBUSY if 621283514Sarybchik * there was none. 622283514Sarybchik */ 623293764Sarybchik if (depth == EF10_FILTER_SEARCH_LIMIT) { 624283514Sarybchik if (ins_index < 0) { 625283514Sarybchik rc = EBUSY; 626283514Sarybchik goto fail2; 627283514Sarybchik } 628283514Sarybchik goto found; 629283514Sarybchik } 630283514Sarybchik depth++; 631283514Sarybchik } 632283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 633283514Sarybchik locked = B_FALSE; 634283514Sarybchik } 635283514Sarybchik 636283514Sarybchikfound: 637283514Sarybchik /* 638283514Sarybchik * Create a software table entry if necessary, and mark it 639283514Sarybchik * busy. We might yet fail to insert, but any attempt to 640283514Sarybchik * insert a conflicting filter while we're waiting for the 641283514Sarybchik * firmware must find the busy entry. 642283514Sarybchik */ 643293764Sarybchik saved_spec = ef10_filter_entry_spec(eftp, ins_index); 644283514Sarybchik if (saved_spec) { 645283514Sarybchik if (saved_spec->efs_priority == EFX_FILTER_PRI_AUTO) { 646283514Sarybchik /* This is a filter we are refreshing */ 647293764Sarybchik ef10_filter_set_entry_not_auto_old(eftp, ins_index); 648283514Sarybchik goto out_unlock; 649283514Sarybchik 650283514Sarybchik } 651283514Sarybchik replacing = B_TRUE; 652283514Sarybchik } else { 653283514Sarybchik EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (*spec), saved_spec); 654283514Sarybchik if (!saved_spec) { 655283514Sarybchik rc = ENOMEM; 656283514Sarybchik goto fail3; 657283514Sarybchik } 658283514Sarybchik *saved_spec = *spec; 659293764Sarybchik ef10_filter_set_entry(eftp, ins_index, saved_spec); 660283514Sarybchik } 661293764Sarybchik ef10_filter_set_entry_busy(eftp, ins_index); 662283514Sarybchik 663283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 664283514Sarybchik locked = B_FALSE; 665283514Sarybchik 666283514Sarybchik /* 667283514Sarybchik * On replacing the filter handle may change after after a successful 668283514Sarybchik * replace operation. 669283514Sarybchik */ 670283514Sarybchik if (replacing) { 671283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 672283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REPLACE, 673293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 674293764Sarybchik } else if (ef10_filter_is_exclusive(spec)) { 675283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 676283514Sarybchik MC_CMD_FILTER_OP_IN_OP_INSERT, 677293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 678283514Sarybchik } else { 679283514Sarybchik rc = efx_mcdi_filter_op_add(enp, spec, 680283514Sarybchik MC_CMD_FILTER_OP_IN_OP_SUBSCRIBE, 681293764Sarybchik &eftp->eft_entry[ins_index].efe_handle); 682283514Sarybchik } 683283514Sarybchik 684283514Sarybchik if (rc != 0) 685283514Sarybchik goto fail4; 686283514Sarybchik 687283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 688283514Sarybchik locked = B_TRUE; 689283514Sarybchik 690283514Sarybchik if (replacing) { 691283514Sarybchik /* Update the fields that may differ */ 692283514Sarybchik saved_spec->efs_priority = spec->efs_priority; 693283514Sarybchik saved_spec->efs_flags = spec->efs_flags; 694283514Sarybchik saved_spec->efs_rss_context = spec->efs_rss_context; 695283514Sarybchik saved_spec->efs_dmaq_id = spec->efs_dmaq_id; 696283514Sarybchik } 697283514Sarybchik 698293764Sarybchik ef10_filter_set_entry_not_busy(eftp, ins_index); 699283514Sarybchik 700283514Sarybchikout_unlock: 701283514Sarybchik 702283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 703283514Sarybchik locked = B_FALSE; 704283514Sarybchik 705283514Sarybchik if (filter_id) 706283514Sarybchik *filter_id = ins_index; 707283514Sarybchik 708283514Sarybchik return (0); 709283514Sarybchik 710283514Sarybchikfail4: 711283514Sarybchik EFSYS_PROBE(fail4); 712283514Sarybchik 713283514Sarybchik if (!replacing) { 714283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), saved_spec); 715283514Sarybchik saved_spec = NULL; 716283514Sarybchik } 717293764Sarybchik ef10_filter_set_entry_not_busy(eftp, ins_index); 718293764Sarybchik ef10_filter_set_entry(eftp, ins_index, NULL); 719283514Sarybchik 720283514Sarybchikfail3: 721283514Sarybchik EFSYS_PROBE(fail3); 722283514Sarybchik 723283514Sarybchikfail2: 724283514Sarybchik EFSYS_PROBE(fail2); 725283514Sarybchik 726283514Sarybchikfail1: 727291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 728283514Sarybchik 729283514Sarybchik if (locked) 730283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 731283514Sarybchik 732283514Sarybchik return (rc); 733283514Sarybchik} 734283514Sarybchik 735291436Sarybchik __checkReturn efx_rc_t 736293764Sarybchikef10_filter_add( 737283514Sarybchik __in efx_nic_t *enp, 738283514Sarybchik __inout efx_filter_spec_t *spec, 739283514Sarybchik __in boolean_t may_replace) 740283514Sarybchik{ 741291436Sarybchik efx_rc_t rc; 742283514Sarybchik 743293764Sarybchik rc = ef10_filter_add_internal(enp, spec, may_replace, NULL); 744283514Sarybchik if (rc != 0) 745283514Sarybchik goto fail1; 746283514Sarybchik 747283514Sarybchik return (0); 748283514Sarybchik 749283514Sarybchikfail1: 750291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 751283514Sarybchik 752283514Sarybchik return (rc); 753283514Sarybchik} 754283514Sarybchik 755283514Sarybchik 756291436Sarybchikstatic __checkReturn efx_rc_t 757293764Sarybchikef10_filter_delete_internal( 758283514Sarybchik __in efx_nic_t *enp, 759283514Sarybchik __in uint32_t filter_id) 760283514Sarybchik{ 761291436Sarybchik efx_rc_t rc; 762293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 763283514Sarybchik efx_filter_spec_t *spec; 764283514Sarybchik int state; 765293764Sarybchik uint32_t filter_idx = filter_id % EFX_EF10_FILTER_TBL_ROWS; 766283514Sarybchik 767283514Sarybchik /* 768283514Sarybchik * Find the software table entry and mark it busy. Don't 769283514Sarybchik * remove it yet; any attempt to update while we're waiting 770283514Sarybchik * for the firmware must find the busy entry. 771283514Sarybchik * 772283514Sarybchik * FIXME: What if the busy flag is never cleared? 773283514Sarybchik */ 774283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 775293764Sarybchik while (ef10_filter_entry_is_busy(table, filter_idx)) { 776283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 777283514Sarybchik EFSYS_SPIN(1); 778283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 779283514Sarybchik } 780293764Sarybchik if ((spec = ef10_filter_entry_spec(table, filter_idx)) != NULL) { 781293764Sarybchik ef10_filter_set_entry_busy(table, filter_idx); 782283514Sarybchik } 783283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 784283514Sarybchik 785283514Sarybchik if (spec == NULL) { 786283514Sarybchik rc = ENOENT; 787283514Sarybchik goto fail1; 788283514Sarybchik } 789283514Sarybchik 790283514Sarybchik /* 791283514Sarybchik * Try to remove the hardware filter. This may fail if the MC has 792283514Sarybchik * rebooted (which frees all hardware filter resources). 793283514Sarybchik */ 794293764Sarybchik if (ef10_filter_is_exclusive(spec)) { 795283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 796283514Sarybchik MC_CMD_FILTER_OP_IN_OP_REMOVE, 797293764Sarybchik &table->eft_entry[filter_idx].efe_handle); 798283514Sarybchik } else { 799283514Sarybchik rc = efx_mcdi_filter_op_delete(enp, 800283514Sarybchik MC_CMD_FILTER_OP_IN_OP_UNSUBSCRIBE, 801293764Sarybchik &table->eft_entry[filter_idx].efe_handle); 802283514Sarybchik } 803283514Sarybchik 804283514Sarybchik /* Free the software table entry */ 805283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 806293764Sarybchik ef10_filter_set_entry_not_busy(table, filter_idx); 807293764Sarybchik ef10_filter_set_entry(table, filter_idx, NULL); 808283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 809283514Sarybchik 810283514Sarybchik EFSYS_KMEM_FREE(enp->en_esip, sizeof (*spec), spec); 811283514Sarybchik 812283514Sarybchik /* Check result of hardware filter removal */ 813283514Sarybchik if (rc != 0) 814283514Sarybchik goto fail2; 815283514Sarybchik 816283514Sarybchik return (0); 817283514Sarybchik 818283514Sarybchikfail2: 819283514Sarybchik EFSYS_PROBE(fail2); 820283514Sarybchik 821283514Sarybchikfail1: 822291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 823283514Sarybchik 824283514Sarybchik return (rc); 825283514Sarybchik} 826283514Sarybchik 827291436Sarybchik __checkReturn efx_rc_t 828293764Sarybchikef10_filter_delete( 829283514Sarybchik __in efx_nic_t *enp, 830283514Sarybchik __inout efx_filter_spec_t *spec) 831283514Sarybchik{ 832291436Sarybchik efx_rc_t rc; 833293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 834283514Sarybchik efx_filter_spec_t *saved_spec; 835283514Sarybchik unsigned int hash; 836283514Sarybchik unsigned int depth; 837283514Sarybchik unsigned int i; 838283514Sarybchik int state; 839283514Sarybchik boolean_t locked = B_FALSE; 840283514Sarybchik 841293764Sarybchik EFSYS_ASSERT(enp->en_family == EFX_FAMILY_HUNTINGTON || 842293764Sarybchik enp->en_family == EFX_FAMILY_MEDFORD); 843283514Sarybchik 844293764Sarybchik hash = ef10_filter_hash(spec); 845283514Sarybchik 846283514Sarybchik EFSYS_LOCK(enp->en_eslp, state); 847283514Sarybchik locked = B_TRUE; 848283514Sarybchik 849283514Sarybchik depth = 1; 850283514Sarybchik for (;;) { 851293764Sarybchik i = (hash + depth) & (EFX_EF10_FILTER_TBL_ROWS - 1); 852293764Sarybchik saved_spec = ef10_filter_entry_spec(table, i); 853293764Sarybchik if (saved_spec && ef10_filter_equal(spec, saved_spec) && 854293764Sarybchik ef10_filter_same_dest(spec, saved_spec)) { 855283514Sarybchik break; 856283514Sarybchik } 857293764Sarybchik if (depth == EF10_FILTER_SEARCH_LIMIT) { 858283514Sarybchik rc = ENOENT; 859283514Sarybchik goto fail1; 860283514Sarybchik } 861283514Sarybchik depth++; 862283514Sarybchik } 863283514Sarybchik 864283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 865283514Sarybchik locked = B_FALSE; 866283514Sarybchik 867293764Sarybchik rc = ef10_filter_delete_internal(enp, i); 868283514Sarybchik if (rc != 0) 869283514Sarybchik goto fail2; 870283514Sarybchik 871283514Sarybchik return (0); 872283514Sarybchik 873283514Sarybchikfail2: 874283514Sarybchik EFSYS_PROBE(fail2); 875283514Sarybchik 876283514Sarybchikfail1: 877291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 878283514Sarybchik 879283514Sarybchik if (locked) 880283514Sarybchik EFSYS_UNLOCK(enp->en_eslp, state); 881283514Sarybchik 882283514Sarybchik return (rc); 883283514Sarybchik} 884283514Sarybchik 885291436Sarybchikstatic __checkReturn efx_rc_t 886283514Sarybchikefx_mcdi_get_parser_disp_info( 887283514Sarybchik __in efx_nic_t *enp, 888283514Sarybchik __out uint32_t *list, 889283514Sarybchik __out size_t *length) 890283514Sarybchik{ 891283514Sarybchik efx_mcdi_req_t req; 892283514Sarybchik uint8_t payload[MAX(MC_CMD_GET_PARSER_DISP_INFO_IN_LEN, 893283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX)]; 894291436Sarybchik efx_rc_t rc; 895283514Sarybchik uint32_t i; 896283514Sarybchik boolean_t support_unknown_ucast = B_FALSE; 897283514Sarybchik boolean_t support_unknown_mcast = B_FALSE; 898283514Sarybchik 899283514Sarybchik (void) memset(payload, 0, sizeof (payload)); 900283514Sarybchik req.emr_cmd = MC_CMD_GET_PARSER_DISP_INFO; 901283514Sarybchik req.emr_in_buf = payload; 902283514Sarybchik req.emr_in_length = MC_CMD_GET_PARSER_DISP_INFO_IN_LEN; 903283514Sarybchik req.emr_out_buf = payload; 904283514Sarybchik req.emr_out_length = MC_CMD_GET_PARSER_DISP_INFO_OUT_LENMAX; 905283514Sarybchik 906283514Sarybchik MCDI_IN_SET_DWORD(req, GET_PARSER_DISP_INFO_OUT_OP, 907283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_IN_OP_GET_SUPPORTED_RX_MATCHES); 908283514Sarybchik 909283514Sarybchik efx_mcdi_execute(enp, &req); 910283514Sarybchik 911283514Sarybchik if (req.emr_rc != 0) { 912283514Sarybchik rc = req.emr_rc; 913283514Sarybchik goto fail1; 914283514Sarybchik } 915283514Sarybchik 916283514Sarybchik *length = MCDI_OUT_DWORD(req, 917283514Sarybchik GET_PARSER_DISP_INFO_OUT_NUM_SUPPORTED_MATCHES); 918283514Sarybchik 919283514Sarybchik if (req.emr_out_length_used < 920283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_LEN(*length)) { 921283514Sarybchik rc = EMSGSIZE; 922283514Sarybchik goto fail2; 923283514Sarybchik } 924283514Sarybchik 925283514Sarybchik memcpy(list, 926283514Sarybchik MCDI_OUT2(req, 927283514Sarybchik uint32_t, 928283514Sarybchik GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES), 929283514Sarybchik (*length) * sizeof (uint32_t)); 930283514Sarybchik EFX_STATIC_ASSERT(sizeof (uint32_t) == 931283514Sarybchik MC_CMD_GET_PARSER_DISP_INFO_OUT_SUPPORTED_MATCHES_LEN); 932283514Sarybchik 933283514Sarybchik /* 934283514Sarybchik * Remove UNKNOWN UCAST and MCAST flags, and if both are present, change 935283514Sarybchik * the lower priority one to LOC_MAC_IG. 936283514Sarybchik */ 937283514Sarybchik for (i = 0; i < *length; i++) { 938283514Sarybchik if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN) { 939283514Sarybchik list[i] &= 940283514Sarybchik (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_UCAST_DST_LBN); 941283514Sarybchik support_unknown_ucast = B_TRUE; 942283514Sarybchik } 943283514Sarybchik if (list[i] & MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN) { 944283514Sarybchik list[i] &= 945283514Sarybchik (~MC_CMD_FILTER_OP_IN_MATCH_UNKNOWN_MCAST_DST_LBN); 946283514Sarybchik support_unknown_mcast = B_TRUE; 947283514Sarybchik } 948283514Sarybchik 949283514Sarybchik if (support_unknown_ucast && support_unknown_mcast) { 950283514Sarybchik list[i] &= EFX_FILTER_MATCH_LOC_MAC_IG; 951283514Sarybchik break; 952283514Sarybchik } 953283514Sarybchik } 954283514Sarybchik 955283514Sarybchik return (0); 956283514Sarybchik 957283514Sarybchikfail2: 958283514Sarybchik EFSYS_PROBE(fail2); 959283514Sarybchikfail1: 960291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 961283514Sarybchik 962283514Sarybchik return (rc); 963283514Sarybchik} 964283514Sarybchik 965291436Sarybchik __checkReturn efx_rc_t 966293764Sarybchikef10_filter_supported_filters( 967283514Sarybchik __in efx_nic_t *enp, 968283514Sarybchik __out uint32_t *list, 969283514Sarybchik __out size_t *length) 970283514Sarybchik{ 971291436Sarybchik efx_rc_t rc; 972283514Sarybchik 973283514Sarybchik if ((rc = efx_mcdi_get_parser_disp_info(enp, list, length) != 0)) 974283514Sarybchik goto fail1; 975283514Sarybchik 976283514Sarybchik return (0); 977283514Sarybchik 978283514Sarybchikfail1: 979291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 980283514Sarybchik 981283514Sarybchik return (rc); 982283514Sarybchik} 983283514Sarybchik 984291436Sarybchikstatic __checkReturn efx_rc_t 985299411Sarybchikef10_filter_insert_unicast( 986283514Sarybchik __in efx_nic_t *enp, 987283514Sarybchik __in_ecount(6) uint8_t const *addr, 988283514Sarybchik __in efx_filter_flag_t filter_flags) 989283514Sarybchik{ 990293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 991283514Sarybchik efx_filter_spec_t spec; 992291436Sarybchik efx_rc_t rc; 993283514Sarybchik 994283514Sarybchik /* Insert the filter for the local station address */ 995283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 996283514Sarybchik filter_flags, 997293764Sarybchik eftp->eft_default_rxq); 998283514Sarybchik efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, addr); 999283514Sarybchik 1000293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1001299411Sarybchik &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1002299411Sarybchik if (rc != 0) 1003299411Sarybchik goto fail1; 1004283514Sarybchik 1005299411Sarybchik eftp->eft_unicst_filter_count++; 1006299411Sarybchik EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1007299411Sarybchik EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1008299411Sarybchik 1009283514Sarybchik return (0); 1010283514Sarybchik 1011299411Sarybchikfail1: 1012299411Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1013299411Sarybchik return (rc); 1014299411Sarybchik} 1015299411Sarybchik 1016299411Sarybchikstatic __checkReturn efx_rc_t 1017299411Sarybchikef10_filter_insert_all_unicast( 1018299411Sarybchik __in efx_nic_t *enp, 1019299411Sarybchik __in efx_filter_flag_t filter_flags) 1020299411Sarybchik{ 1021299411Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1022299411Sarybchik efx_filter_spec_t spec; 1023299411Sarybchik efx_rc_t rc; 1024299411Sarybchik 1025283514Sarybchik /* Insert the unknown unicast filter */ 1026283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1027283514Sarybchik filter_flags, 1028293764Sarybchik eftp->eft_default_rxq); 1029283514Sarybchik efx_filter_spec_set_uc_def(&spec); 1030293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1031299411Sarybchik &eftp->eft_unicst_filter_indexes[eftp->eft_unicst_filter_count]); 1032283514Sarybchik if (rc != 0) 1033283514Sarybchik goto fail1; 1034283514Sarybchik 1035299411Sarybchik eftp->eft_unicst_filter_count++; 1036299411Sarybchik EFSYS_ASSERT(eftp->eft_unicst_filter_count <= 1037299411Sarybchik EFX_EF10_FILTER_UNICAST_FILTERS_MAX); 1038283514Sarybchik 1039283514Sarybchik return (0); 1040283514Sarybchik 1041283514Sarybchikfail1: 1042291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1043283514Sarybchik return (rc); 1044283514Sarybchik} 1045283514Sarybchik 1046291436Sarybchikstatic __checkReturn efx_rc_t 1047299518Sarybchikef10_filter_insert_multicast_list( 1048283514Sarybchik __in efx_nic_t *enp, 1049283514Sarybchik __in boolean_t mulcst, 1050283514Sarybchik __in boolean_t brdcst, 1051283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1052299410Sarybchik __in uint32_t count, 1053299518Sarybchik __in efx_filter_flag_t filter_flags, 1054299518Sarybchik __in boolean_t rollback) 1055283514Sarybchik{ 1056293764Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1057283514Sarybchik efx_filter_spec_t spec; 1058283514Sarybchik uint8_t addr[6]; 1059299518Sarybchik uint32_t i; 1060299518Sarybchik uint32_t filter_index; 1061299518Sarybchik uint32_t filter_count; 1062291436Sarybchik efx_rc_t rc; 1063283514Sarybchik 1064283514Sarybchik if (mulcst == B_FALSE) 1065283514Sarybchik count = 0; 1066283514Sarybchik 1067283514Sarybchik if (count + (brdcst ? 1 : 0) > 1068293764Sarybchik EFX_ARRAY_SIZE(eftp->eft_mulcst_filter_indexes)) { 1069299518Sarybchik /* Too many MAC addresses */ 1070299518Sarybchik rc = EINVAL; 1071299518Sarybchik goto fail1; 1072283514Sarybchik } 1073283514Sarybchik 1074283514Sarybchik /* Insert/renew multicast address list filters */ 1075299518Sarybchik filter_count = 0; 1076299518Sarybchik for (i = 0; i < count; i++) { 1077283514Sarybchik efx_filter_spec_init_rx(&spec, 1078283514Sarybchik EFX_FILTER_PRI_AUTO, 1079283514Sarybchik filter_flags, 1080293764Sarybchik eftp->eft_default_rxq); 1081283514Sarybchik 1082283514Sarybchik efx_filter_spec_set_eth_local(&spec, 1083283514Sarybchik EFX_FILTER_SPEC_VID_UNSPEC, 1084283514Sarybchik &addrs[i * EFX_MAC_ADDR_LEN]); 1085283514Sarybchik 1086293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1087299518Sarybchik &filter_index); 1088299518Sarybchik 1089299518Sarybchik if (rc == 0) { 1090299518Sarybchik eftp->eft_mulcst_filter_indexes[filter_count] = 1091299518Sarybchik filter_index; 1092299518Sarybchik filter_count++; 1093299518Sarybchik } else if (rollback == B_TRUE) { 1094299518Sarybchik /* Only stop upon failure if told to rollback */ 1095283514Sarybchik goto rollback; 1096283514Sarybchik } 1097299518Sarybchik 1098283514Sarybchik } 1099283514Sarybchik 1100283514Sarybchik if (brdcst == B_TRUE) { 1101283514Sarybchik /* Insert/renew broadcast address filter */ 1102283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1103283514Sarybchik filter_flags, 1104293764Sarybchik eftp->eft_default_rxq); 1105283514Sarybchik 1106283514Sarybchik EFX_MAC_BROADCAST_ADDR_SET(addr); 1107283514Sarybchik efx_filter_spec_set_eth_local(&spec, EFX_FILTER_SPEC_VID_UNSPEC, 1108283514Sarybchik addr); 1109283514Sarybchik 1110293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1111299518Sarybchik &filter_index); 1112299518Sarybchik 1113299518Sarybchik if (rc == 0) { 1114299518Sarybchik eftp->eft_mulcst_filter_indexes[filter_count] = 1115299518Sarybchik filter_index; 1116299518Sarybchik filter_count++; 1117299518Sarybchik } else if (rollback == B_TRUE) { 1118299518Sarybchik /* Only stop upon failure if told to rollback */ 1119283514Sarybchik goto rollback; 1120283514Sarybchik } 1121283514Sarybchik } 1122283514Sarybchik 1123299518Sarybchik eftp->eft_mulcst_filter_count = filter_count; 1124299594Sarybchik eftp->eft_using_all_mulcst = B_FALSE; 1125299518Sarybchik 1126283514Sarybchik return (0); 1127283514Sarybchik 1128283514Sarybchikrollback: 1129299518Sarybchik /* Remove any filters we have inserted */ 1130299518Sarybchik i = filter_count; 1131283514Sarybchik while (i--) { 1132293764Sarybchik (void) ef10_filter_delete_internal(enp, 1133293764Sarybchik eftp->eft_mulcst_filter_indexes[i]); 1134283514Sarybchik } 1135293764Sarybchik eftp->eft_mulcst_filter_count = 0; 1136283514Sarybchik 1137299518Sarybchikfail1: 1138299518Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1139299518Sarybchik 1140299518Sarybchik return (rc); 1141299518Sarybchik} 1142299518Sarybchik 1143299518Sarybchikstatic __checkReturn efx_rc_t 1144299518Sarybchikef10_filter_insert_all_multicast( 1145299518Sarybchik __in efx_nic_t *enp, 1146299518Sarybchik __in efx_filter_flag_t filter_flags) 1147299518Sarybchik{ 1148299518Sarybchik ef10_filter_table_t *eftp = enp->en_filter.ef_ef10_filter_table; 1149299518Sarybchik efx_filter_spec_t spec; 1150299518Sarybchik efx_rc_t rc; 1151299518Sarybchik 1152283514Sarybchik /* Insert the unknown multicast filter */ 1153283514Sarybchik efx_filter_spec_init_rx(&spec, EFX_FILTER_PRI_AUTO, 1154283514Sarybchik filter_flags, 1155293764Sarybchik eftp->eft_default_rxq); 1156283514Sarybchik efx_filter_spec_set_mc_def(&spec); 1157283514Sarybchik 1158293764Sarybchik rc = ef10_filter_add_internal(enp, &spec, B_TRUE, 1159293764Sarybchik &eftp->eft_mulcst_filter_indexes[0]); 1160283514Sarybchik if (rc != 0) 1161283514Sarybchik goto fail1; 1162283514Sarybchik 1163293764Sarybchik eftp->eft_mulcst_filter_count = 1; 1164299594Sarybchik eftp->eft_using_all_mulcst = B_TRUE; 1165283514Sarybchik 1166283514Sarybchik /* 1167283514Sarybchik * FIXME: If brdcst == B_FALSE, add a filter to drop broadcast traffic. 1168283514Sarybchik */ 1169283514Sarybchik 1170283514Sarybchik return (0); 1171283514Sarybchik 1172283514Sarybchikfail1: 1173291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1174283514Sarybchik 1175283514Sarybchik return (rc); 1176283514Sarybchik} 1177283514Sarybchik 1178299594Sarybchikstatic void 1179299594Sarybchikef10_filter_remove_old( 1180299594Sarybchik __in efx_nic_t *enp) 1181299594Sarybchik{ 1182299594Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1183299594Sarybchik uint32_t i; 1184283514Sarybchik 1185299594Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1186299594Sarybchik if (ef10_filter_entry_is_auto_old(table, i)) { 1187299594Sarybchik (void) ef10_filter_delete_internal(enp, i); 1188299594Sarybchik } 1189299594Sarybchik } 1190299594Sarybchik} 1191299594Sarybchik 1192299594Sarybchik 1193291436Sarybchikstatic __checkReturn efx_rc_t 1194283514Sarybchikhunt_filter_get_workarounds( 1195283514Sarybchik __in efx_nic_t *enp) 1196283514Sarybchik{ 1197283514Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1198283514Sarybchik uint32_t implemented = 0; 1199283514Sarybchik uint32_t enabled = 0; 1200291436Sarybchik efx_rc_t rc; 1201283514Sarybchik 1202283514Sarybchik rc = efx_mcdi_get_workarounds(enp, &implemented, &enabled); 1203283514Sarybchik if (rc == 0) { 1204283514Sarybchik /* Check if chained multicast filter support is enabled */ 1205283514Sarybchik if (implemented & enabled & MC_CMD_GET_WORKAROUNDS_OUT_BUG26807) 1206283514Sarybchik encp->enc_bug26807_workaround = B_TRUE; 1207283514Sarybchik else 1208283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1209283514Sarybchik } else if (rc == ENOTSUP) { 1210283514Sarybchik /* 1211283514Sarybchik * Firmware is too old to support GET_WORKAROUNDS, and support 1212283514Sarybchik * for this workaround was implemented later. 1213283514Sarybchik */ 1214283514Sarybchik encp->enc_bug26807_workaround = B_FALSE; 1215283514Sarybchik } else { 1216283514Sarybchik goto fail1; 1217283514Sarybchik } 1218283514Sarybchik 1219283514Sarybchik return (0); 1220283514Sarybchik 1221283514Sarybchikfail1: 1222291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1223283514Sarybchik 1224283514Sarybchik return (rc); 1225283514Sarybchik 1226283514Sarybchik} 1227283514Sarybchik 1228283514Sarybchik 1229283514Sarybchik/* 1230283514Sarybchik * Reconfigure all filters. 1231283514Sarybchik * If all_unicst and/or all mulcst filters cannot be applied then 1232283514Sarybchik * return ENOTSUP (Note the filters for the specified addresses are 1233283514Sarybchik * still applied in this case). 1234283514Sarybchik */ 1235291436Sarybchik __checkReturn efx_rc_t 1236293764Sarybchikef10_filter_reconfigure( 1237283514Sarybchik __in efx_nic_t *enp, 1238283514Sarybchik __in_ecount(6) uint8_t const *mac_addr, 1239283514Sarybchik __in boolean_t all_unicst, 1240283514Sarybchik __in boolean_t mulcst, 1241283514Sarybchik __in boolean_t all_mulcst, 1242283514Sarybchik __in boolean_t brdcst, 1243283514Sarybchik __in_ecount(6*count) uint8_t const *addrs, 1244299410Sarybchik __in uint32_t count) 1245283514Sarybchik{ 1246299594Sarybchik efx_nic_cfg_t *encp = &enp->en_nic_cfg; 1247293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1248283514Sarybchik efx_filter_flag_t filter_flags; 1249283514Sarybchik unsigned i; 1250299518Sarybchik efx_rc_t all_unicst_rc = 0; 1251299518Sarybchik efx_rc_t all_mulcst_rc = 0; 1252291436Sarybchik efx_rc_t rc; 1253283514Sarybchik 1254293764Sarybchik if (table->eft_default_rxq == NULL) { 1255283514Sarybchik /* 1256283514Sarybchik * Filters direct traffic to the default RXQ, and so cannot be 1257283514Sarybchik * inserted until it is available. Any currently configured 1258283514Sarybchik * filters must be removed (ignore errors in case the MC 1259283514Sarybchik * has rebooted, which removes hardware filters). 1260283514Sarybchik */ 1261299411Sarybchik for (i = 0; i < table->eft_unicst_filter_count; i++) { 1262293764Sarybchik (void) ef10_filter_delete_internal(enp, 1263299411Sarybchik table->eft_unicst_filter_indexes[i]); 1264283514Sarybchik } 1265299411Sarybchik table->eft_unicst_filter_count = 0; 1266299411Sarybchik 1267293764Sarybchik for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1268293764Sarybchik (void) ef10_filter_delete_internal(enp, 1269293764Sarybchik table->eft_mulcst_filter_indexes[i]); 1270283514Sarybchik } 1271293764Sarybchik table->eft_mulcst_filter_count = 0; 1272283514Sarybchik 1273283514Sarybchik return (0); 1274283514Sarybchik } 1275283514Sarybchik 1276293764Sarybchik if (table->eft_using_rss) 1277283514Sarybchik filter_flags = EFX_FILTER_FLAG_RX_RSS; 1278283514Sarybchik else 1279283514Sarybchik filter_flags = 0; 1280283514Sarybchik 1281283514Sarybchik /* Mark old filters which may need to be removed */ 1282299411Sarybchik for (i = 0; i < table->eft_unicst_filter_count; i++) { 1283293764Sarybchik ef10_filter_set_entry_auto_old(table, 1284299411Sarybchik table->eft_unicst_filter_indexes[i]); 1285283514Sarybchik } 1286293764Sarybchik for (i = 0; i < table->eft_mulcst_filter_count; i++) { 1287293764Sarybchik ef10_filter_set_entry_auto_old(table, 1288293764Sarybchik table->eft_mulcst_filter_indexes[i]); 1289283514Sarybchik } 1290283514Sarybchik 1291299411Sarybchik /* 1292299411Sarybchik * Insert or renew unicast filters. 1293299411Sarybchik * 1294299411Sarybchik * Frimware does not perform chaining on unicast filters. As traffic is 1295299411Sarybchik * therefore only delivered to the first matching filter, we should 1296299411Sarybchik * always insert the specific filter for our MAC address, to try and 1297299411Sarybchik * ensure we get that traffic. 1298299411Sarybchik * 1299299411Sarybchik * (If the filter for our MAC address has already been inserted by 1300299411Sarybchik * another function, we won't receive traffic sent to us, even if we 1301299411Sarybchik * insert a unicast mismatch filter. To prevent traffic stealing, this 1302299411Sarybchik * therefore relies on the privilege model only allowing functions to 1303299411Sarybchik * insert filters for their own MAC address unless explicitly given 1304299411Sarybchik * additional privileges by the user. This also means that, even on a 1305299411Sarybchik * priviliged function, inserting a unicast mismatch filter may not 1306299411Sarybchik * catch all traffic in multi PCI function scenarios.) 1307299411Sarybchik */ 1308299411Sarybchik table->eft_unicst_filter_count = 0; 1309299411Sarybchik rc = ef10_filter_insert_unicast(enp, mac_addr, filter_flags); 1310299411Sarybchik if (all_unicst || (rc != 0)) { 1311299411Sarybchik all_unicst_rc = ef10_filter_insert_all_unicast(enp, 1312299411Sarybchik filter_flags); 1313299411Sarybchik if ((rc != 0) && (all_unicst_rc != 0)) 1314283514Sarybchik goto fail1; 1315283514Sarybchik } 1316283514Sarybchik 1317283514Sarybchik /* 1318283514Sarybchik * WORKAROUND_BUG26807 controls firmware support for chained multicast 1319283514Sarybchik * filters, and can only be enabled or disabled when the hardware filter 1320283514Sarybchik * table is empty. 1321283514Sarybchik * 1322283514Sarybchik * Firmware will reset (FLR) functions which have inserted filters in 1323283514Sarybchik * the hardware filter table when the workaround is enabled/disabled. 1324283514Sarybchik * Functions without any hardware filters are not reset. 1325283514Sarybchik * 1326283514Sarybchik * Re-check if the workaround is enabled after adding unicast hardware 1327283514Sarybchik * filters. This ensures that encp->enc_workaround_bug26807 matches the 1328283514Sarybchik * firmware state, and that later changes to enable/disable the 1329283514Sarybchik * workaround will result in this function seeing a reset (FLR). 1330293764Sarybchik * 1331299338Sarybchik * FIXME: On Medford multicast chaining should always be on. 1332283514Sarybchik */ 1333283514Sarybchik if ((rc = hunt_filter_get_workarounds(enp)) != 0) 1334299411Sarybchik goto fail2; 1335283514Sarybchik 1336299594Sarybchik if ((table->eft_using_all_mulcst != all_mulcst) && 1337299594Sarybchik (encp->enc_bug26807_workaround == B_TRUE)) { 1338299594Sarybchik /* 1339299594Sarybchik * Multicast filter chaining is enabled, so traffic that matches 1340299594Sarybchik * more than one multicast filter will be replicated and 1341299594Sarybchik * delivered to multiple recipients. To avoid this duplicate 1342299594Sarybchik * delivery, remove old multicast filters before inserting new 1343299594Sarybchik * multicast filters. 1344299594Sarybchik */ 1345299594Sarybchik ef10_filter_remove_old(enp); 1346299594Sarybchik } 1347299594Sarybchik 1348283514Sarybchik /* Insert or renew multicast filters */ 1349299518Sarybchik if (all_mulcst == B_TRUE) { 1350299518Sarybchik /* 1351299518Sarybchik * Insert the all multicast filter. If that fails, try to insert 1352299518Sarybchik * all of our multicast filters (but without rollback on 1353299518Sarybchik * failure). 1354299518Sarybchik */ 1355299518Sarybchik all_mulcst_rc = ef10_filter_insert_all_multicast(enp, 1356299518Sarybchik filter_flags); 1357299518Sarybchik if (all_mulcst_rc != 0) { 1358299518Sarybchik rc = ef10_filter_insert_multicast_list(enp, B_TRUE, 1359299518Sarybchik brdcst, addrs, count, filter_flags, B_FALSE); 1360299518Sarybchik if (rc != 0) 1361299518Sarybchik goto fail3; 1362283514Sarybchik } 1363299518Sarybchik } else { 1364299518Sarybchik /* 1365299518Sarybchik * Insert filters for multicast addresses. 1366299518Sarybchik * If any insertion fails, then rollback and try to insert the 1367299518Sarybchik * all multicast filter instead. 1368299518Sarybchik * If that also fails, try to insert all of the multicast 1369299518Sarybchik * filters (but without rollback on failure). 1370299518Sarybchik */ 1371299518Sarybchik rc = ef10_filter_insert_multicast_list(enp, mulcst, brdcst, 1372299518Sarybchik addrs, count, filter_flags, B_TRUE); 1373299518Sarybchik if (rc != 0) { 1374299594Sarybchik if ((table->eft_using_all_mulcst == B_FALSE) && 1375299594Sarybchik (encp->enc_bug26807_workaround == B_TRUE)) { 1376299594Sarybchik /* 1377299594Sarybchik * Multicast filter chaining is on, so remove 1378299594Sarybchik * old filters before inserting the multicast 1379299594Sarybchik * all filter to avoid duplicate delivery caused 1380299594Sarybchik * by packets matching multiple filters. 1381299594Sarybchik */ 1382299594Sarybchik ef10_filter_remove_old(enp); 1383299594Sarybchik } 1384299594Sarybchik 1385299518Sarybchik rc = ef10_filter_insert_all_multicast(enp, 1386299518Sarybchik filter_flags); 1387299518Sarybchik if (rc != 0) { 1388299518Sarybchik rc = ef10_filter_insert_multicast_list(enp, 1389299518Sarybchik mulcst, brdcst, 1390299518Sarybchik addrs, count, filter_flags, B_FALSE); 1391299518Sarybchik if (rc != 0) 1392299518Sarybchik goto fail4; 1393299518Sarybchik } 1394299518Sarybchik } 1395283514Sarybchik } 1396283514Sarybchik 1397283514Sarybchik /* Remove old filters which were not renewed */ 1398299594Sarybchik ef10_filter_remove_old(enp); 1399283514Sarybchik 1400283514Sarybchik /* report if any optional flags were rejected */ 1401283514Sarybchik if (((all_unicst != B_FALSE) && (all_unicst_rc != 0)) || 1402283514Sarybchik ((all_mulcst != B_FALSE) && (all_mulcst_rc != 0))) { 1403283514Sarybchik rc = ENOTSUP; 1404283514Sarybchik } 1405283514Sarybchik 1406283514Sarybchik return (rc); 1407283514Sarybchik 1408283514Sarybchikfail4: 1409283514Sarybchik EFSYS_PROBE(fail4); 1410283514Sarybchikfail3: 1411283514Sarybchik EFSYS_PROBE(fail3); 1412283514Sarybchikfail2: 1413283514Sarybchik EFSYS_PROBE(fail2); 1414283514Sarybchikfail1: 1415291436Sarybchik EFSYS_PROBE1(fail1, efx_rc_t, rc); 1416283514Sarybchik 1417283514Sarybchik /* Clear auto old flags */ 1418293764Sarybchik for (i = 0; i < EFX_ARRAY_SIZE(table->eft_entry); i++) { 1419293764Sarybchik if (ef10_filter_entry_is_auto_old(table, i)) { 1420293764Sarybchik ef10_filter_set_entry_not_auto_old(table, i); 1421283514Sarybchik } 1422283514Sarybchik } 1423283514Sarybchik 1424283514Sarybchik return (rc); 1425283514Sarybchik} 1426283514Sarybchik 1427283514Sarybchik void 1428293764Sarybchikef10_filter_get_default_rxq( 1429283514Sarybchik __in efx_nic_t *enp, 1430283514Sarybchik __out efx_rxq_t **erpp, 1431283514Sarybchik __out boolean_t *using_rss) 1432283514Sarybchik{ 1433293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1434283514Sarybchik 1435293764Sarybchik *erpp = table->eft_default_rxq; 1436293764Sarybchik *using_rss = table->eft_using_rss; 1437283514Sarybchik} 1438283514Sarybchik 1439283514Sarybchik 1440283514Sarybchik void 1441293764Sarybchikef10_filter_default_rxq_set( 1442283514Sarybchik __in efx_nic_t *enp, 1443283514Sarybchik __in efx_rxq_t *erp, 1444283514Sarybchik __in boolean_t using_rss) 1445283514Sarybchik{ 1446293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1447283514Sarybchik 1448283514Sarybchik#if EFSYS_OPT_RX_SCALE 1449283514Sarybchik EFSYS_ASSERT((using_rss == B_FALSE) || 1450293754Sarybchik (enp->en_rss_context != EF10_RSS_CONTEXT_INVALID)); 1451293764Sarybchik table->eft_using_rss = using_rss; 1452283514Sarybchik#else 1453283514Sarybchik EFSYS_ASSERT(using_rss == B_FALSE); 1454293764Sarybchik table->eft_using_rss = B_FALSE; 1455283514Sarybchik#endif 1456293764Sarybchik table->eft_default_rxq = erp; 1457283514Sarybchik} 1458283514Sarybchik 1459283514Sarybchik void 1460293764Sarybchikef10_filter_default_rxq_clear( 1461283514Sarybchik __in efx_nic_t *enp) 1462283514Sarybchik{ 1463293764Sarybchik ef10_filter_table_t *table = enp->en_filter.ef_ef10_filter_table; 1464283514Sarybchik 1465293764Sarybchik table->eft_default_rxq = NULL; 1466293764Sarybchik table->eft_using_rss = B_FALSE; 1467283514Sarybchik} 1468283514Sarybchik 1469283514Sarybchik 1470283514Sarybchik#endif /* EFSYS_OPT_FILTER */ 1471283514Sarybchik 1472283514Sarybchik#endif /* EFSYS_OPT_HUNTINGTON */ 1473