efx_filter.c revision 342486
1210006Srdivacky/*- 2210006Srdivacky * Copyright (c) 2007-2016 Solarflare Communications Inc. 3210006Srdivacky * All rights reserved. 4210006Srdivacky * 5210006Srdivacky * Redistribution and use in source and binary forms, with or without 6210006Srdivacky * modification, are permitted provided that the following conditions are met: 7210006Srdivacky * 8210006Srdivacky * 1. Redistributions of source code must retain the above copyright notice, 9210006Srdivacky * this list of conditions and the following disclaimer. 10210006Srdivacky * 2. Redistributions in binary form must reproduce the above copyright notice, 11210006Srdivacky * this list of conditions and the following disclaimer in the documentation 12210006Srdivacky * and/or other materials provided with the distribution. 13210006Srdivacky * 14210006Srdivacky * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15218893Sdim * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16210006Srdivacky * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17218893Sdim * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18210006Srdivacky * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19218893Sdim * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20210006Srdivacky * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21218893Sdim * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22221345Sdim * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23210006Srdivacky * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24210006Srdivacky * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25221345Sdim * 26210006Srdivacky * The views and conclusions contained in the software and documentation are 27210006Srdivacky * those of the authors and should not be interpreted as representing official 28210006Srdivacky * policies, either expressed or implied, of the FreeBSD Project. 29210006Srdivacky */ 30210006Srdivacky 31210006Srdivacky#include <sys/cdefs.h> 32210006Srdivacky__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/efx_filter.c 342486 2018-12-26 09:41:04Z arybchik $"); 33210006Srdivacky 34210006Srdivacky#include "efx.h" 35210006Srdivacky#include "efx_impl.h" 36221345Sdim 37221345Sdim 38221345Sdim#if EFSYS_OPT_FILTER 39221345Sdim 40221345Sdim#if EFSYS_OPT_SIENA 41221345Sdim 42221345Sdimstatic __checkReturn efx_rc_t 43221345Sdimsiena_filter_init( 44221345Sdim __in efx_nic_t *enp); 45221345Sdim 46221345Sdimstatic void 47221345Sdimsiena_filter_fini( 48210006Srdivacky __in efx_nic_t *enp); 49210006Srdivacky 50221345Sdimstatic __checkReturn efx_rc_t 51221345Sdimsiena_filter_restore( 52221345Sdim __in efx_nic_t *enp); 53221345Sdim 54210006Srdivackystatic __checkReturn efx_rc_t 55221345Sdimsiena_filter_add( 56221345Sdim __in efx_nic_t *enp, 57221345Sdim __inout efx_filter_spec_t *spec, 58221345Sdim __in boolean_t may_replace); 59221345Sdim 60221345Sdimstatic __checkReturn efx_rc_t 61221345Sdimsiena_filter_delete( 62218893Sdim __in efx_nic_t *enp, 63221345Sdim __inout efx_filter_spec_t *spec); 64210006Srdivacky 65221345Sdimstatic __checkReturn efx_rc_t 66221345Sdimsiena_filter_supported_filters( 67221345Sdim __in efx_nic_t *enp, 68221345Sdim __out_ecount(buffer_length) uint32_t *buffer, 69221345Sdim __in size_t buffer_length, 70221345Sdim __out size_t *list_lengthp); 71221345Sdim 72221345Sdim#endif /* EFSYS_OPT_SIENA */ 73221345Sdim 74221345Sdim#if EFSYS_OPT_SIENA 75221345Sdimstatic const efx_filter_ops_t __efx_filter_siena_ops = { 76221345Sdim siena_filter_init, /* efo_init */ 77221345Sdim siena_filter_fini, /* efo_fini */ 78221345Sdim siena_filter_restore, /* efo_restore */ 79221345Sdim siena_filter_add, /* efo_add */ 80221345Sdim siena_filter_delete, /* efo_delete */ 81221345Sdim siena_filter_supported_filters, /* efo_supported_filters */ 82221345Sdim NULL, /* efo_reconfigure */ 83221345Sdim}; 84221345Sdim#endif /* EFSYS_OPT_SIENA */ 85221345Sdim 86221345Sdim#if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 87221345Sdimstatic const efx_filter_ops_t __efx_filter_ef10_ops = { 88221345Sdim ef10_filter_init, /* efo_init */ 89221345Sdim ef10_filter_fini, /* efo_fini */ 90221345Sdim ef10_filter_restore, /* efo_restore */ 91221345Sdim ef10_filter_add, /* efo_add */ 92210006Srdivacky ef10_filter_delete, /* efo_delete */ 93210006Srdivacky ef10_filter_supported_filters, /* efo_supported_filters */ 94210006Srdivacky ef10_filter_reconfigure, /* efo_reconfigure */ 95212904Sdim}; 96212904Sdim#endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 97212904Sdim 98221345Sdim __checkReturn efx_rc_t 99221345Sdimefx_filter_insert( 100221345Sdim __in efx_nic_t *enp, 101221345Sdim __inout efx_filter_spec_t *spec) 102221345Sdim{ 103221345Sdim const efx_filter_ops_t *efop = enp->en_efop; 104221345Sdim 105221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); 106221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 107221345Sdim EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX); 108221345Sdim 109221345Sdim return (efop->efo_add(enp, spec, B_FALSE)); 110210006Srdivacky} 111218893Sdim 112218893Sdim __checkReturn efx_rc_t 113210006Srdivackyefx_filter_remove( 114221345Sdim __in efx_nic_t *enp, 115221345Sdim __inout efx_filter_spec_t *spec) 116221345Sdim{ 117221345Sdim const efx_filter_ops_t *efop = enp->en_efop; 118221345Sdim 119221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); 120221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 121221345Sdim EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX); 122221345Sdim 123221345Sdim#if EFSYS_OPT_RX_SCALE 124221345Sdim spec->efs_rss_context = enp->en_rss_context; 125221345Sdim#endif 126221345Sdim 127221345Sdim return (efop->efo_delete(enp, spec)); 128221345Sdim} 129221345Sdim 130221345Sdim __checkReturn efx_rc_t 131210006Srdivackyefx_filter_restore( 132210006Srdivacky __in efx_nic_t *enp) 133221345Sdim{ 134210006Srdivacky efx_rc_t rc; 135218893Sdim 136218893Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); 137221345Sdim 138221345Sdim if ((rc = enp->en_efop->efo_restore(enp)) != 0) 139221345Sdim goto fail1; 140221345Sdim 141221345Sdim return (0); 142221345Sdim 143221345Sdimfail1: 144210006Srdivacky EFSYS_PROBE1(fail1, efx_rc_t, rc); 145210006Srdivacky 146210006Srdivacky return (rc); 147210006Srdivacky} 148212904Sdim 149212904Sdim __checkReturn efx_rc_t 150212904Sdimefx_filter_init( 151212904Sdim __in efx_nic_t *enp) 152210006Srdivacky{ 153210006Srdivacky const efx_filter_ops_t *efop; 154210006Srdivacky efx_rc_t rc; 155221345Sdim 156221345Sdim EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 157221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 158221345Sdim EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER)); 159221345Sdim 160221345Sdim switch (enp->en_family) { 161221345Sdim#if EFSYS_OPT_SIENA 162221345Sdim case EFX_FAMILY_SIENA: 163221345Sdim efop = &__efx_filter_siena_ops; 164221345Sdim break; 165221345Sdim#endif /* EFSYS_OPT_SIENA */ 166221345Sdim 167221345Sdim#if EFSYS_OPT_HUNTINGTON 168221345Sdim case EFX_FAMILY_HUNTINGTON: 169221345Sdim efop = &__efx_filter_ef10_ops; 170221345Sdim break; 171221345Sdim#endif /* EFSYS_OPT_HUNTINGTON */ 172221345Sdim 173221345Sdim#if EFSYS_OPT_MEDFORD 174221345Sdim case EFX_FAMILY_MEDFORD: 175221345Sdim efop = &__efx_filter_ef10_ops; 176221345Sdim break; 177221345Sdim#endif /* EFSYS_OPT_MEDFORD */ 178221345Sdim 179221345Sdim default: 180221345Sdim EFSYS_ASSERT(0); 181221345Sdim rc = ENOTSUP; 182221345Sdim goto fail1; 183221345Sdim } 184221345Sdim 185221345Sdim if ((rc = efop->efo_init(enp)) != 0) 186221345Sdim goto fail2; 187221345Sdim 188221345Sdim enp->en_efop = efop; 189221345Sdim enp->en_mod_flags |= EFX_MOD_FILTER; 190221345Sdim return (0); 191221345Sdim 192221345Sdimfail2: 193221345Sdim EFSYS_PROBE(fail2); 194221345Sdimfail1: 195221345Sdim EFSYS_PROBE1(fail1, efx_rc_t, rc); 196221345Sdim 197221345Sdim enp->en_efop = NULL; 198221345Sdim enp->en_mod_flags &= ~EFX_MOD_FILTER; 199221345Sdim return (rc); 200221345Sdim} 201221345Sdim 202221345Sdim void 203221345Sdimefx_filter_fini( 204221345Sdim __in efx_nic_t *enp) 205221345Sdim{ 206221345Sdim EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 207221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 208221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); 209221345Sdim 210221345Sdim enp->en_efop->efo_fini(enp); 211221345Sdim 212221345Sdim enp->en_efop = NULL; 213221345Sdim enp->en_mod_flags &= ~EFX_MOD_FILTER; 214221345Sdim} 215221345Sdim 216221345Sdim/* 217221345Sdim * Query the possible combinations of match flags which can be filtered on. 218221345Sdim * These are returned as a list, of which each 32 bit element is a bitmask 219221345Sdim * formed of EFX_FILTER_MATCH flags. 220221345Sdim * 221221345Sdim * The combinations are ordered in priority from highest to lowest. 222221345Sdim * 223221345Sdim * If the provided buffer is too short to hold the list, the call with fail with 224221345Sdim * ENOSPC and *list_lengthp will be set to the buffer length required. 225221345Sdim */ 226221345Sdim __checkReturn efx_rc_t 227221345Sdimefx_filter_supported_filters( 228221345Sdim __in efx_nic_t *enp, 229221345Sdim __out_ecount(buffer_length) uint32_t *buffer, 230221345Sdim __in size_t buffer_length, 231221345Sdim __out size_t *list_lengthp) 232221345Sdim{ 233221345Sdim efx_rc_t rc; 234221345Sdim 235221345Sdim EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 236221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 237221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); 238221345Sdim EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL); 239221345Sdim 240221345Sdim if (buffer == NULL) { 241221345Sdim rc = EINVAL; 242221345Sdim goto fail1; 243221345Sdim } 244221345Sdim 245221345Sdim rc = enp->en_efop->efo_supported_filters(enp, buffer, buffer_length, 246221345Sdim list_lengthp); 247221345Sdim if (rc != 0) 248221345Sdim goto fail2; 249221345Sdim 250221345Sdim return (0); 251221345Sdim 252221345Sdimfail2: 253221345Sdim EFSYS_PROBE(fail2); 254221345Sdimfail1: 255221345Sdim EFSYS_PROBE1(fail1, efx_rc_t, rc); 256221345Sdim 257221345Sdim return (rc); 258221345Sdim} 259221345Sdim 260221345Sdim __checkReturn efx_rc_t 261221345Sdimefx_filter_reconfigure( 262221345Sdim __in efx_nic_t *enp, 263221345Sdim __in_ecount(6) uint8_t const *mac_addr, 264221345Sdim __in boolean_t all_unicst, 265221345Sdim __in boolean_t mulcst, 266221345Sdim __in boolean_t all_mulcst, 267221345Sdim __in boolean_t brdcst, 268221345Sdim __in_ecount(6*count) uint8_t const *addrs, 269221345Sdim __in uint32_t count) 270221345Sdim{ 271221345Sdim efx_rc_t rc; 272221345Sdim 273221345Sdim EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 274221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 275221345Sdim EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER); 276221345Sdim 277221345Sdim if (enp->en_efop->efo_reconfigure != NULL) { 278221345Sdim if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr, 279221345Sdim all_unicst, mulcst, 280221345Sdim all_mulcst, brdcst, 281221345Sdim addrs, count)) != 0) 282221345Sdim goto fail1; 283221345Sdim } 284221345Sdim 285221345Sdim return (0); 286221345Sdim 287221345Sdimfail1: 288221345Sdim EFSYS_PROBE1(fail1, efx_rc_t, rc); 289221345Sdim 290221345Sdim return (rc); 291221345Sdim} 292221345Sdim 293221345Sdim void 294221345Sdimefx_filter_spec_init_rx( 295221345Sdim __out efx_filter_spec_t *spec, 296221345Sdim __in efx_filter_priority_t priority, 297221345Sdim __in efx_filter_flags_t flags, 298221345Sdim __in efx_rxq_t *erp) 299221345Sdim{ 300221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 301221345Sdim EFSYS_ASSERT3P(erp, !=, NULL); 302221345Sdim EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS | 303221345Sdim EFX_FILTER_FLAG_RX_SCATTER)) == 0); 304221345Sdim 305221345Sdim memset(spec, 0, sizeof (*spec)); 306221345Sdim spec->efs_priority = priority; 307221345Sdim spec->efs_flags = EFX_FILTER_FLAG_RX | flags; 308221345Sdim spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT; 309221345Sdim spec->efs_dmaq_id = (uint16_t)erp->er_index; 310221345Sdim} 311221345Sdim 312221345Sdim void 313221345Sdimefx_filter_spec_init_tx( 314221345Sdim __out efx_filter_spec_t *spec, 315221345Sdim __in efx_txq_t *etp) 316221345Sdim{ 317221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 318221345Sdim EFSYS_ASSERT3P(etp, !=, NULL); 319221345Sdim 320221345Sdim memset(spec, 0, sizeof (*spec)); 321221345Sdim spec->efs_priority = EFX_FILTER_PRI_REQUIRED; 322221345Sdim spec->efs_flags = EFX_FILTER_FLAG_TX; 323221345Sdim spec->efs_dmaq_id = (uint16_t)etp->et_index; 324221345Sdim} 325221345Sdim 326221345Sdim 327221345Sdim/* 328221345Sdim * Specify IPv4 host, transport protocol and port in a filter specification 329221345Sdim */ 330221345Sdim__checkReturn efx_rc_t 331221345Sdimefx_filter_spec_set_ipv4_local( 332221345Sdim __inout efx_filter_spec_t *spec, 333221345Sdim __in uint8_t proto, 334221345Sdim __in uint32_t host, 335221345Sdim __in uint16_t port) 336221345Sdim{ 337221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 338221345Sdim 339221345Sdim spec->efs_match_flags |= 340221345Sdim EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 341221345Sdim EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; 342221345Sdim spec->efs_ether_type = EFX_ETHER_TYPE_IPV4; 343221345Sdim spec->efs_ip_proto = proto; 344221345Sdim spec->efs_loc_host.eo_u32[0] = host; 345221345Sdim spec->efs_loc_port = port; 346221345Sdim return (0); 347221345Sdim} 348221345Sdim 349221345Sdim/* 350221345Sdim * Specify IPv4 hosts, transport protocol and ports in a filter specification 351221345Sdim */ 352221345Sdim__checkReturn efx_rc_t 353221345Sdimefx_filter_spec_set_ipv4_full( 354221345Sdim __inout efx_filter_spec_t *spec, 355221345Sdim __in uint8_t proto, 356221345Sdim __in uint32_t lhost, 357221345Sdim __in uint16_t lport, 358221345Sdim __in uint32_t rhost, 359221345Sdim __in uint16_t rport) 360221345Sdim{ 361221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 362221345Sdim 363221345Sdim spec->efs_match_flags |= 364221345Sdim EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 365221345Sdim EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 366221345Sdim EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; 367221345Sdim spec->efs_ether_type = EFX_ETHER_TYPE_IPV4; 368221345Sdim spec->efs_ip_proto = proto; 369221345Sdim spec->efs_loc_host.eo_u32[0] = lhost; 370221345Sdim spec->efs_loc_port = lport; 371221345Sdim spec->efs_rem_host.eo_u32[0] = rhost; 372221345Sdim spec->efs_rem_port = rport; 373221345Sdim return (0); 374221345Sdim} 375221345Sdim 376221345Sdim/* 377221345Sdim * Specify local Ethernet address and/or VID in filter specification 378221345Sdim */ 379221345Sdim__checkReturn efx_rc_t 380221345Sdimefx_filter_spec_set_eth_local( 381221345Sdim __inout efx_filter_spec_t *spec, 382221345Sdim __in uint16_t vid, 383221345Sdim __in const uint8_t *addr) 384221345Sdim{ 385221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 386221345Sdim EFSYS_ASSERT3P(addr, !=, NULL); 387221345Sdim 388221345Sdim if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL) 389221345Sdim return (EINVAL); 390221345Sdim 391221345Sdim if (vid != EFX_FILTER_SPEC_VID_UNSPEC) { 392221345Sdim spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID; 393221345Sdim spec->efs_outer_vid = vid; 394221345Sdim } 395221345Sdim if (addr != NULL) { 396221345Sdim spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC; 397221345Sdim memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN); 398221345Sdim } 399221345Sdim return (0); 400221345Sdim} 401221345Sdim 402221345Sdim void 403221345Sdimefx_filter_spec_set_ether_type( 404221345Sdim __inout efx_filter_spec_t *spec, 405221345Sdim __in uint16_t ether_type) 406221345Sdim{ 407221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 408221345Sdim 409221345Sdim spec->efs_ether_type = ether_type; 410221345Sdim spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE; 411221345Sdim} 412221345Sdim 413221345Sdim/* 414221345Sdim * Specify matching otherwise-unmatched unicast in a filter specification 415221345Sdim */ 416221345Sdim__checkReturn efx_rc_t 417221345Sdimefx_filter_spec_set_uc_def( 418221345Sdim __inout efx_filter_spec_t *spec) 419221345Sdim{ 420221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 421221345Sdim 422221345Sdim spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST; 423221345Sdim return (0); 424221345Sdim} 425221345Sdim 426221345Sdim/* 427221345Sdim * Specify matching otherwise-unmatched multicast in a filter specification 428221345Sdim */ 429221345Sdim__checkReturn efx_rc_t 430221345Sdimefx_filter_spec_set_mc_def( 431221345Sdim __inout efx_filter_spec_t *spec) 432221345Sdim{ 433221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 434221345Sdim 435221345Sdim spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST; 436221345Sdim return (0); 437221345Sdim} 438221345Sdim 439221345Sdim 440221345Sdim__checkReturn efx_rc_t 441221345Sdimefx_filter_spec_set_encap_type( 442221345Sdim __inout efx_filter_spec_t *spec, 443221345Sdim __in efx_tunnel_protocol_t encap_type, 444221345Sdim __in efx_filter_inner_frame_match_t inner_frame_match) 445221345Sdim{ 446221345Sdim uint32_t match_flags = 0; 447221345Sdim uint8_t ip_proto; 448221345Sdim efx_rc_t rc; 449221345Sdim 450221345Sdim EFSYS_ASSERT3P(spec, !=, NULL); 451221345Sdim 452221345Sdim switch (encap_type) { 453221345Sdim case EFX_TUNNEL_PROTOCOL_VXLAN: 454221345Sdim case EFX_TUNNEL_PROTOCOL_GENEVE: 455221345Sdim ip_proto = EFX_IPPROTO_UDP; 456221345Sdim break; 457221345Sdim case EFX_TUNNEL_PROTOCOL_NVGRE: 458221345Sdim ip_proto = EFX_IPPROTO_GRE; 459221345Sdim break; 460221345Sdim default: 461221345Sdim EFSYS_ASSERT(0); 462221345Sdim rc = EINVAL; 463221345Sdim goto fail1; 464221345Sdim } 465221345Sdim 466221345Sdim switch (inner_frame_match) { 467221345Sdim case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST: 468221345Sdim match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST; 469221345Sdim break; 470221345Sdim case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST: 471221345Sdim match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST; 472221345Sdim break; 473221345Sdim case EFX_FILTER_INNER_FRAME_MATCH_OTHER: 474221345Sdim /* This is for when specific inner frames are to be matched. */ 475221345Sdim break; 476221345Sdim default: 477221345Sdim EFSYS_ASSERT(0); 478221345Sdim rc = EINVAL; 479221345Sdim goto fail2; 480221345Sdim } 481221345Sdim 482221345Sdim spec->efs_encap_type = encap_type; 483221345Sdim spec->efs_ip_proto = ip_proto; 484221345Sdim spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO); 485221345Sdim 486221345Sdim return (0); 487221345Sdim 488221345Sdimfail2: 489221345Sdim EFSYS_PROBE(fail2); 490221345Sdimfail1: 491221345Sdim EFSYS_PROBE1(fail1, efx_rc_t, rc); 492221345Sdim 493221345Sdim return (rc); 494221345Sdim} 495221345Sdim 496221345Sdim 497221345Sdim 498221345Sdim#if EFSYS_OPT_SIENA 499221345Sdim 500221345Sdim/* 501221345Sdim * "Fudge factors" - difference between programmed value and actual depth. 502221345Sdim * Due to pipelined implementation we need to program H/W with a value that 503221345Sdim * is larger than the hop limit we want. 504221345Sdim */ 505221345Sdim#define FILTER_CTL_SRCH_FUDGE_WILD 3 506221345Sdim#define FILTER_CTL_SRCH_FUDGE_FULL 1 507221345Sdim 508221345Sdim/* 509221345Sdim * Hard maximum hop limit. Hardware will time-out beyond 200-something. 510221345Sdim * We also need to avoid infinite loops in efx_filter_search() when the 511221345Sdim * table is full. 512221345Sdim */ 513221345Sdim#define FILTER_CTL_SRCH_MAX 200 514221345Sdim 515221345Sdimstatic __checkReturn efx_rc_t 516221345Sdimsiena_filter_spec_from_gen_spec( 517221345Sdim __out siena_filter_spec_t *sf_spec, 518221345Sdim __in efx_filter_spec_t *gen_spec) 519221345Sdim{ 520221345Sdim efx_rc_t rc; 521221345Sdim boolean_t is_full = B_FALSE; 522221345Sdim 523221345Sdim if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) 524221345Sdim EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX); 525221345Sdim else 526221345Sdim EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX); 527221345Sdim 528221345Sdim /* Falconsiena only has one RSS context */ 529221345Sdim if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 530221345Sdim gen_spec->efs_rss_context != 0) { 531221345Sdim rc = EINVAL; 532221345Sdim goto fail1; 533221345Sdim } 534221345Sdim 535221345Sdim sf_spec->sfs_flags = gen_spec->efs_flags; 536221345Sdim sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id; 537221345Sdim 538221345Sdim switch (gen_spec->efs_match_flags) { 539221345Sdim case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 540221345Sdim EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 541221345Sdim EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT: 542221345Sdim is_full = B_TRUE; 543221345Sdim /* Fall through */ 544221345Sdim case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 545221345Sdim EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: { 546221345Sdim uint32_t rhost, host1, host2; 547221345Sdim uint16_t rport, port1, port2; 548221345Sdim 549221345Sdim if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) { 550221345Sdim rc = ENOTSUP; 551221345Sdim goto fail2; 552221345Sdim } 553221345Sdim if (gen_spec->efs_loc_port == 0 || 554221345Sdim (is_full && gen_spec->efs_rem_port == 0)) { 555221345Sdim rc = EINVAL; 556221345Sdim goto fail3; 557221345Sdim } 558221345Sdim switch (gen_spec->efs_ip_proto) { 559221345Sdim case EFX_IPPROTO_TCP: 560221345Sdim if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 561221345Sdim sf_spec->sfs_type = (is_full ? 562221345Sdim EFX_SIENA_FILTER_TX_TCP_FULL : 563221345Sdim EFX_SIENA_FILTER_TX_TCP_WILD); 564221345Sdim } else { 565221345Sdim sf_spec->sfs_type = (is_full ? 566221345Sdim EFX_SIENA_FILTER_RX_TCP_FULL : 567221345Sdim EFX_SIENA_FILTER_RX_TCP_WILD); 568221345Sdim } 569221345Sdim break; 570221345Sdim case EFX_IPPROTO_UDP: 571221345Sdim if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 572221345Sdim sf_spec->sfs_type = (is_full ? 573221345Sdim EFX_SIENA_FILTER_TX_UDP_FULL : 574221345Sdim EFX_SIENA_FILTER_TX_UDP_WILD); 575221345Sdim } else { 576221345Sdim sf_spec->sfs_type = (is_full ? 577221345Sdim EFX_SIENA_FILTER_RX_UDP_FULL : 578221345Sdim EFX_SIENA_FILTER_RX_UDP_WILD); 579221345Sdim } 580221345Sdim break; 581221345Sdim default: 582221345Sdim rc = ENOTSUP; 583221345Sdim goto fail4; 584221345Sdim } 585221345Sdim /* 586221345Sdim * The filter is constructed in terms of source and destination, 587221345Sdim * with the odd wrinkle that the ports are swapped in a UDP 588221345Sdim * wildcard filter. We need to convert from local and remote 589221345Sdim * addresses (zero for a wildcard). 590221345Sdim */ 591221345Sdim rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0; 592221345Sdim rport = is_full ? gen_spec->efs_rem_port : 0; 593219077Sdim if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 594221345Sdim host1 = gen_spec->efs_loc_host.eo_u32[0]; 595221345Sdim host2 = rhost; 596221345Sdim } else { 597221345Sdim host1 = rhost; 598218893Sdim host2 = gen_spec->efs_loc_host.eo_u32[0]; 599221345Sdim } 600210006Srdivacky if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 601210006Srdivacky if (sf_spec->sfs_type == 602210006Srdivacky EFX_SIENA_FILTER_TX_UDP_WILD) { 603221345Sdim port1 = rport; 604210006Srdivacky port2 = gen_spec->efs_loc_port; 605210006Srdivacky } else { 606210006Srdivacky port1 = gen_spec->efs_loc_port; 607210006Srdivacky port2 = rport; 608210006Srdivacky } 609218893Sdim } else { 610221345Sdim if (sf_spec->sfs_type == 611221345Sdim EFX_SIENA_FILTER_RX_UDP_WILD) { 612221345Sdim port1 = gen_spec->efs_loc_port; 613221345Sdim port2 = rport; 614221345Sdim } else { 615221345Sdim port1 = rport; 616221345Sdim port2 = gen_spec->efs_loc_port; 617221345Sdim } 618221345Sdim } 619221345Sdim sf_spec->sfs_dword[0] = (host1 << 16) | port1; 620210006Srdivacky sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16); 621210006Srdivacky sf_spec->sfs_dword[2] = host2; 622210006Srdivacky break; 623210006Srdivacky } 624221345Sdim 625221345Sdim case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID: 626210006Srdivacky is_full = B_TRUE; 627210006Srdivacky /* Fall through */ 628221345Sdim case EFX_FILTER_MATCH_LOC_MAC: 629210006Srdivacky if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 630210006Srdivacky sf_spec->sfs_type = (is_full ? 631210006Srdivacky EFX_SIENA_FILTER_TX_MAC_FULL : 632210006Srdivacky EFX_SIENA_FILTER_TX_MAC_WILD); 633221345Sdim } else { 634210006Srdivacky sf_spec->sfs_type = (is_full ? 635210006Srdivacky EFX_SIENA_FILTER_RX_MAC_FULL : 636210006Srdivacky EFX_SIENA_FILTER_RX_MAC_WILD); 637210006Srdivacky } 638210006Srdivacky sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0; 639210006Srdivacky sf_spec->sfs_dword[1] = 640218893Sdim gen_spec->efs_loc_mac[2] << 24 | 641218893Sdim gen_spec->efs_loc_mac[3] << 16 | 642218893Sdim gen_spec->efs_loc_mac[4] << 8 | 643218893Sdim gen_spec->efs_loc_mac[5]; 644221345Sdim sf_spec->sfs_dword[2] = 645218893Sdim gen_spec->efs_loc_mac[0] << 8 | 646218893Sdim gen_spec->efs_loc_mac[1]; 647218893Sdim break; 648210006Srdivacky 649221345Sdim default: 650210006Srdivacky EFSYS_ASSERT(B_FALSE); 651210006Srdivacky rc = ENOTSUP; 652210006Srdivacky goto fail5; 653221345Sdim } 654221345Sdim 655218893Sdim return (0); 656221345Sdim 657210006Srdivackyfail5: 658210006Srdivacky EFSYS_PROBE(fail5); 659210006Srdivackyfail4: 660210006Srdivacky EFSYS_PROBE(fail4); 661221345Sdimfail3: 662218893Sdim EFSYS_PROBE(fail3); 663210006Srdivackyfail2: 664210006Srdivacky EFSYS_PROBE(fail2); 665210006Srdivackyfail1: 666210006Srdivacky EFSYS_PROBE1(fail1, efx_rc_t, rc); 667210006Srdivacky 668221345Sdim return (rc); 669210006Srdivacky} 670210006Srdivacky 671210006Srdivacky/* 672210006Srdivacky * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit 673210006Srdivacky * key derived from the n-tuple. 674218893Sdim */ 675210006Srdivackystatic uint16_t 676210006Srdivackysiena_filter_tbl_hash( 677221345Sdim __in uint32_t key) 678221345Sdim{ 679218893Sdim uint16_t tmp; 680218893Sdim 681221345Sdim /* First 16 rounds */ 682210006Srdivacky tmp = 0x1fff ^ (uint16_t)(key >> 16); 683221345Sdim tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 684210006Srdivacky tmp = tmp ^ tmp >> 9; 685221345Sdim 686221345Sdim /* Last 16 rounds */ 687221345Sdim tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff); 688221345Sdim tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 689221345Sdim tmp = tmp ^ tmp >> 9; 690221345Sdim 691221345Sdim return (tmp); 692221345Sdim} 693210006Srdivacky 694210006Srdivacky/* 695210006Srdivacky * To allow for hash collisions, filter search continues at these 696210006Srdivacky * increments from the first possible entry selected by the hash. 697221345Sdim */ 698221345Sdimstatic uint16_t 699221345Sdimsiena_filter_tbl_increment( 700221345Sdim __in uint32_t key) 701221345Sdim{ 702221345Sdim return ((uint16_t)(key * 2 - 1)); 703221345Sdim} 704221345Sdim 705221345Sdimstatic __checkReturn boolean_t 706221345Sdimsiena_filter_test_used( 707221345Sdim __in siena_filter_tbl_t *sftp, 708221345Sdim __in unsigned int index) 709221345Sdim{ 710221345Sdim EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 711221345Sdim return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0); 712210006Srdivacky} 713210006Srdivacky 714221345Sdimstatic void 715221345Sdimsiena_filter_set_used( 716221345Sdim __in siena_filter_tbl_t *sftp, 717210006Srdivacky __in unsigned int index) 718221345Sdim{ 719221345Sdim EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 720210006Srdivacky sftp->sft_bitmap[index / 32] |= (1 << (index % 32)); 721221345Sdim ++sftp->sft_used; 722221345Sdim} 723221345Sdim 724221345Sdimstatic void 725221345Sdimsiena_filter_clear_used( 726210006Srdivacky __in siena_filter_tbl_t *sftp, 727210006Srdivacky __in unsigned int index) 728221345Sdim{ 729221345Sdim EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 730221345Sdim sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32)); 731221345Sdim 732221345Sdim --sftp->sft_used; 733210006Srdivacky EFSYS_ASSERT3U(sftp->sft_used, >=, 0); 734221345Sdim} 735210006Srdivacky 736210006Srdivacky 737221345Sdimstatic siena_filter_tbl_id_t 738221345Sdimsiena_filter_tbl_id( 739221345Sdim __in siena_filter_type_t type) 740221345Sdim{ 741221345Sdim siena_filter_tbl_id_t tbl_id; 742221345Sdim 743221345Sdim switch (type) { 744212904Sdim case EFX_SIENA_FILTER_RX_TCP_FULL: 745221345Sdim case EFX_SIENA_FILTER_RX_TCP_WILD: 746221345Sdim case EFX_SIENA_FILTER_RX_UDP_FULL: 747221345Sdim case EFX_SIENA_FILTER_RX_UDP_WILD: 748212904Sdim tbl_id = EFX_SIENA_FILTER_TBL_RX_IP; 749212904Sdim break; 750212904Sdim 751221345Sdim case EFX_SIENA_FILTER_RX_MAC_FULL: 752212904Sdim case EFX_SIENA_FILTER_RX_MAC_WILD: 753212904Sdim tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC; 754212904Sdim break; 755221345Sdim 756212904Sdim case EFX_SIENA_FILTER_TX_TCP_FULL: 757212904Sdim case EFX_SIENA_FILTER_TX_TCP_WILD: 758212904Sdim case EFX_SIENA_FILTER_TX_UDP_FULL: 759212904Sdim case EFX_SIENA_FILTER_TX_UDP_WILD: 760210006Srdivacky tbl_id = EFX_SIENA_FILTER_TBL_TX_IP; 761218893Sdim break; 762218893Sdim 763218893Sdim case EFX_SIENA_FILTER_TX_MAC_FULL: 764218893Sdim case EFX_SIENA_FILTER_TX_MAC_WILD: 765210006Srdivacky tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC; 766218893Sdim break; 767218893Sdim 768210006Srdivacky default: 769210006Srdivacky EFSYS_ASSERT(B_FALSE); 770210006Srdivacky tbl_id = EFX_SIENA_FILTER_NTBLS; 771210006Srdivacky break; 772210006Srdivacky } 773210006Srdivacky return (tbl_id); 774210006Srdivacky} 775210006Srdivacky 776210006Srdivackystatic void 777210006Srdivackysiena_filter_reset_search_depth( 778210006Srdivacky __inout siena_filter_t *sfp, 779218893Sdim __in siena_filter_tbl_id_t tbl_id) 780218893Sdim{ 781218893Sdim switch (tbl_id) { 782210006Srdivacky case EFX_SIENA_FILTER_TBL_RX_IP: 783210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0; 784210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0; 785210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0; 786210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0; 787218893Sdim break; 788221345Sdim 789221345Sdim case EFX_SIENA_FILTER_TBL_RX_MAC: 790210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0; 791210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0; 792221345Sdim break; 793218893Sdim 794221345Sdim case EFX_SIENA_FILTER_TBL_TX_IP: 795210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0; 796210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0; 797210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0; 798210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0; 799210006Srdivacky break; 800210006Srdivacky 801210006Srdivacky case EFX_SIENA_FILTER_TBL_TX_MAC: 802221345Sdim sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0; 803210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0; 804210006Srdivacky break; 805221345Sdim 806221345Sdim default: 807210006Srdivacky EFSYS_ASSERT(B_FALSE); 808221345Sdim break; 809221345Sdim } 810210006Srdivacky} 811218893Sdim 812221345Sdimstatic void 813210006Srdivackysiena_filter_push_rx_limits( 814210006Srdivacky __in efx_nic_t *enp) 815210006Srdivacky{ 816210006Srdivacky siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 817221345Sdim efx_oword_t oword; 818221345Sdim 819210006Srdivacky EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 820221345Sdim 821221345Sdim EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT, 822210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] + 823221345Sdim FILTER_CTL_SRCH_FUDGE_FULL); 824221345Sdim EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT, 825210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] + 826221345Sdim FILTER_CTL_SRCH_FUDGE_WILD); 827210006Srdivacky EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT, 828210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] + 829210006Srdivacky FILTER_CTL_SRCH_FUDGE_FULL); 830221345Sdim EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT, 831221345Sdim sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] + 832221345Sdim FILTER_CTL_SRCH_FUDGE_WILD); 833210006Srdivacky 834221345Sdim if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) { 835221345Sdim EFX_SET_OWORD_FIELD(oword, 836210006Srdivacky FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, 837210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] + 838210006Srdivacky FILTER_CTL_SRCH_FUDGE_FULL); 839210006Srdivacky EFX_SET_OWORD_FIELD(oword, 840210006Srdivacky FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, 841210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] + 842210006Srdivacky FILTER_CTL_SRCH_FUDGE_WILD); 843210006Srdivacky } 844221345Sdim 845210006Srdivacky EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 846210006Srdivacky} 847210006Srdivacky 848210006Srdivackystatic void 849210006Srdivackysiena_filter_push_tx_limits( 850210006Srdivacky __in efx_nic_t *enp) 851210006Srdivacky{ 852210006Srdivacky siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 853210006Srdivacky efx_oword_t oword; 854210006Srdivacky 855210006Srdivacky EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword); 856221345Sdim 857221345Sdim if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) { 858221345Sdim EFX_SET_OWORD_FIELD(oword, 859221345Sdim FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE, 860212904Sdim sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] + 861221345Sdim FILTER_CTL_SRCH_FUDGE_FULL); 862212904Sdim EFX_SET_OWORD_FIELD(oword, 863212904Sdim FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE, 864210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] + 865210006Srdivacky FILTER_CTL_SRCH_FUDGE_WILD); 866210006Srdivacky EFX_SET_OWORD_FIELD(oword, 867221345Sdim FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE, 868210006Srdivacky sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] + 869221345Sdim FILTER_CTL_SRCH_FUDGE_FULL); 870221345Sdim EFX_SET_OWORD_FIELD(oword, 871221345Sdim FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE, 872221345Sdim sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] + 873221345Sdim FILTER_CTL_SRCH_FUDGE_WILD); 874221345Sdim } 875221345Sdim 876221345Sdim if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) { 877221345Sdim EFX_SET_OWORD_FIELD( 878221345Sdim oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, 879221345Sdim sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] + 880221345Sdim FILTER_CTL_SRCH_FUDGE_FULL); 881221345Sdim EFX_SET_OWORD_FIELD( 882221345Sdim oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, 883221345Sdim sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] + 884221345Sdim FILTER_CTL_SRCH_FUDGE_WILD); 885221345Sdim } 886221345Sdim 887221345Sdim EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword); 888221345Sdim} 889221345Sdim 890221345Sdim/* Build a filter entry and return its n-tuple key. */ 891221345Sdimstatic __checkReturn uint32_t 892221345Sdimsiena_filter_build( 893221345Sdim __out efx_oword_t *filter, 894221345Sdim __in siena_filter_spec_t *spec) 895210006Srdivacky{ 896210006Srdivacky uint32_t dword3; 897210006Srdivacky uint32_t key; 898210006Srdivacky uint8_t type = spec->sfs_type; 899210006Srdivacky uint32_t flags = spec->sfs_flags; 900210006Srdivacky 901221345Sdim switch (siena_filter_tbl_id(type)) { 902210006Srdivacky case EFX_SIENA_FILTER_TBL_RX_IP: { 903210006Srdivacky boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL || 904210006Srdivacky type == EFX_SIENA_FILTER_RX_UDP_WILD); 905221345Sdim EFX_POPULATE_OWORD_7(*filter, 906210006Srdivacky FRF_BZ_RSS_EN, 907210006Srdivacky (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 908210006Srdivacky FRF_BZ_SCATTER_EN, 909210006Srdivacky (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 910210006Srdivacky FRF_AZ_TCP_UDP, is_udp, 911218893Sdim FRF_AZ_RXQ_ID, spec->sfs_dmaq_id, 912210006Srdivacky EFX_DWORD_2, spec->sfs_dword[2], 913210006Srdivacky EFX_DWORD_1, spec->sfs_dword[1], 914210006Srdivacky EFX_DWORD_0, spec->sfs_dword[0]); 915210006Srdivacky dword3 = is_udp; 916210006Srdivacky break; 917210006Srdivacky } 918210006Srdivacky 919210006Srdivacky case EFX_SIENA_FILTER_TBL_RX_MAC: { 920221345Sdim boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD); 921210006Srdivacky EFX_POPULATE_OWORD_7(*filter, 922210006Srdivacky FRF_CZ_RMFT_RSS_EN, 923210006Srdivacky (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 924221345Sdim FRF_CZ_RMFT_SCATTER_EN, 925210006Srdivacky (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 926210006Srdivacky FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id, 927210006Srdivacky FRF_CZ_RMFT_WILDCARD_MATCH, is_wild, 928210006Srdivacky FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2], 929221345Sdim FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1], 930221345Sdim FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]); 931221345Sdim dword3 = is_wild; 932221345Sdim break; 933221345Sdim } 934221345Sdim 935221345Sdim case EFX_SIENA_FILTER_TBL_TX_IP: { 936221345Sdim boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL || 937221345Sdim type == EFX_SIENA_FILTER_TX_UDP_WILD); 938221345Sdim EFX_POPULATE_OWORD_5(*filter, 939221345Sdim FRF_CZ_TIFT_TCP_UDP, is_udp, 940221345Sdim FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id, 941221345Sdim EFX_DWORD_2, spec->sfs_dword[2], 942221345Sdim EFX_DWORD_1, spec->sfs_dword[1], 943221345Sdim EFX_DWORD_0, spec->sfs_dword[0]); 944221345Sdim dword3 = is_udp | spec->sfs_dmaq_id << 1; 945221345Sdim break; 946221345Sdim } 947221345Sdim 948221345Sdim case EFX_SIENA_FILTER_TBL_TX_MAC: { 949221345Sdim boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD); 950221345Sdim EFX_POPULATE_OWORD_5(*filter, 951221345Sdim FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id, 952221345Sdim FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, 953221345Sdim FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2], 954221345Sdim FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1], 955221345Sdim FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]); 956221345Sdim dword3 = is_wild | spec->sfs_dmaq_id << 1; 957221345Sdim break; 958221345Sdim } 959221345Sdim 960221345Sdim default: 961221345Sdim EFSYS_ASSERT(B_FALSE); 962221345Sdim return (0); 963221345Sdim } 964221345Sdim 965221345Sdim key = 966221345Sdim spec->sfs_dword[0] ^ 967221345Sdim spec->sfs_dword[1] ^ 968221345Sdim spec->sfs_dword[2] ^ 969221345Sdim dword3; 970221345Sdim 971221345Sdim return (key); 972221345Sdim} 973221345Sdim 974221345Sdimstatic __checkReturn efx_rc_t 975221345Sdimsiena_filter_push_entry( 976221345Sdim __inout efx_nic_t *enp, 977221345Sdim __in siena_filter_type_t type, 978221345Sdim __in int index, 979221345Sdim __in efx_oword_t *eop) 980221345Sdim{ 981221345Sdim efx_rc_t rc; 982221345Sdim 983221345Sdim switch (type) { 984221345Sdim case EFX_SIENA_FILTER_RX_TCP_FULL: 985221345Sdim case EFX_SIENA_FILTER_RX_TCP_WILD: 986221345Sdim case EFX_SIENA_FILTER_RX_UDP_FULL: 987221345Sdim case EFX_SIENA_FILTER_RX_UDP_WILD: 988221345Sdim EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index, 989221345Sdim eop, B_TRUE); 990221345Sdim break; 991221345Sdim 992221345Sdim case EFX_SIENA_FILTER_RX_MAC_FULL: 993221345Sdim case EFX_SIENA_FILTER_RX_MAC_WILD: 994221345Sdim EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index, 995221345Sdim eop, B_TRUE); 996221345Sdim break; 997221345Sdim 998221345Sdim case EFX_SIENA_FILTER_TX_TCP_FULL: 999221345Sdim case EFX_SIENA_FILTER_TX_TCP_WILD: 1000221345Sdim case EFX_SIENA_FILTER_TX_UDP_FULL: 1001 case EFX_SIENA_FILTER_TX_UDP_WILD: 1002 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index, 1003 eop, B_TRUE); 1004 break; 1005 1006 case EFX_SIENA_FILTER_TX_MAC_FULL: 1007 case EFX_SIENA_FILTER_TX_MAC_WILD: 1008 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index, 1009 eop, B_TRUE); 1010 break; 1011 1012 default: 1013 EFSYS_ASSERT(B_FALSE); 1014 rc = ENOTSUP; 1015 goto fail1; 1016 } 1017 return (0); 1018 1019fail1: 1020 return (rc); 1021} 1022 1023 1024static __checkReturn boolean_t 1025siena_filter_equal( 1026 __in const siena_filter_spec_t *left, 1027 __in const siena_filter_spec_t *right) 1028{ 1029 siena_filter_tbl_id_t tbl_id; 1030 1031 tbl_id = siena_filter_tbl_id(left->sfs_type); 1032 1033 1034 if (left->sfs_type != right->sfs_type) 1035 return (B_FALSE); 1036 1037 if (memcmp(left->sfs_dword, right->sfs_dword, 1038 sizeof (left->sfs_dword))) 1039 return (B_FALSE); 1040 1041 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP || 1042 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) && 1043 left->sfs_dmaq_id != right->sfs_dmaq_id) 1044 return (B_FALSE); 1045 1046 return (B_TRUE); 1047} 1048 1049static __checkReturn efx_rc_t 1050siena_filter_search( 1051 __in siena_filter_tbl_t *sftp, 1052 __in siena_filter_spec_t *spec, 1053 __in uint32_t key, 1054 __in boolean_t for_insert, 1055 __out int *filter_index, 1056 __out unsigned int *depth_required) 1057{ 1058 unsigned int hash, incr, filter_idx, depth; 1059 1060 hash = siena_filter_tbl_hash(key); 1061 incr = siena_filter_tbl_increment(key); 1062 1063 filter_idx = hash & (sftp->sft_size - 1); 1064 depth = 1; 1065 1066 for (;;) { 1067 /* 1068 * Return success if entry is used and matches this spec 1069 * or entry is unused and we are trying to insert. 1070 */ 1071 if (siena_filter_test_used(sftp, filter_idx) ? 1072 siena_filter_equal(spec, 1073 &sftp->sft_spec[filter_idx]) : 1074 for_insert) { 1075 *filter_index = filter_idx; 1076 *depth_required = depth; 1077 return (0); 1078 } 1079 1080 /* Return failure if we reached the maximum search depth */ 1081 if (depth == FILTER_CTL_SRCH_MAX) 1082 return (for_insert ? EBUSY : ENOENT); 1083 1084 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1); 1085 ++depth; 1086 } 1087} 1088 1089static void 1090siena_filter_clear_entry( 1091 __in efx_nic_t *enp, 1092 __in siena_filter_tbl_t *sftp, 1093 __in int index) 1094{ 1095 efx_oword_t filter; 1096 1097 if (siena_filter_test_used(sftp, index)) { 1098 siena_filter_clear_used(sftp, index); 1099 1100 EFX_ZERO_OWORD(filter); 1101 siena_filter_push_entry(enp, 1102 sftp->sft_spec[index].sfs_type, 1103 index, &filter); 1104 1105 memset(&sftp->sft_spec[index], 1106 0, sizeof (sftp->sft_spec[0])); 1107 } 1108} 1109 1110 void 1111siena_filter_tbl_clear( 1112 __in efx_nic_t *enp, 1113 __in siena_filter_tbl_id_t tbl_id) 1114{ 1115 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1116 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id]; 1117 int index; 1118 efsys_lock_state_t state; 1119 1120 EFSYS_LOCK(enp->en_eslp, state); 1121 1122 for (index = 0; index < sftp->sft_size; ++index) { 1123 siena_filter_clear_entry(enp, sftp, index); 1124 } 1125 1126 if (sftp->sft_used == 0) 1127 siena_filter_reset_search_depth(sfp, tbl_id); 1128 1129 EFSYS_UNLOCK(enp->en_eslp, state); 1130} 1131 1132static __checkReturn efx_rc_t 1133siena_filter_init( 1134 __in efx_nic_t *enp) 1135{ 1136 siena_filter_t *sfp; 1137 siena_filter_tbl_t *sftp; 1138 int tbl_id; 1139 efx_rc_t rc; 1140 1141 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp); 1142 1143 if (!sfp) { 1144 rc = ENOMEM; 1145 goto fail1; 1146 } 1147 1148 enp->en_filter.ef_siena_filter = sfp; 1149 1150 switch (enp->en_family) { 1151 case EFX_FAMILY_SIENA: 1152 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP]; 1153 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS; 1154 1155 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC]; 1156 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; 1157 1158 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP]; 1159 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS; 1160 1161 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC]; 1162 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS; 1163 break; 1164 1165 default: 1166 rc = ENOTSUP; 1167 goto fail2; 1168 } 1169 1170 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) { 1171 unsigned int bitmap_size; 1172 1173 sftp = &sfp->sf_tbl[tbl_id]; 1174 if (sftp->sft_size == 0) 1175 continue; 1176 1177 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) == 1178 sizeof (uint32_t)); 1179 bitmap_size = 1180 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8; 1181 1182 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap); 1183 if (!sftp->sft_bitmap) { 1184 rc = ENOMEM; 1185 goto fail3; 1186 } 1187 1188 EFSYS_KMEM_ALLOC(enp->en_esip, 1189 sftp->sft_size * sizeof (*sftp->sft_spec), 1190 sftp->sft_spec); 1191 if (!sftp->sft_spec) { 1192 rc = ENOMEM; 1193 goto fail4; 1194 } 1195 memset(sftp->sft_spec, 0, 1196 sftp->sft_size * sizeof (*sftp->sft_spec)); 1197 } 1198 1199 return (0); 1200 1201fail4: 1202 EFSYS_PROBE(fail4); 1203 1204fail3: 1205 EFSYS_PROBE(fail3); 1206 1207fail2: 1208 EFSYS_PROBE(fail2); 1209 siena_filter_fini(enp); 1210 1211fail1: 1212 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1213 return (rc); 1214} 1215 1216static void 1217siena_filter_fini( 1218 __in efx_nic_t *enp) 1219{ 1220 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1221 siena_filter_tbl_id_t tbl_id; 1222 1223 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1224 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 1225 1226 if (sfp == NULL) 1227 return; 1228 1229 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) { 1230 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id]; 1231 unsigned int bitmap_size; 1232 1233 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) == 1234 sizeof (uint32_t)); 1235 bitmap_size = 1236 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8; 1237 1238 if (sftp->sft_bitmap != NULL) { 1239 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size, 1240 sftp->sft_bitmap); 1241 sftp->sft_bitmap = NULL; 1242 } 1243 1244 if (sftp->sft_spec != NULL) { 1245 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size * 1246 sizeof (*sftp->sft_spec), sftp->sft_spec); 1247 sftp->sft_spec = NULL; 1248 } 1249 } 1250 1251 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t), 1252 enp->en_filter.ef_siena_filter); 1253} 1254 1255/* Restore filter state after a reset */ 1256static __checkReturn efx_rc_t 1257siena_filter_restore( 1258 __in efx_nic_t *enp) 1259{ 1260 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1261 siena_filter_tbl_id_t tbl_id; 1262 siena_filter_tbl_t *sftp; 1263 siena_filter_spec_t *spec; 1264 efx_oword_t filter; 1265 int filter_idx; 1266 efsys_lock_state_t state; 1267 uint32_t key; 1268 efx_rc_t rc; 1269 1270 EFSYS_LOCK(enp->en_eslp, state); 1271 1272 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) { 1273 sftp = &sfp->sf_tbl[tbl_id]; 1274 for (filter_idx = 0; 1275 filter_idx < sftp->sft_size; 1276 filter_idx++) { 1277 if (!siena_filter_test_used(sftp, filter_idx)) 1278 continue; 1279 1280 spec = &sftp->sft_spec[filter_idx]; 1281 if ((key = siena_filter_build(&filter, spec)) == 0) { 1282 rc = EINVAL; 1283 goto fail1; 1284 } 1285 if ((rc = siena_filter_push_entry(enp, 1286 spec->sfs_type, filter_idx, &filter)) != 0) 1287 goto fail2; 1288 } 1289 } 1290 1291 siena_filter_push_rx_limits(enp); 1292 siena_filter_push_tx_limits(enp); 1293 1294 EFSYS_UNLOCK(enp->en_eslp, state); 1295 1296 return (0); 1297 1298fail2: 1299 EFSYS_PROBE(fail2); 1300 1301fail1: 1302 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1303 1304 EFSYS_UNLOCK(enp->en_eslp, state); 1305 1306 return (rc); 1307} 1308 1309static __checkReturn efx_rc_t 1310siena_filter_add( 1311 __in efx_nic_t *enp, 1312 __inout efx_filter_spec_t *spec, 1313 __in boolean_t may_replace) 1314{ 1315 efx_rc_t rc; 1316 siena_filter_spec_t sf_spec; 1317 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1318 siena_filter_tbl_id_t tbl_id; 1319 siena_filter_tbl_t *sftp; 1320 siena_filter_spec_t *saved_sf_spec; 1321 efx_oword_t filter; 1322 int filter_idx; 1323 unsigned int depth; 1324 efsys_lock_state_t state; 1325 uint32_t key; 1326 1327 1328 EFSYS_ASSERT3P(spec, !=, NULL); 1329 1330 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0) 1331 goto fail1; 1332 1333 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type); 1334 sftp = &sfp->sf_tbl[tbl_id]; 1335 1336 if (sftp->sft_size == 0) { 1337 rc = EINVAL; 1338 goto fail2; 1339 } 1340 1341 key = siena_filter_build(&filter, &sf_spec); 1342 1343 EFSYS_LOCK(enp->en_eslp, state); 1344 1345 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE, 1346 &filter_idx, &depth); 1347 if (rc != 0) 1348 goto fail3; 1349 1350 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size); 1351 saved_sf_spec = &sftp->sft_spec[filter_idx]; 1352 1353 if (siena_filter_test_used(sftp, filter_idx)) { 1354 if (may_replace == B_FALSE) { 1355 rc = EEXIST; 1356 goto fail4; 1357 } 1358 } 1359 siena_filter_set_used(sftp, filter_idx); 1360 *saved_sf_spec = sf_spec; 1361 1362 if (sfp->sf_depth[sf_spec.sfs_type] < depth) { 1363 sfp->sf_depth[sf_spec.sfs_type] = depth; 1364 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP || 1365 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) 1366 siena_filter_push_tx_limits(enp); 1367 else 1368 siena_filter_push_rx_limits(enp); 1369 } 1370 1371 siena_filter_push_entry(enp, sf_spec.sfs_type, 1372 filter_idx, &filter); 1373 1374 EFSYS_UNLOCK(enp->en_eslp, state); 1375 return (0); 1376 1377fail4: 1378 EFSYS_PROBE(fail4); 1379 1380fail3: 1381 EFSYS_UNLOCK(enp->en_eslp, state); 1382 EFSYS_PROBE(fail3); 1383 1384fail2: 1385 EFSYS_PROBE(fail2); 1386 1387fail1: 1388 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1389 return (rc); 1390} 1391 1392static __checkReturn efx_rc_t 1393siena_filter_delete( 1394 __in efx_nic_t *enp, 1395 __inout efx_filter_spec_t *spec) 1396{ 1397 efx_rc_t rc; 1398 siena_filter_spec_t sf_spec; 1399 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1400 siena_filter_tbl_id_t tbl_id; 1401 siena_filter_tbl_t *sftp; 1402 efx_oword_t filter; 1403 int filter_idx; 1404 unsigned int depth; 1405 efsys_lock_state_t state; 1406 uint32_t key; 1407 1408 EFSYS_ASSERT3P(spec, !=, NULL); 1409 1410 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0) 1411 goto fail1; 1412 1413 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type); 1414 sftp = &sfp->sf_tbl[tbl_id]; 1415 1416 key = siena_filter_build(&filter, &sf_spec); 1417 1418 EFSYS_LOCK(enp->en_eslp, state); 1419 1420 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE, 1421 &filter_idx, &depth); 1422 if (rc != 0) 1423 goto fail2; 1424 1425 siena_filter_clear_entry(enp, sftp, filter_idx); 1426 if (sftp->sft_used == 0) 1427 siena_filter_reset_search_depth(sfp, tbl_id); 1428 1429 EFSYS_UNLOCK(enp->en_eslp, state); 1430 return (0); 1431 1432fail2: 1433 EFSYS_UNLOCK(enp->en_eslp, state); 1434 EFSYS_PROBE(fail2); 1435 1436fail1: 1437 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1438 return (rc); 1439} 1440 1441#define SIENA_MAX_SUPPORTED_MATCHES 4 1442 1443static __checkReturn efx_rc_t 1444siena_filter_supported_filters( 1445 __in efx_nic_t *enp, 1446 __out_ecount(buffer_length) uint32_t *buffer, 1447 __in size_t buffer_length, 1448 __out size_t *list_lengthp) 1449{ 1450 uint32_t index = 0; 1451 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES]; 1452 size_t list_length; 1453 efx_rc_t rc; 1454 1455 rx_matches[index++] = 1456 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1457 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 1458 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; 1459 1460 rx_matches[index++] = 1461 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1462 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; 1463 1464 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) { 1465 rx_matches[index++] = 1466 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC; 1467 1468 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC; 1469 } 1470 1471 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES); 1472 list_length = index; 1473 1474 *list_lengthp = list_length; 1475 1476 if (buffer_length < list_length) { 1477 rc = ENOSPC; 1478 goto fail1; 1479 } 1480 1481 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0])); 1482 1483 return (0); 1484 1485fail1: 1486 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1487 1488 return (rc); 1489} 1490 1491#undef MAX_SUPPORTED 1492 1493#endif /* EFSYS_OPT_SIENA */ 1494 1495#endif /* EFSYS_OPT_FILTER */ 1496