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