1 /*
   2  * Copyright (c) 2007-2015 Solarflare Communications Inc.
   3  * All rights reserved.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions are met:
   7  *
   8  * 1. Redistributions of source code must retain the above copyright notice,
   9  *    this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright notice,
  11  *    this list of conditions and the following disclaimer in the documentation
  12  *    and/or other materials provided with the distribution.
  13  *
  14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  16  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  17  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  21  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  22  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  23  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  24  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  *
  26  * The views and conclusions contained in the software and documentation are
  27  * those of the authors and should not be interpreted as representing official
  28  * policies, either expressed or implied, of the FreeBSD Project.
  29  */
  30 
  31 #include "efx.h"
  32 #include "efx_impl.h"
  33 
  34 
  35 #if EFSYS_OPT_FILTER
  36 
  37 #if EFSYS_OPT_SIENA
  38 
  39 static  __checkReturn   efx_rc_t
  40 siena_filter_init(
  41         __in            efx_nic_t *enp);
  42 
  43 static                  void
  44 siena_filter_fini(
  45         __in            efx_nic_t *enp);
  46 
  47 static  __checkReturn   efx_rc_t
  48 siena_filter_restore(
  49         __in            efx_nic_t *enp);
  50 
  51 static  __checkReturn   efx_rc_t
  52 siena_filter_add(
  53         __in            efx_nic_t *enp,
  54         __inout         efx_filter_spec_t *spec,
  55         __in            boolean_t may_replace);
  56 
  57 static  __checkReturn   efx_rc_t
  58 siena_filter_delete(
  59         __in            efx_nic_t *enp,
  60         __inout         efx_filter_spec_t *spec);
  61 
  62 static  __checkReturn   efx_rc_t
  63 siena_filter_supported_filters(
  64         __in            efx_nic_t *enp,
  65         __out           uint32_t *list,
  66         __out           size_t *length);
  67 
  68 #endif /* EFSYS_OPT_SIENA */
  69 
  70 #if EFSYS_OPT_SIENA
  71 static const efx_filter_ops_t   __efx_filter_siena_ops = {
  72         siena_filter_init,              /* efo_init */
  73         siena_filter_fini,              /* efo_fini */
  74         siena_filter_restore,           /* efo_restore */
  75         siena_filter_add,               /* efo_add */
  76         siena_filter_delete,            /* efo_delete */
  77         siena_filter_supported_filters, /* efo_supported_filters */
  78         NULL,                           /* efo_reconfigure */
  79 };
  80 #endif /* EFSYS_OPT_SIENA */
  81 
  82 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD
  83 static const efx_filter_ops_t   __efx_filter_ef10_ops = {
  84         ef10_filter_init,               /* efo_init */
  85         ef10_filter_fini,               /* efo_fini */
  86         ef10_filter_restore,            /* efo_restore */
  87         ef10_filter_add,                /* efo_add */
  88         ef10_filter_delete,             /* efo_delete */
  89         ef10_filter_supported_filters,  /* efo_supported_filters */
  90         ef10_filter_reconfigure,        /* efo_reconfigure */
  91 };
  92 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */
  93 
  94         __checkReturn   efx_rc_t
  95 efx_filter_insert(
  96         __in            efx_nic_t *enp,
  97         __inout         efx_filter_spec_t *spec)
  98 {
  99         const efx_filter_ops_t *efop = enp->en_efop;
 100 
 101         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 102         EFSYS_ASSERT3P(spec, !=, NULL);
 103         EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
 104 
 105         return (efop->efo_add(enp, spec, B_FALSE));
 106 }
 107 
 108         __checkReturn   efx_rc_t
 109 efx_filter_remove(
 110         __in            efx_nic_t *enp,
 111         __inout         efx_filter_spec_t *spec)
 112 {
 113         const efx_filter_ops_t *efop = enp->en_efop;
 114 
 115         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 116         EFSYS_ASSERT3P(spec, !=, NULL);
 117         EFSYS_ASSERT3U(spec->efs_flags, &, EFX_FILTER_FLAG_RX);
 118 
 119 #if EFSYS_OPT_RX_SCALE
 120         spec->efs_rss_context = enp->en_rss_context;
 121 #endif
 122 
 123         return (efop->efo_delete(enp, spec));
 124 }
 125 
 126         __checkReturn   efx_rc_t
 127 efx_filter_restore(
 128         __in            efx_nic_t *enp)
 129 {
 130         efx_rc_t rc;
 131 
 132         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 133 
 134         if ((rc = enp->en_efop->efo_restore(enp)) != 0)
 135                 goto fail1;
 136 
 137         return (0);
 138 
 139 fail1:
 140         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 141 
 142         return (rc);
 143 }
 144 
 145         __checkReturn   efx_rc_t
 146 efx_filter_init(
 147         __in            efx_nic_t *enp)
 148 {
 149         const efx_filter_ops_t *efop;
 150         efx_rc_t rc;
 151 
 152         /* Check that efx_filter_spec_t is 64 bytes. */
 153         EFX_STATIC_ASSERT(sizeof (efx_filter_spec_t) == 64);
 154 
 155         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 156         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 157         EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_FILTER));
 158 
 159         switch (enp->en_family) {
 160 #if EFSYS_OPT_SIENA
 161         case EFX_FAMILY_SIENA:
 162                 efop = &__efx_filter_siena_ops;
 163                 break;
 164 #endif /* EFSYS_OPT_SIENA */
 165 
 166 #if EFSYS_OPT_HUNTINGTON
 167         case EFX_FAMILY_HUNTINGTON:
 168                 efop = &__efx_filter_ef10_ops;
 169                 break;
 170 #endif /* EFSYS_OPT_HUNTINGTON */
 171 
 172 #if EFSYS_OPT_MEDFORD
 173         case EFX_FAMILY_MEDFORD:
 174                 efop = &__efx_filter_ef10_ops;
 175                 break;
 176 #endif /* EFSYS_OPT_MEDFORD */
 177 
 178         default:
 179                 EFSYS_ASSERT(0);
 180                 rc = ENOTSUP;
 181                 goto fail1;
 182         }
 183 
 184         if ((rc = efop->efo_init(enp)) != 0)
 185                 goto fail2;
 186 
 187         enp->en_efop = efop;
 188         enp->en_mod_flags |= EFX_MOD_FILTER;
 189         return (0);
 190 
 191 fail2:
 192         EFSYS_PROBE(fail2);
 193 fail1:
 194         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 195 
 196         enp->en_efop = NULL;
 197         enp->en_mod_flags &= ~EFX_MOD_FILTER;
 198         return (rc);
 199 }
 200 
 201                         void
 202 efx_filter_fini(
 203         __in            efx_nic_t *enp)
 204 {
 205         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 206         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 207         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 208 
 209         enp->en_efop->efo_fini(enp);
 210 
 211         enp->en_efop = NULL;
 212         enp->en_mod_flags &= ~EFX_MOD_FILTER;
 213 }
 214 
 215         __checkReturn   efx_rc_t
 216 efx_filter_supported_filters(
 217         __in            efx_nic_t *enp,
 218         __out           uint32_t *list,
 219         __out           size_t *length)
 220 {
 221         efx_rc_t rc;
 222 
 223         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 224         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 225         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 226         EFSYS_ASSERT(enp->en_efop->efo_supported_filters != NULL);
 227 
 228         if ((rc = enp->en_efop->efo_supported_filters(enp, list, length)) != 0)
 229                 goto fail1;
 230 
 231         return (0);
 232 
 233 fail1:
 234         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 235 
 236         return (rc);
 237 }
 238 
 239         __checkReturn   efx_rc_t
 240 efx_filter_reconfigure(
 241         __in                            efx_nic_t *enp,
 242         __in_ecount(6)                  uint8_t const *mac_addr,
 243         __in                            boolean_t all_unicst,
 244         __in                            boolean_t mulcst,
 245         __in                            boolean_t all_mulcst,
 246         __in                            boolean_t brdcst,
 247         __in_ecount(6*count)            uint8_t const *addrs,
 248         __in                            uint32_t count)
 249 {
 250         efx_rc_t rc;
 251 
 252         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
 253         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
 254         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_FILTER);
 255 
 256         if (enp->en_efop->efo_reconfigure != NULL) {
 257                 if ((rc = enp->en_efop->efo_reconfigure(enp, mac_addr,
 258                                                         all_unicst, mulcst,
 259                                                         all_mulcst, brdcst,
 260                                                         addrs, count)) != 0)
 261                         goto fail1;
 262         }
 263 
 264         return (0);
 265 
 266 fail1:
 267         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 268 
 269         return (rc);
 270 }
 271 
 272                 void
 273 efx_filter_spec_init_rx(
 274         __out           efx_filter_spec_t *spec,
 275         __in            efx_filter_priority_t priority,
 276         __in            efx_filter_flag_t flags,
 277         __in            efx_rxq_t *erp)
 278 {
 279         EFSYS_ASSERT3P(spec, !=, NULL);
 280         EFSYS_ASSERT3P(erp, !=, NULL);
 281         EFSYS_ASSERT((flags & ~(EFX_FILTER_FLAG_RX_RSS |
 282                                 EFX_FILTER_FLAG_RX_SCATTER)) == 0);
 283 
 284         (void) memset(spec, 0, sizeof (*spec));
 285         spec->efs_priority = priority;
 286         spec->efs_flags = EFX_FILTER_FLAG_RX | flags;
 287         spec->efs_rss_context = EFX_FILTER_SPEC_RSS_CONTEXT_DEFAULT;
 288         spec->efs_dmaq_id = (uint16_t)erp->er_index;
 289 }
 290 
 291                 void
 292 efx_filter_spec_init_tx(
 293         __out           efx_filter_spec_t *spec,
 294         __in            efx_txq_t *etp)
 295 {
 296         EFSYS_ASSERT3P(spec, !=, NULL);
 297         EFSYS_ASSERT3P(etp, !=, NULL);
 298 
 299         (void) memset(spec, 0, sizeof (*spec));
 300         spec->efs_priority = EFX_FILTER_PRI_REQUIRED;
 301         spec->efs_flags = EFX_FILTER_FLAG_TX;
 302         spec->efs_dmaq_id = (uint16_t)etp->et_index;
 303 }
 304 
 305 
 306 /*
 307  *  Specify IPv4 host, transport protocol and port in a filter specification
 308  */
 309 __checkReturn           efx_rc_t
 310 efx_filter_spec_set_ipv4_local(
 311         __inout         efx_filter_spec_t *spec,
 312         __in            uint8_t proto,
 313         __in            uint32_t host,
 314         __in            uint16_t port)
 315 {
 316         EFSYS_ASSERT3P(spec, !=, NULL);
 317 
 318         spec->efs_match_flags |=
 319                 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
 320                 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
 321         spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
 322         spec->efs_ip_proto = proto;
 323         spec->efs_loc_host.eo_u32[0] = host;
 324         spec->efs_loc_port = port;
 325         return (0);
 326 }
 327 
 328 /*
 329  * Specify IPv4 hosts, transport protocol and ports in a filter specification
 330  */
 331 __checkReturn           efx_rc_t
 332 efx_filter_spec_set_ipv4_full(
 333         __inout         efx_filter_spec_t *spec,
 334         __in            uint8_t proto,
 335         __in            uint32_t lhost,
 336         __in            uint16_t lport,
 337         __in            uint32_t rhost,
 338         __in            uint16_t rport)
 339 {
 340         EFSYS_ASSERT3P(spec, !=, NULL);
 341 
 342         spec->efs_match_flags |=
 343                 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
 344                 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
 345                 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
 346         spec->efs_ether_type = EFX_ETHER_TYPE_IPV4;
 347         spec->efs_ip_proto = proto;
 348         spec->efs_loc_host.eo_u32[0] = lhost;
 349         spec->efs_loc_port = lport;
 350         spec->efs_rem_host.eo_u32[0] = rhost;
 351         spec->efs_rem_port = rport;
 352         return (0);
 353 }
 354 
 355 /*
 356  * Specify local Ethernet address and/or VID in filter specification
 357  */
 358 __checkReturn           efx_rc_t
 359 efx_filter_spec_set_eth_local(
 360         __inout         efx_filter_spec_t *spec,
 361         __in            uint16_t vid,
 362         __in            const uint8_t *addr)
 363 {
 364         EFSYS_ASSERT3P(spec, !=, NULL);
 365         EFSYS_ASSERT3P(addr, !=, NULL);
 366 
 367         if (vid == EFX_FILTER_SPEC_VID_UNSPEC && addr == NULL)
 368                 return (EINVAL);
 369 
 370         if (vid != EFX_FILTER_SPEC_VID_UNSPEC) {
 371                 spec->efs_match_flags |= EFX_FILTER_MATCH_OUTER_VID;
 372                 spec->efs_outer_vid = vid;
 373         }
 374         if (addr != NULL) {
 375                 spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC;
 376                 (void) memcpy(spec->efs_loc_mac, addr, EFX_MAC_ADDR_LEN);
 377         }
 378         return (0);
 379 }
 380 
 381 /*
 382  * Specify matching otherwise-unmatched unicast in a filter specification
 383  */
 384 __checkReturn           efx_rc_t
 385 efx_filter_spec_set_uc_def(
 386         __inout         efx_filter_spec_t *spec)
 387 {
 388         EFSYS_ASSERT3P(spec, !=, NULL);
 389 
 390         spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
 391         return (0);
 392 }
 393 
 394 /*
 395  * Specify matching otherwise-unmatched multicast in a filter specification
 396  */
 397 __checkReturn           efx_rc_t
 398 efx_filter_spec_set_mc_def(
 399         __inout         efx_filter_spec_t *spec)
 400 {
 401         EFSYS_ASSERT3P(spec, !=, NULL);
 402 
 403         spec->efs_match_flags |= EFX_FILTER_MATCH_LOC_MAC_IG;
 404         spec->efs_loc_mac[0] = 1;
 405         return (0);
 406 }
 407 
 408 
 409 
 410 #if EFSYS_OPT_SIENA
 411 
 412 /*
 413  * "Fudge factors" - difference between programmed value and actual depth.
 414  * Due to pipelined implementation we need to program H/W with a value that
 415  * is larger than the hop limit we want.
 416  */
 417 #define FILTER_CTL_SRCH_FUDGE_WILD 3
 418 #define FILTER_CTL_SRCH_FUDGE_FULL 1
 419 
 420 /*
 421  * Hard maximum hop limit.  Hardware will time-out beyond 200-something.
 422  * We also need to avoid infinite loops in efx_filter_search() when the
 423  * table is full.
 424  */
 425 #define FILTER_CTL_SRCH_MAX 200
 426 
 427 static  __checkReturn   efx_rc_t
 428 siena_filter_spec_from_gen_spec(
 429         __out           siena_filter_spec_t *sf_spec,
 430         __in            efx_filter_spec_t *gen_spec)
 431 {
 432         efx_rc_t rc;
 433         boolean_t is_full = B_FALSE;
 434 
 435         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX)
 436                 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX);
 437         else
 438                 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX);
 439 
 440         /* Falconsiena only has one RSS context */
 441         if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) &&
 442             gen_spec->efs_rss_context != 0) {
 443                 rc = EINVAL;
 444                 goto fail1;
 445         }
 446 
 447         sf_spec->sfs_flags = gen_spec->efs_flags;
 448         sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id;
 449 
 450         switch (gen_spec->efs_match_flags) {
 451         case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
 452             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
 453             EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT:
 454                 is_full = B_TRUE;
 455                 /* FALLTHROUGH */
 456         case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
 457             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: {
 458                 uint32_t rhost, host1, host2;
 459                 uint16_t rport, port1, port2;
 460 
 461                 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) {
 462                         rc = ENOTSUP;
 463                         goto fail2;
 464                 }
 465                 if (gen_spec->efs_loc_port == 0 ||
 466                     (is_full && gen_spec->efs_rem_port == 0)) {
 467                         rc = EINVAL;
 468                         goto fail3;
 469                 }
 470                 switch (gen_spec->efs_ip_proto) {
 471                 case EFX_IPPROTO_TCP:
 472                         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
 473                                 sf_spec->sfs_type = (is_full ?
 474                                     EFX_SIENA_FILTER_TX_TCP_FULL :
 475                                     EFX_SIENA_FILTER_TX_TCP_WILD);
 476                         } else {
 477                                 sf_spec->sfs_type = (is_full ?
 478                                     EFX_SIENA_FILTER_RX_TCP_FULL :
 479                                     EFX_SIENA_FILTER_RX_TCP_WILD);
 480                         }
 481                         break;
 482                 case EFX_IPPROTO_UDP:
 483                         if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
 484                                 sf_spec->sfs_type = (is_full ?
 485                                     EFX_SIENA_FILTER_TX_UDP_FULL :
 486                                     EFX_SIENA_FILTER_TX_UDP_WILD);
 487                         } else {
 488                                 sf_spec->sfs_type = (is_full ?
 489                                     EFX_SIENA_FILTER_RX_UDP_FULL :
 490                                     EFX_SIENA_FILTER_RX_UDP_WILD);
 491                         }
 492                         break;
 493                 default:
 494                         rc = ENOTSUP;
 495                         goto fail4;
 496                 }
 497                 /*
 498                  * The filter is constructed in terms of source and destination,
 499                  * with the odd wrinkle that the ports are swapped in a UDP
 500                  * wildcard filter. We need to convert from local and remote
 501                  * addresses (zero for a wildcard).
 502                  */
 503                 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0;
 504                 rport = is_full ? gen_spec->efs_rem_port : 0;
 505                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
 506                         host1 = gen_spec->efs_loc_host.eo_u32[0];
 507                         host2 = rhost;
 508                 } else {
 509                         host1 = rhost;
 510                         host2 = gen_spec->efs_loc_host.eo_u32[0];
 511                 }
 512                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
 513                         if (sf_spec->sfs_type ==
 514                             EFX_SIENA_FILTER_TX_UDP_WILD) {
 515                                 port1 = rport;
 516                                 port2 = gen_spec->efs_loc_port;
 517                         } else {
 518                                 port1 = gen_spec->efs_loc_port;
 519                                 port2 = rport;
 520                         }
 521                 } else {
 522                         if (sf_spec->sfs_type ==
 523                             EFX_SIENA_FILTER_RX_UDP_WILD) {
 524                                 port1 = gen_spec->efs_loc_port;
 525                                 port2 = rport;
 526                         } else {
 527                                 port1 = rport;
 528                                 port2 = gen_spec->efs_loc_port;
 529                         }
 530                 }
 531                 sf_spec->sfs_dword[0] = (host1 << 16) | port1;
 532                 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16);
 533                 sf_spec->sfs_dword[2] = host2;
 534                 break;
 535         }
 536 
 537         case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID:
 538                 is_full = B_TRUE;
 539                 /* FALLTHROUGH */
 540         case EFX_FILTER_MATCH_LOC_MAC:
 541                 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) {
 542                         sf_spec->sfs_type = (is_full ?
 543                             EFX_SIENA_FILTER_TX_MAC_FULL :
 544                             EFX_SIENA_FILTER_TX_MAC_WILD);
 545                 } else {
 546                         sf_spec->sfs_type = (is_full ?
 547                             EFX_SIENA_FILTER_RX_MAC_FULL :
 548                             EFX_SIENA_FILTER_RX_MAC_WILD);
 549                 }
 550                 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0;
 551                 sf_spec->sfs_dword[1] =
 552                     gen_spec->efs_loc_mac[2] << 24 |
 553                     gen_spec->efs_loc_mac[3] << 16 |
 554                     gen_spec->efs_loc_mac[4] <<  8 |
 555                     gen_spec->efs_loc_mac[5];
 556                 sf_spec->sfs_dword[2] =
 557                     gen_spec->efs_loc_mac[0] << 8 |
 558                     gen_spec->efs_loc_mac[1];
 559                 break;
 560 
 561         default:
 562                 EFSYS_ASSERT(B_FALSE);
 563                 rc = ENOTSUP;
 564                 goto fail5;
 565         }
 566 
 567         return (0);
 568 
 569 fail5:
 570         EFSYS_PROBE(fail5);
 571 fail4:
 572         EFSYS_PROBE(fail4);
 573 fail3:
 574         EFSYS_PROBE(fail3);
 575 fail2:
 576         EFSYS_PROBE(fail2);
 577 fail1:
 578         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 579 
 580         return (rc);
 581 }
 582 
 583 /*
 584  * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit
 585  * key derived from the n-tuple.
 586  */
 587 static                  uint16_t
 588 siena_filter_tbl_hash(
 589         __in            uint32_t key)
 590 {
 591         uint16_t tmp;
 592 
 593         /* First 16 rounds */
 594         tmp = 0x1fff ^ (uint16_t)(key >> 16);
 595         tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
 596         tmp = tmp ^ tmp >> 9;
 597 
 598         /* Last 16 rounds */
 599         tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff);
 600         tmp = tmp ^ tmp >> 3 ^ tmp >> 6;
 601         tmp = tmp ^ tmp >> 9;
 602 
 603         return (tmp);
 604 }
 605 
 606 /*
 607  * To allow for hash collisions, filter search continues at these
 608  * increments from the first possible entry selected by the hash.
 609  */
 610 static                  uint16_t
 611 siena_filter_tbl_increment(
 612         __in            uint32_t key)
 613 {
 614         return ((uint16_t)(key * 2 - 1));
 615 }
 616 
 617 static  __checkReturn   boolean_t
 618 siena_filter_test_used(
 619         __in            siena_filter_tbl_t *sftp,
 620         __in            unsigned int index)
 621 {
 622         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
 623         return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0);
 624 }
 625 
 626 static                  void
 627 siena_filter_set_used(
 628         __in            siena_filter_tbl_t *sftp,
 629         __in            unsigned int index)
 630 {
 631         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
 632         sftp->sft_bitmap[index / 32] |= (1 << (index % 32));
 633         ++sftp->sft_used;
 634 }
 635 
 636 static                  void
 637 siena_filter_clear_used(
 638         __in            siena_filter_tbl_t *sftp,
 639         __in            unsigned int index)
 640 {
 641         EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL);
 642         sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32));
 643 
 644         --sftp->sft_used;
 645 }
 646 
 647 
 648 static                  siena_filter_tbl_id_t
 649 siena_filter_tbl_id(
 650         __in            siena_filter_type_t type)
 651 {
 652         siena_filter_tbl_id_t tbl_id;
 653 
 654         switch (type) {
 655         case EFX_SIENA_FILTER_RX_TCP_FULL:
 656         case EFX_SIENA_FILTER_RX_TCP_WILD:
 657         case EFX_SIENA_FILTER_RX_UDP_FULL:
 658         case EFX_SIENA_FILTER_RX_UDP_WILD:
 659                 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP;
 660                 break;
 661 
 662         case EFX_SIENA_FILTER_RX_MAC_FULL:
 663         case EFX_SIENA_FILTER_RX_MAC_WILD:
 664                 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC;
 665                 break;
 666 
 667         case EFX_SIENA_FILTER_TX_TCP_FULL:
 668         case EFX_SIENA_FILTER_TX_TCP_WILD:
 669         case EFX_SIENA_FILTER_TX_UDP_FULL:
 670         case EFX_SIENA_FILTER_TX_UDP_WILD:
 671                 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP;
 672                 break;
 673 
 674         case EFX_SIENA_FILTER_TX_MAC_FULL:
 675         case EFX_SIENA_FILTER_TX_MAC_WILD:
 676                 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC;
 677                 break;
 678 
 679         default:
 680                 EFSYS_ASSERT(B_FALSE);
 681                 tbl_id = EFX_SIENA_FILTER_NTBLS;
 682                 break;
 683         }
 684         return (tbl_id);
 685 }
 686 
 687 static                  void
 688 siena_filter_reset_search_depth(
 689         __inout         siena_filter_t *sfp,
 690         __in            siena_filter_tbl_id_t tbl_id)
 691 {
 692         switch (tbl_id) {
 693         case EFX_SIENA_FILTER_TBL_RX_IP:
 694                 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0;
 695                 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0;
 696                 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0;
 697                 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0;
 698                 break;
 699 
 700         case EFX_SIENA_FILTER_TBL_RX_MAC:
 701                 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0;
 702                 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0;
 703                 break;
 704 
 705         case EFX_SIENA_FILTER_TBL_TX_IP:
 706                 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0;
 707                 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0;
 708                 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0;
 709                 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0;
 710                 break;
 711 
 712         case EFX_SIENA_FILTER_TBL_TX_MAC:
 713                 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0;
 714                 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0;
 715                 break;
 716 
 717         default:
 718                 EFSYS_ASSERT(B_FALSE);
 719                 break;
 720         }
 721 }
 722 
 723 static                  void
 724 siena_filter_push_rx_limits(
 725         __in            efx_nic_t *enp)
 726 {
 727         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
 728         efx_oword_t oword;
 729 
 730         EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
 731 
 732         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT,
 733             sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] +
 734             FILTER_CTL_SRCH_FUDGE_FULL);
 735         EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT,
 736             sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] +
 737             FILTER_CTL_SRCH_FUDGE_WILD);
 738         EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT,
 739             sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] +
 740             FILTER_CTL_SRCH_FUDGE_FULL);
 741         EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT,
 742             sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] +
 743             FILTER_CTL_SRCH_FUDGE_WILD);
 744 
 745         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) {
 746                 EFX_SET_OWORD_FIELD(oword,
 747                     FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT,
 748                     sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] +
 749                     FILTER_CTL_SRCH_FUDGE_FULL);
 750                 EFX_SET_OWORD_FIELD(oword,
 751                     FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT,
 752                     sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] +
 753                     FILTER_CTL_SRCH_FUDGE_WILD);
 754         }
 755 
 756         EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword);
 757 }
 758 
 759 static                  void
 760 siena_filter_push_tx_limits(
 761         __in            efx_nic_t *enp)
 762 {
 763         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
 764         efx_oword_t oword;
 765 
 766         EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword);
 767 
 768         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) {
 769                 EFX_SET_OWORD_FIELD(oword,
 770                     FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE,
 771                     sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] +
 772                     FILTER_CTL_SRCH_FUDGE_FULL);
 773                 EFX_SET_OWORD_FIELD(oword,
 774                     FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE,
 775                     sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] +
 776                     FILTER_CTL_SRCH_FUDGE_WILD);
 777                 EFX_SET_OWORD_FIELD(oword,
 778                     FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE,
 779                     sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] +
 780                     FILTER_CTL_SRCH_FUDGE_FULL);
 781                 EFX_SET_OWORD_FIELD(oword,
 782                     FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE,
 783                     sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] +
 784                     FILTER_CTL_SRCH_FUDGE_WILD);
 785         }
 786 
 787         if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) {
 788                 EFX_SET_OWORD_FIELD(
 789                         oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE,
 790                         sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] +
 791                         FILTER_CTL_SRCH_FUDGE_FULL);
 792                 EFX_SET_OWORD_FIELD(
 793                         oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE,
 794                         sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] +
 795                         FILTER_CTL_SRCH_FUDGE_WILD);
 796         }
 797 
 798         EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword);
 799 }
 800 
 801 /* Build a filter entry and return its n-tuple key. */
 802 static  __checkReturn   uint32_t
 803 siena_filter_build(
 804         __out           efx_oword_t *filter,
 805         __in            siena_filter_spec_t *spec)
 806 {
 807         uint32_t dword3;
 808         uint32_t key;
 809         uint8_t  type  = spec->sfs_type;
 810         uint32_t flags = spec->sfs_flags;
 811 
 812         switch (siena_filter_tbl_id(type)) {
 813         case EFX_SIENA_FILTER_TBL_RX_IP: {
 814                 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL ||
 815                     type == EFX_SIENA_FILTER_RX_UDP_WILD);
 816                 EFX_POPULATE_OWORD_7(*filter,
 817                     FRF_BZ_RSS_EN,
 818                     (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
 819                     FRF_BZ_SCATTER_EN,
 820                     (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
 821                     FRF_AZ_TCP_UDP, is_udp,
 822                     FRF_AZ_RXQ_ID, spec->sfs_dmaq_id,
 823                     EFX_DWORD_2, spec->sfs_dword[2],
 824                     EFX_DWORD_1, spec->sfs_dword[1],
 825                     EFX_DWORD_0, spec->sfs_dword[0]);
 826                 dword3 = is_udp;
 827                 break;
 828         }
 829 
 830         case EFX_SIENA_FILTER_TBL_RX_MAC: {
 831                 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD);
 832                 EFX_POPULATE_OWORD_7(*filter,
 833                     FRF_CZ_RMFT_RSS_EN,
 834                     (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0,
 835                     FRF_CZ_RMFT_SCATTER_EN,
 836                     (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0,
 837                     FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id,
 838                     FRF_CZ_RMFT_WILDCARD_MATCH, is_wild,
 839                     FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2],
 840                     FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1],
 841                     FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]);
 842                 dword3 = is_wild;
 843                 break;
 844         }
 845 
 846         case EFX_SIENA_FILTER_TBL_TX_IP: {
 847                 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL ||
 848                     type == EFX_SIENA_FILTER_TX_UDP_WILD);
 849                 EFX_POPULATE_OWORD_5(*filter,
 850                     FRF_CZ_TIFT_TCP_UDP, is_udp,
 851                     FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id,
 852                     EFX_DWORD_2, spec->sfs_dword[2],
 853                     EFX_DWORD_1, spec->sfs_dword[1],
 854                     EFX_DWORD_0, spec->sfs_dword[0]);
 855                 dword3 = is_udp | spec->sfs_dmaq_id << 1;
 856                 break;
 857         }
 858 
 859         case EFX_SIENA_FILTER_TBL_TX_MAC: {
 860                 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD);
 861                 EFX_POPULATE_OWORD_5(*filter,
 862                     FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id,
 863                     FRF_CZ_TMFT_WILDCARD_MATCH, is_wild,
 864                     FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2],
 865                     FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1],
 866                     FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]);
 867                 dword3 = is_wild | spec->sfs_dmaq_id << 1;
 868                 break;
 869         }
 870 
 871         default:
 872                 EFSYS_ASSERT(B_FALSE);
 873                 return (0);
 874         }
 875 
 876         key =
 877             spec->sfs_dword[0] ^
 878             spec->sfs_dword[1] ^
 879             spec->sfs_dword[2] ^
 880             dword3;
 881 
 882         return (key);
 883 }
 884 
 885 static  __checkReturn           efx_rc_t
 886 siena_filter_push_entry(
 887         __inout                 efx_nic_t *enp,
 888         __in                    siena_filter_type_t type,
 889         __in                    int index,
 890         __in                    efx_oword_t *eop)
 891 {
 892         efx_rc_t rc;
 893 
 894         switch (type) {
 895         case EFX_SIENA_FILTER_RX_TCP_FULL:
 896         case EFX_SIENA_FILTER_RX_TCP_WILD:
 897         case EFX_SIENA_FILTER_RX_UDP_FULL:
 898         case EFX_SIENA_FILTER_RX_UDP_WILD:
 899                 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index,
 900                     eop, B_TRUE);
 901                 break;
 902 
 903         case EFX_SIENA_FILTER_RX_MAC_FULL:
 904         case EFX_SIENA_FILTER_RX_MAC_WILD:
 905                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index,
 906                     eop, B_TRUE);
 907                 break;
 908 
 909         case EFX_SIENA_FILTER_TX_TCP_FULL:
 910         case EFX_SIENA_FILTER_TX_TCP_WILD:
 911         case EFX_SIENA_FILTER_TX_UDP_FULL:
 912         case EFX_SIENA_FILTER_TX_UDP_WILD:
 913                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index,
 914                     eop, B_TRUE);
 915                 break;
 916 
 917         case EFX_SIENA_FILTER_TX_MAC_FULL:
 918         case EFX_SIENA_FILTER_TX_MAC_WILD:
 919                 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index,
 920                     eop, B_TRUE);
 921                 break;
 922 
 923         default:
 924                 EFSYS_ASSERT(B_FALSE);
 925                 rc = ENOTSUP;
 926                 goto fail1;
 927         }
 928         return (0);
 929 
 930 fail1:
 931         return (rc);
 932 }
 933 
 934 
 935 static  __checkReturn   boolean_t
 936 siena_filter_equal(
 937         __in            const siena_filter_spec_t *left,
 938         __in            const siena_filter_spec_t *right)
 939 {
 940         siena_filter_tbl_id_t tbl_id;
 941 
 942         tbl_id = siena_filter_tbl_id(left->sfs_type);
 943 
 944 
 945         if (left->sfs_type != right->sfs_type)
 946                 return (B_FALSE);
 947 
 948         if (memcmp(left->sfs_dword, right->sfs_dword,
 949                 sizeof (left->sfs_dword)))
 950                 return (B_FALSE);
 951 
 952         if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
 953                 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) &&
 954             left->sfs_dmaq_id != right->sfs_dmaq_id)
 955                 return (B_FALSE);
 956 
 957         return (B_TRUE);
 958 }
 959 
 960 static  __checkReturn   efx_rc_t
 961 siena_filter_search(
 962         __in            siena_filter_tbl_t *sftp,
 963         __in            siena_filter_spec_t *spec,
 964         __in            uint32_t key,
 965         __in            boolean_t for_insert,
 966         __out           int *filter_index,
 967         __out           unsigned int *depth_required)
 968 {
 969         unsigned hash, incr, filter_idx, depth;
 970 
 971         hash = siena_filter_tbl_hash(key);
 972         incr = siena_filter_tbl_increment(key);
 973 
 974         filter_idx = hash & (sftp->sft_size - 1);
 975         depth = 1;
 976 
 977         for (;;) {
 978                 /*
 979                  * Return success if entry is used and matches this spec
 980                  * or entry is unused and we are trying to insert.
 981                  */
 982                 if (siena_filter_test_used(sftp, filter_idx) ?
 983                     siena_filter_equal(spec,
 984                     &sftp->sft_spec[filter_idx]) :
 985                     for_insert) {
 986                         *filter_index = filter_idx;
 987                         *depth_required = depth;
 988                         return (0);
 989                 }
 990 
 991                 /* Return failure if we reached the maximum search depth */
 992                 if (depth == FILTER_CTL_SRCH_MAX)
 993                         return (for_insert ? EBUSY : ENOENT);
 994 
 995                 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1);
 996                 ++depth;
 997         }
 998 }
 999 
1000 static                  void
1001 siena_filter_clear_entry(
1002         __in            efx_nic_t *enp,
1003         __in            siena_filter_tbl_t *sftp,
1004         __in            int index)
1005 {
1006         efx_oword_t filter;
1007 
1008         if (siena_filter_test_used(sftp, index)) {
1009                 siena_filter_clear_used(sftp, index);
1010 
1011                 EFX_ZERO_OWORD(filter);
1012                 (void) siena_filter_push_entry(enp,
1013                     sftp->sft_spec[index].sfs_type,
1014                     index, &filter);
1015 
1016                 (void) memset(&sftp->sft_spec[index],
1017                     0, sizeof (sftp->sft_spec[0]));
1018         }
1019 }
1020 
1021                         void
1022 siena_filter_tbl_clear(
1023         __in            efx_nic_t *enp,
1024         __in            siena_filter_tbl_id_t tbl_id)
1025 {
1026         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1027         siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1028         int index;
1029         int state;
1030 
1031         EFSYS_LOCK(enp->en_eslp, state);
1032 
1033         for (index = 0; index < sftp->sft_size; ++index) {
1034                 siena_filter_clear_entry(enp, sftp, index);
1035         }
1036 
1037         if (sftp->sft_used == 0)
1038                 siena_filter_reset_search_depth(sfp, tbl_id);
1039 
1040         EFSYS_UNLOCK(enp->en_eslp, state);
1041 }
1042 
1043 static  __checkReturn   efx_rc_t
1044 siena_filter_init(
1045         __in            efx_nic_t *enp)
1046 {
1047         siena_filter_t *sfp;
1048         siena_filter_tbl_t *sftp;
1049         int tbl_id;
1050         efx_rc_t rc;
1051 
1052         EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp);
1053 
1054         if (!sfp) {
1055                 rc = ENOMEM;
1056                 goto fail1;
1057         }
1058 
1059         enp->en_filter.ef_siena_filter = sfp;
1060 
1061         switch (enp->en_family) {
1062         case EFX_FAMILY_SIENA:
1063                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP];
1064                 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS;
1065 
1066                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC];
1067                 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS;
1068 
1069                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP];
1070                 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS;
1071 
1072                 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC];
1073                 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS;
1074                 break;
1075 
1076         default:
1077                 rc = ENOTSUP;
1078                 goto fail2;
1079         }
1080 
1081         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1082                 unsigned int bitmap_size;
1083 
1084                 sftp = &sfp->sf_tbl[tbl_id];
1085                 if (sftp->sft_size == 0)
1086                         continue;
1087 
1088                 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1089                     sizeof (uint32_t));
1090                 bitmap_size =
1091                     (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1092 
1093                 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap);
1094                 if (!sftp->sft_bitmap) {
1095                         rc = ENOMEM;
1096                         goto fail3;
1097                 }
1098 
1099                 EFSYS_KMEM_ALLOC(enp->en_esip,
1100                     sftp->sft_size * sizeof (*sftp->sft_spec),
1101                     sftp->sft_spec);
1102                 if (!sftp->sft_spec) {
1103                         rc = ENOMEM;
1104                         goto fail4;
1105                 }
1106                 (void) memset(sftp->sft_spec, 0,
1107                     sftp->sft_size * sizeof (*sftp->sft_spec));
1108         }
1109 
1110         return (0);
1111 
1112 fail4:
1113         EFSYS_PROBE(fail4);
1114 
1115 fail3:
1116         EFSYS_PROBE(fail3);
1117 
1118 fail2:
1119         EFSYS_PROBE(fail2);
1120         siena_filter_fini(enp);
1121 
1122 fail1:
1123         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1124         return (rc);
1125 }
1126 
1127 static                  void
1128 siena_filter_fini(
1129         __in            efx_nic_t *enp)
1130 {
1131         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1132         siena_filter_tbl_id_t tbl_id;
1133 
1134         EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
1135         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
1136 
1137         if (sfp == NULL)
1138                 return;
1139 
1140         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1141                 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id];
1142                 unsigned int bitmap_size;
1143 
1144                 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) ==
1145                     sizeof (uint32_t));
1146                 bitmap_size =
1147                     (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8;
1148 
1149                 if (sftp->sft_bitmap != NULL) {
1150                         EFSYS_KMEM_FREE(enp->en_esip, bitmap_size,
1151                             sftp->sft_bitmap);
1152                         sftp->sft_bitmap = NULL;
1153                 }
1154 
1155                 if (sftp->sft_spec != NULL) {
1156                         EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size *
1157                             sizeof (*sftp->sft_spec), sftp->sft_spec);
1158                         sftp->sft_spec = NULL;
1159                 }
1160         }
1161 
1162         EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t),
1163             enp->en_filter.ef_siena_filter);
1164 }
1165 
1166 /* Restore filter state after a reset */
1167 static  __checkReturn   efx_rc_t
1168 siena_filter_restore(
1169         __in            efx_nic_t *enp)
1170 {
1171         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1172         siena_filter_tbl_id_t tbl_id;
1173         siena_filter_tbl_t *sftp;
1174         siena_filter_spec_t *spec;
1175         efx_oword_t filter;
1176         int filter_idx;
1177         int state;
1178         efx_rc_t rc;
1179 
1180         EFSYS_LOCK(enp->en_eslp, state);
1181 
1182         for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) {
1183                 sftp = &sfp->sf_tbl[tbl_id];
1184                 for (filter_idx = 0;
1185                         filter_idx < sftp->sft_size;
1186                         filter_idx++) {
1187                         if (!siena_filter_test_used(sftp, filter_idx))
1188                                 continue;
1189 
1190                         spec = &sftp->sft_spec[filter_idx];
1191                         if ((rc = siena_filter_build(&filter, spec)) != 0)
1192                                 goto fail1;
1193                         if ((rc = siena_filter_push_entry(enp,
1194                                     spec->sfs_type, filter_idx, &filter)) != 0)
1195                                 goto fail2;
1196                 }
1197         }
1198 
1199         siena_filter_push_rx_limits(enp);
1200         siena_filter_push_tx_limits(enp);
1201 
1202         EFSYS_UNLOCK(enp->en_eslp, state);
1203 
1204         return (0);
1205 
1206 fail2:
1207         EFSYS_PROBE(fail2);
1208 
1209 fail1:
1210         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1211 
1212         EFSYS_UNLOCK(enp->en_eslp, state);
1213 
1214         return (rc);
1215 }
1216 
1217 static   __checkReturn  efx_rc_t
1218 siena_filter_add(
1219         __in            efx_nic_t *enp,
1220         __inout         efx_filter_spec_t *spec,
1221         __in            boolean_t may_replace)
1222 {
1223         efx_rc_t rc;
1224         siena_filter_spec_t sf_spec;
1225         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1226         siena_filter_tbl_id_t tbl_id;
1227         siena_filter_tbl_t *sftp;
1228         siena_filter_spec_t *saved_sf_spec;
1229         efx_oword_t filter;
1230         int filter_idx;
1231         unsigned int depth;
1232         int state;
1233         uint32_t key;
1234 
1235 
1236         EFSYS_ASSERT3P(spec, !=, NULL);
1237 
1238         if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1239                 goto fail1;
1240 
1241         tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1242         sftp = &sfp->sf_tbl[tbl_id];
1243 
1244         if (sftp->sft_size == 0) {
1245                 rc = EINVAL;
1246                 goto fail2;
1247         }
1248 
1249         key = siena_filter_build(&filter, &sf_spec);
1250 
1251         EFSYS_LOCK(enp->en_eslp, state);
1252 
1253         rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE,
1254             &filter_idx, &depth);
1255         if (rc != 0)
1256                 goto fail3;
1257 
1258         EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size);
1259         saved_sf_spec = &sftp->sft_spec[filter_idx];
1260 
1261         if (siena_filter_test_used(sftp, filter_idx)) {
1262                 if (may_replace == B_FALSE) {
1263                         rc = EEXIST;
1264                         goto fail4;
1265                 }
1266         }
1267         siena_filter_set_used(sftp, filter_idx);
1268         *saved_sf_spec = sf_spec;
1269 
1270         if (sfp->sf_depth[sf_spec.sfs_type] < depth) {
1271                 sfp->sf_depth[sf_spec.sfs_type] = depth;
1272                 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP ||
1273                     tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC)
1274                         siena_filter_push_tx_limits(enp);
1275                 else
1276                         siena_filter_push_rx_limits(enp);
1277         }
1278 
1279         (void) siena_filter_push_entry(enp, sf_spec.sfs_type,
1280             filter_idx, &filter);
1281 
1282         EFSYS_UNLOCK(enp->en_eslp, state);
1283         return (0);
1284 
1285 fail4:
1286         EFSYS_PROBE(fail4);
1287 
1288 fail3:
1289         EFSYS_UNLOCK(enp->en_eslp, state);
1290         EFSYS_PROBE(fail3);
1291 
1292 fail2:
1293         EFSYS_PROBE(fail2);
1294 
1295 fail1:
1296         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1297         return (rc);
1298 }
1299 
1300 static   __checkReturn  efx_rc_t
1301 siena_filter_delete(
1302         __in            efx_nic_t *enp,
1303         __inout         efx_filter_spec_t *spec)
1304 {
1305         efx_rc_t rc;
1306         siena_filter_spec_t sf_spec;
1307         siena_filter_t *sfp = enp->en_filter.ef_siena_filter;
1308         siena_filter_tbl_id_t tbl_id;
1309         siena_filter_tbl_t *sftp;
1310         efx_oword_t filter;
1311         int filter_idx;
1312         unsigned int depth;
1313         int state;
1314         uint32_t key;
1315 
1316         EFSYS_ASSERT3P(spec, !=, NULL);
1317 
1318         if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0)
1319                 goto fail1;
1320 
1321         tbl_id = siena_filter_tbl_id(sf_spec.sfs_type);
1322         sftp = &sfp->sf_tbl[tbl_id];
1323 
1324         key = siena_filter_build(&filter, &sf_spec);
1325 
1326         EFSYS_LOCK(enp->en_eslp, state);
1327 
1328         rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE,
1329             &filter_idx, &depth);
1330         if (rc != 0)
1331                 goto fail2;
1332 
1333         siena_filter_clear_entry(enp, sftp, filter_idx);
1334         if (sftp->sft_used == 0)
1335                 siena_filter_reset_search_depth(sfp, tbl_id);
1336 
1337         EFSYS_UNLOCK(enp->en_eslp, state);
1338         return (0);
1339 
1340 fail2:
1341         EFSYS_UNLOCK(enp->en_eslp, state);
1342         EFSYS_PROBE(fail2);
1343 
1344 fail1:
1345         EFSYS_PROBE1(fail1, efx_rc_t, rc);
1346         return (rc);
1347 }
1348 
1349 #define MAX_SUPPORTED 4
1350 
1351 static  __checkReturn   efx_rc_t
1352 siena_filter_supported_filters(
1353         __in            efx_nic_t *enp,
1354         __out           uint32_t *list,
1355         __out           size_t *length)
1356 {
1357         int index = 0;
1358         uint32_t rx_matches[MAX_SUPPORTED];
1359         efx_rc_t rc;
1360 
1361         if (list == NULL) {
1362                 rc = EINVAL;
1363                 goto fail1;
1364         }
1365 
1366         rx_matches[index++] =
1367             EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1368             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT |
1369             EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT;
1370 
1371         rx_matches[index++] =
1372             EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO |
1373             EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT;
1374 
1375         if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) {
1376                 rx_matches[index++] =
1377                     EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC;
1378 
1379                 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC;
1380         }
1381 
1382         EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED);
1383 
1384         *length = index;
1385         (void) memcpy(list, rx_matches, *length);
1386 
1387         return (0);
1388 
1389 fail1:
1390 
1391         return (rc);
1392 }
1393 
1394 #undef MAX_SUPPORTED
1395 
1396 #endif /* EFSYS_OPT_SIENA */
1397 
1398 #endif /* EFSYS_OPT_FILTER */