efx_filter.c revision 311493
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 311493 2017-01-06 07:28:43Z 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 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 191fail2: 192 EFSYS_PROBE(fail2); 193fail1: 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 202efx_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 216efx_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 233fail1: 234 EFSYS_PROBE1(fail1, efx_rc_t, rc); 235 236 return (rc); 237} 238 239 __checkReturn efx_rc_t 240efx_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 266fail1: 267 EFSYS_PROBE1(fail1, efx_rc_t, rc); 268 269 return (rc); 270} 271 272 void 273efx_filter_spec_init_rx( 274 __out efx_filter_spec_t *spec, 275 __in efx_filter_priority_t priority, 276 __in efx_filter_flags_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 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 292efx_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 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 310efx_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 332efx_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 359efx_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 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 385efx_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_UNKNOWN_UCAST_DST; 391 return (0); 392} 393 394/* 395 * Specify matching otherwise-unmatched multicast in a filter specification 396 */ 397__checkReturn efx_rc_t 398efx_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_UNKNOWN_MCAST_DST; 404 return (0); 405} 406 407 408 409#if EFSYS_OPT_SIENA 410 411/* 412 * "Fudge factors" - difference between programmed value and actual depth. 413 * Due to pipelined implementation we need to program H/W with a value that 414 * is larger than the hop limit we want. 415 */ 416#define FILTER_CTL_SRCH_FUDGE_WILD 3 417#define FILTER_CTL_SRCH_FUDGE_FULL 1 418 419/* 420 * Hard maximum hop limit. Hardware will time-out beyond 200-something. 421 * We also need to avoid infinite loops in efx_filter_search() when the 422 * table is full. 423 */ 424#define FILTER_CTL_SRCH_MAX 200 425 426static __checkReturn efx_rc_t 427siena_filter_spec_from_gen_spec( 428 __out siena_filter_spec_t *sf_spec, 429 __in efx_filter_spec_t *gen_spec) 430{ 431 efx_rc_t rc; 432 boolean_t is_full = B_FALSE; 433 434 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) 435 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX); 436 else 437 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX); 438 439 /* Falconsiena only has one RSS context */ 440 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 441 gen_spec->efs_rss_context != 0) { 442 rc = EINVAL; 443 goto fail1; 444 } 445 446 sf_spec->sfs_flags = gen_spec->efs_flags; 447 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id; 448 449 switch (gen_spec->efs_match_flags) { 450 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 451 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 452 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT: 453 is_full = B_TRUE; 454 /* Fall through */ 455 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 456 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: { 457 uint32_t rhost, host1, host2; 458 uint16_t rport, port1, port2; 459 460 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) { 461 rc = ENOTSUP; 462 goto fail2; 463 } 464 if (gen_spec->efs_loc_port == 0 || 465 (is_full && gen_spec->efs_rem_port == 0)) { 466 rc = EINVAL; 467 goto fail3; 468 } 469 switch (gen_spec->efs_ip_proto) { 470 case EFX_IPPROTO_TCP: 471 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 472 sf_spec->sfs_type = (is_full ? 473 EFX_SIENA_FILTER_TX_TCP_FULL : 474 EFX_SIENA_FILTER_TX_TCP_WILD); 475 } else { 476 sf_spec->sfs_type = (is_full ? 477 EFX_SIENA_FILTER_RX_TCP_FULL : 478 EFX_SIENA_FILTER_RX_TCP_WILD); 479 } 480 break; 481 case EFX_IPPROTO_UDP: 482 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 483 sf_spec->sfs_type = (is_full ? 484 EFX_SIENA_FILTER_TX_UDP_FULL : 485 EFX_SIENA_FILTER_TX_UDP_WILD); 486 } else { 487 sf_spec->sfs_type = (is_full ? 488 EFX_SIENA_FILTER_RX_UDP_FULL : 489 EFX_SIENA_FILTER_RX_UDP_WILD); 490 } 491 break; 492 default: 493 rc = ENOTSUP; 494 goto fail4; 495 } 496 /* 497 * The filter is constructed in terms of source and destination, 498 * with the odd wrinkle that the ports are swapped in a UDP 499 * wildcard filter. We need to convert from local and remote 500 * addresses (zero for a wildcard). 501 */ 502 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0; 503 rport = is_full ? gen_spec->efs_rem_port : 0; 504 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 505 host1 = gen_spec->efs_loc_host.eo_u32[0]; 506 host2 = rhost; 507 } else { 508 host1 = rhost; 509 host2 = gen_spec->efs_loc_host.eo_u32[0]; 510 } 511 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 512 if (sf_spec->sfs_type == 513 EFX_SIENA_FILTER_TX_UDP_WILD) { 514 port1 = rport; 515 port2 = gen_spec->efs_loc_port; 516 } else { 517 port1 = gen_spec->efs_loc_port; 518 port2 = rport; 519 } 520 } else { 521 if (sf_spec->sfs_type == 522 EFX_SIENA_FILTER_RX_UDP_WILD) { 523 port1 = gen_spec->efs_loc_port; 524 port2 = rport; 525 } else { 526 port1 = rport; 527 port2 = gen_spec->efs_loc_port; 528 } 529 } 530 sf_spec->sfs_dword[0] = (host1 << 16) | port1; 531 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16); 532 sf_spec->sfs_dword[2] = host2; 533 break; 534 } 535 536 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID: 537 is_full = B_TRUE; 538 /* Fall through */ 539 case EFX_FILTER_MATCH_LOC_MAC: 540 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 541 sf_spec->sfs_type = (is_full ? 542 EFX_SIENA_FILTER_TX_MAC_FULL : 543 EFX_SIENA_FILTER_TX_MAC_WILD); 544 } else { 545 sf_spec->sfs_type = (is_full ? 546 EFX_SIENA_FILTER_RX_MAC_FULL : 547 EFX_SIENA_FILTER_RX_MAC_WILD); 548 } 549 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0; 550 sf_spec->sfs_dword[1] = 551 gen_spec->efs_loc_mac[2] << 24 | 552 gen_spec->efs_loc_mac[3] << 16 | 553 gen_spec->efs_loc_mac[4] << 8 | 554 gen_spec->efs_loc_mac[5]; 555 sf_spec->sfs_dword[2] = 556 gen_spec->efs_loc_mac[0] << 8 | 557 gen_spec->efs_loc_mac[1]; 558 break; 559 560 default: 561 EFSYS_ASSERT(B_FALSE); 562 rc = ENOTSUP; 563 goto fail5; 564 } 565 566 return (0); 567 568fail5: 569 EFSYS_PROBE(fail5); 570fail4: 571 EFSYS_PROBE(fail4); 572fail3: 573 EFSYS_PROBE(fail3); 574fail2: 575 EFSYS_PROBE(fail2); 576fail1: 577 EFSYS_PROBE1(fail1, efx_rc_t, rc); 578 579 return (rc); 580} 581 582/* 583 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit 584 * key derived from the n-tuple. 585 */ 586static uint16_t 587siena_filter_tbl_hash( 588 __in uint32_t key) 589{ 590 uint16_t tmp; 591 592 /* First 16 rounds */ 593 tmp = 0x1fff ^ (uint16_t)(key >> 16); 594 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 595 tmp = tmp ^ tmp >> 9; 596 597 /* Last 16 rounds */ 598 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff); 599 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 600 tmp = tmp ^ tmp >> 9; 601 602 return (tmp); 603} 604 605/* 606 * To allow for hash collisions, filter search continues at these 607 * increments from the first possible entry selected by the hash. 608 */ 609static uint16_t 610siena_filter_tbl_increment( 611 __in uint32_t key) 612{ 613 return ((uint16_t)(key * 2 - 1)); 614} 615 616static __checkReturn boolean_t 617siena_filter_test_used( 618 __in siena_filter_tbl_t *sftp, 619 __in unsigned int index) 620{ 621 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 622 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0); 623} 624 625static void 626siena_filter_set_used( 627 __in siena_filter_tbl_t *sftp, 628 __in unsigned int index) 629{ 630 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 631 sftp->sft_bitmap[index / 32] |= (1 << (index % 32)); 632 ++sftp->sft_used; 633} 634 635static void 636siena_filter_clear_used( 637 __in siena_filter_tbl_t *sftp, 638 __in unsigned int index) 639{ 640 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 641 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32)); 642 643 --sftp->sft_used; 644 EFSYS_ASSERT3U(sftp->sft_used, >=, 0); 645} 646 647 648static siena_filter_tbl_id_t 649siena_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 687static void 688siena_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 723static void 724siena_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 759static void 760siena_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. */ 802static __checkReturn uint32_t 803siena_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 885static __checkReturn efx_rc_t 886siena_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 930fail1: 931 return (rc); 932} 933 934 935static __checkReturn boolean_t 936siena_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 960static __checkReturn efx_rc_t 961siena_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 int 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 1000static void 1001siena_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 siena_filter_push_entry(enp, 1013 sftp->sft_spec[index].sfs_type, 1014 index, &filter); 1015 1016 memset(&sftp->sft_spec[index], 1017 0, sizeof (sftp->sft_spec[0])); 1018 } 1019} 1020 1021 void 1022siena_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 efsys_lock_state_t 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 1043static __checkReturn efx_rc_t 1044siena_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 memset(sftp->sft_spec, 0, 1107 sftp->sft_size * sizeof (*sftp->sft_spec)); 1108 } 1109 1110 return (0); 1111 1112fail4: 1113 EFSYS_PROBE(fail4); 1114 1115fail3: 1116 EFSYS_PROBE(fail3); 1117 1118fail2: 1119 EFSYS_PROBE(fail2); 1120 siena_filter_fini(enp); 1121 1122fail1: 1123 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1124 return (rc); 1125} 1126 1127static void 1128siena_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 */ 1167static __checkReturn efx_rc_t 1168siena_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 efsys_lock_state_t state; 1178 uint32_t key; 1179 efx_rc_t rc; 1180 1181 EFSYS_LOCK(enp->en_eslp, state); 1182 1183 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) { 1184 sftp = &sfp->sf_tbl[tbl_id]; 1185 for (filter_idx = 0; 1186 filter_idx < sftp->sft_size; 1187 filter_idx++) { 1188 if (!siena_filter_test_used(sftp, filter_idx)) 1189 continue; 1190 1191 spec = &sftp->sft_spec[filter_idx]; 1192 if ((key = siena_filter_build(&filter, spec)) == 0) { 1193 rc = EINVAL; 1194 goto fail1; 1195 } 1196 if ((rc = siena_filter_push_entry(enp, 1197 spec->sfs_type, filter_idx, &filter)) != 0) 1198 goto fail2; 1199 } 1200 } 1201 1202 siena_filter_push_rx_limits(enp); 1203 siena_filter_push_tx_limits(enp); 1204 1205 EFSYS_UNLOCK(enp->en_eslp, state); 1206 1207 return (0); 1208 1209fail2: 1210 EFSYS_PROBE(fail2); 1211 1212fail1: 1213 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1214 1215 EFSYS_UNLOCK(enp->en_eslp, state); 1216 1217 return (rc); 1218} 1219 1220static __checkReturn efx_rc_t 1221siena_filter_add( 1222 __in efx_nic_t *enp, 1223 __inout efx_filter_spec_t *spec, 1224 __in boolean_t may_replace) 1225{ 1226 efx_rc_t rc; 1227 siena_filter_spec_t sf_spec; 1228 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1229 siena_filter_tbl_id_t tbl_id; 1230 siena_filter_tbl_t *sftp; 1231 siena_filter_spec_t *saved_sf_spec; 1232 efx_oword_t filter; 1233 int filter_idx; 1234 unsigned int depth; 1235 efsys_lock_state_t state; 1236 uint32_t key; 1237 1238 1239 EFSYS_ASSERT3P(spec, !=, NULL); 1240 1241 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0) 1242 goto fail1; 1243 1244 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type); 1245 sftp = &sfp->sf_tbl[tbl_id]; 1246 1247 if (sftp->sft_size == 0) { 1248 rc = EINVAL; 1249 goto fail2; 1250 } 1251 1252 key = siena_filter_build(&filter, &sf_spec); 1253 1254 EFSYS_LOCK(enp->en_eslp, state); 1255 1256 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE, 1257 &filter_idx, &depth); 1258 if (rc != 0) 1259 goto fail3; 1260 1261 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size); 1262 saved_sf_spec = &sftp->sft_spec[filter_idx]; 1263 1264 if (siena_filter_test_used(sftp, filter_idx)) { 1265 if (may_replace == B_FALSE) { 1266 rc = EEXIST; 1267 goto fail4; 1268 } 1269 } 1270 siena_filter_set_used(sftp, filter_idx); 1271 *saved_sf_spec = sf_spec; 1272 1273 if (sfp->sf_depth[sf_spec.sfs_type] < depth) { 1274 sfp->sf_depth[sf_spec.sfs_type] = depth; 1275 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP || 1276 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) 1277 siena_filter_push_tx_limits(enp); 1278 else 1279 siena_filter_push_rx_limits(enp); 1280 } 1281 1282 siena_filter_push_entry(enp, sf_spec.sfs_type, 1283 filter_idx, &filter); 1284 1285 EFSYS_UNLOCK(enp->en_eslp, state); 1286 return (0); 1287 1288fail4: 1289 EFSYS_PROBE(fail4); 1290 1291fail3: 1292 EFSYS_UNLOCK(enp->en_eslp, state); 1293 EFSYS_PROBE(fail3); 1294 1295fail2: 1296 EFSYS_PROBE(fail2); 1297 1298fail1: 1299 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1300 return (rc); 1301} 1302 1303static __checkReturn efx_rc_t 1304siena_filter_delete( 1305 __in efx_nic_t *enp, 1306 __inout efx_filter_spec_t *spec) 1307{ 1308 efx_rc_t rc; 1309 siena_filter_spec_t sf_spec; 1310 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1311 siena_filter_tbl_id_t tbl_id; 1312 siena_filter_tbl_t *sftp; 1313 efx_oword_t filter; 1314 int filter_idx; 1315 unsigned int depth; 1316 efsys_lock_state_t state; 1317 uint32_t key; 1318 1319 EFSYS_ASSERT3P(spec, !=, NULL); 1320 1321 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0) 1322 goto fail1; 1323 1324 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type); 1325 sftp = &sfp->sf_tbl[tbl_id]; 1326 1327 key = siena_filter_build(&filter, &sf_spec); 1328 1329 EFSYS_LOCK(enp->en_eslp, state); 1330 1331 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE, 1332 &filter_idx, &depth); 1333 if (rc != 0) 1334 goto fail2; 1335 1336 siena_filter_clear_entry(enp, sftp, filter_idx); 1337 if (sftp->sft_used == 0) 1338 siena_filter_reset_search_depth(sfp, tbl_id); 1339 1340 EFSYS_UNLOCK(enp->en_eslp, state); 1341 return (0); 1342 1343fail2: 1344 EFSYS_UNLOCK(enp->en_eslp, state); 1345 EFSYS_PROBE(fail2); 1346 1347fail1: 1348 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1349 return (rc); 1350} 1351 1352#define MAX_SUPPORTED 4 1353 1354static __checkReturn efx_rc_t 1355siena_filter_supported_filters( 1356 __in efx_nic_t *enp, 1357 __out uint32_t *list, 1358 __out size_t *length) 1359{ 1360 int index = 0; 1361 uint32_t rx_matches[MAX_SUPPORTED]; 1362 efx_rc_t rc; 1363 1364 if (list == NULL) { 1365 rc = EINVAL; 1366 goto fail1; 1367 } 1368 1369 rx_matches[index++] = 1370 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1371 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 1372 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; 1373 1374 rx_matches[index++] = 1375 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1376 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; 1377 1378 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) { 1379 rx_matches[index++] = 1380 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC; 1381 1382 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC; 1383 } 1384 1385 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED); 1386 1387 *length = index; 1388 memcpy(list, rx_matches, *length); 1389 1390 return (0); 1391 1392fail1: 1393 1394 return (rc); 1395} 1396 1397#undef MAX_SUPPORTED 1398 1399#endif /* EFSYS_OPT_SIENA */ 1400 1401#endif /* EFSYS_OPT_FILTER */ 1402