efx_filter.c revision 301337
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 <sys/cdefs.h> 32__FBSDID("$FreeBSD: stable/10/sys/dev/sfxge/common/efx_filter.c 301337 2016-06-04 14:55:56Z 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 43falconsiena_filter_init( 44 __in efx_nic_t *enp); 45 46static void 47falconsiena_filter_fini( 48 __in efx_nic_t *enp); 49 50static __checkReturn efx_rc_t 51falconsiena_filter_restore( 52 __in efx_nic_t *enp); 53 54static __checkReturn efx_rc_t 55falconsiena_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 61falconsiena_filter_delete( 62 __in efx_nic_t *enp, 63 __inout efx_filter_spec_t *spec); 64 65static __checkReturn efx_rc_t 66falconsiena_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 efx_filter_ops_t __efx_filter_siena_ops = { 75 falconsiena_filter_init, /* efo_init */ 76 falconsiena_filter_fini, /* efo_fini */ 77 falconsiena_filter_restore, /* efo_restore */ 78 falconsiena_filter_add, /* efo_add */ 79 falconsiena_filter_delete, /* efo_delete */ 80 falconsiena_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 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 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 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 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_ops_t *)&__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_ops_t *)&__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_ops_t *)&__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 431falconsiena_filter_spec_from_gen_spec( 432 __out falconsiena_filter_spec_t *fs_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 fs_spec->fsfs_flags = gen_spec->efs_flags; 451 fs_spec->fsfs_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 fs_spec->fsfs_type = (is_full ? 477 EFX_FS_FILTER_TX_TCP_FULL : 478 EFX_FS_FILTER_TX_TCP_WILD); 479 } else { 480 fs_spec->fsfs_type = (is_full ? 481 EFX_FS_FILTER_RX_TCP_FULL : 482 EFX_FS_FILTER_RX_TCP_WILD); 483 } 484 break; 485 case EFX_IPPROTO_UDP: 486 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 487 fs_spec->fsfs_type = (is_full ? 488 EFX_FS_FILTER_TX_UDP_FULL : 489 EFX_FS_FILTER_TX_UDP_WILD); 490 } else { 491 fs_spec->fsfs_type = (is_full ? 492 EFX_FS_FILTER_RX_UDP_FULL : 493 EFX_FS_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 (fs_spec->fsfs_type == EFX_FS_FILTER_TX_UDP_WILD) { 517 port1 = rport; 518 port2 = gen_spec->efs_loc_port; 519 } else { 520 port1 = gen_spec->efs_loc_port; 521 port2 = rport; 522 } 523 } else { 524 if (fs_spec->fsfs_type == EFX_FS_FILTER_RX_UDP_WILD) { 525 port1 = gen_spec->efs_loc_port; 526 port2 = rport; 527 } else { 528 port1 = rport; 529 port2 = gen_spec->efs_loc_port; 530 } 531 } 532 fs_spec->fsfs_dword[0] = (host1 << 16) | port1; 533 fs_spec->fsfs_dword[1] = (port2 << 16) | (host1 >> 16); 534 fs_spec->fsfs_dword[2] = host2; 535 break; 536 } 537 538 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID: 539 is_full = B_TRUE; 540 /* Fall through */ 541 case EFX_FILTER_MATCH_LOC_MAC: 542 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 543 fs_spec->fsfs_type = (is_full ? 544 EFX_FS_FILTER_TX_MAC_FULL : 545 EFX_FS_FILTER_TX_MAC_WILD); 546 } else { 547 fs_spec->fsfs_type = (is_full ? 548 EFX_FS_FILTER_RX_MAC_FULL : 549 EFX_FS_FILTER_RX_MAC_WILD); 550 } 551 fs_spec->fsfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0; 552 fs_spec->fsfs_dword[1] = 553 gen_spec->efs_loc_mac[2] << 24 | 554 gen_spec->efs_loc_mac[3] << 16 | 555 gen_spec->efs_loc_mac[4] << 8 | 556 gen_spec->efs_loc_mac[5]; 557 fs_spec->fsfs_dword[2] = 558 gen_spec->efs_loc_mac[0] << 8 | 559 gen_spec->efs_loc_mac[1]; 560 break; 561 562 default: 563 EFSYS_ASSERT(B_FALSE); 564 rc = ENOTSUP; 565 goto fail5; 566 } 567 568 return (0); 569 570fail5: 571 EFSYS_PROBE(fail5); 572fail4: 573 EFSYS_PROBE(fail4); 574fail3: 575 EFSYS_PROBE(fail3); 576fail2: 577 EFSYS_PROBE(fail2); 578fail1: 579 EFSYS_PROBE1(fail1, efx_rc_t, rc); 580 581 return (rc); 582} 583 584/* 585 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit 586 * key derived from the n-tuple. 587 */ 588static uint16_t 589falconsiena_filter_tbl_hash( 590 __in uint32_t key) 591{ 592 uint16_t tmp; 593 594 /* First 16 rounds */ 595 tmp = 0x1fff ^ (uint16_t)(key >> 16); 596 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 597 tmp = tmp ^ tmp >> 9; 598 599 /* Last 16 rounds */ 600 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff); 601 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 602 tmp = tmp ^ tmp >> 9; 603 604 return (tmp); 605} 606 607/* 608 * To allow for hash collisions, filter search continues at these 609 * increments from the first possible entry selected by the hash. 610 */ 611static uint16_t 612falconsiena_filter_tbl_increment( 613 __in uint32_t key) 614{ 615 return ((uint16_t)(key * 2 - 1)); 616} 617 618static __checkReturn boolean_t 619falconsiena_filter_test_used( 620 __in falconsiena_filter_tbl_t *fsftp, 621 __in unsigned int index) 622{ 623 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL); 624 return ((fsftp->fsft_bitmap[index / 32] & (1 << (index % 32))) != 0); 625} 626 627static void 628falconsiena_filter_set_used( 629 __in falconsiena_filter_tbl_t *fsftp, 630 __in unsigned int index) 631{ 632 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL); 633 fsftp->fsft_bitmap[index / 32] |= (1 << (index % 32)); 634 ++fsftp->fsft_used; 635} 636 637static void 638falconsiena_filter_clear_used( 639 __in falconsiena_filter_tbl_t *fsftp, 640 __in unsigned int index) 641{ 642 EFSYS_ASSERT3P(fsftp->fsft_bitmap, !=, NULL); 643 fsftp->fsft_bitmap[index / 32] &= ~(1 << (index % 32)); 644 645 --fsftp->fsft_used; 646 EFSYS_ASSERT3U(fsftp->fsft_used, >=, 0); 647} 648 649 650static falconsiena_filter_tbl_id_t 651falconsiena_filter_tbl_id( 652 __in falconsiena_filter_type_t type) 653{ 654 falconsiena_filter_tbl_id_t tbl_id; 655 656 switch (type) { 657 case EFX_FS_FILTER_RX_TCP_FULL: 658 case EFX_FS_FILTER_RX_TCP_WILD: 659 case EFX_FS_FILTER_RX_UDP_FULL: 660 case EFX_FS_FILTER_RX_UDP_WILD: 661 tbl_id = EFX_FS_FILTER_TBL_RX_IP; 662 break; 663 664#if EFSYS_OPT_SIENA 665 case EFX_FS_FILTER_RX_MAC_FULL: 666 case EFX_FS_FILTER_RX_MAC_WILD: 667 tbl_id = EFX_FS_FILTER_TBL_RX_MAC; 668 break; 669 670 case EFX_FS_FILTER_TX_TCP_FULL: 671 case EFX_FS_FILTER_TX_TCP_WILD: 672 case EFX_FS_FILTER_TX_UDP_FULL: 673 case EFX_FS_FILTER_TX_UDP_WILD: 674 tbl_id = EFX_FS_FILTER_TBL_TX_IP; 675 break; 676 677 case EFX_FS_FILTER_TX_MAC_FULL: 678 case EFX_FS_FILTER_TX_MAC_WILD: 679 tbl_id = EFX_FS_FILTER_TBL_TX_MAC; 680 break; 681#endif /* EFSYS_OPT_SIENA */ 682 683 default: 684 EFSYS_ASSERT(B_FALSE); 685 tbl_id = EFX_FS_FILTER_NTBLS; 686 break; 687 } 688 return (tbl_id); 689} 690 691static void 692falconsiena_filter_reset_search_depth( 693 __inout falconsiena_filter_t *fsfp, 694 __in falconsiena_filter_tbl_id_t tbl_id) 695{ 696 switch (tbl_id) { 697 case EFX_FS_FILTER_TBL_RX_IP: 698 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] = 0; 699 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] = 0; 700 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] = 0; 701 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] = 0; 702 break; 703 704#if EFSYS_OPT_SIENA 705 case EFX_FS_FILTER_TBL_RX_MAC: 706 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] = 0; 707 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] = 0; 708 break; 709 710 case EFX_FS_FILTER_TBL_TX_IP: 711 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] = 0; 712 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] = 0; 713 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] = 0; 714 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] = 0; 715 break; 716 717 case EFX_FS_FILTER_TBL_TX_MAC: 718 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] = 0; 719 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] = 0; 720 break; 721#endif /* EFSYS_OPT_SIENA */ 722 723 default: 724 EFSYS_ASSERT(B_FALSE); 725 break; 726 } 727} 728 729static void 730falconsiena_filter_push_rx_limits( 731 __in efx_nic_t *enp) 732{ 733 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; 734 efx_oword_t oword; 735 736 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 737 738 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT, 739 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_FULL] + 740 FILTER_CTL_SRCH_FUDGE_FULL); 741 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT, 742 fsfp->fsf_depth[EFX_FS_FILTER_RX_TCP_WILD] + 743 FILTER_CTL_SRCH_FUDGE_WILD); 744 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT, 745 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_FULL] + 746 FILTER_CTL_SRCH_FUDGE_FULL); 747 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT, 748 fsfp->fsf_depth[EFX_FS_FILTER_RX_UDP_WILD] + 749 FILTER_CTL_SRCH_FUDGE_WILD); 750 751#if EFSYS_OPT_SIENA 752 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC].fsft_size) { 753 EFX_SET_OWORD_FIELD(oword, 754 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, 755 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_FULL] + 756 FILTER_CTL_SRCH_FUDGE_FULL); 757 EFX_SET_OWORD_FIELD(oword, 758 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, 759 fsfp->fsf_depth[EFX_FS_FILTER_RX_MAC_WILD] + 760 FILTER_CTL_SRCH_FUDGE_WILD); 761 } 762#endif /* EFSYS_OPT_SIENA */ 763 764 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 765} 766 767static void 768falconsiena_filter_push_tx_limits( 769 __in efx_nic_t *enp) 770{ 771 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; 772 efx_oword_t oword; 773 774 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword); 775 776 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP].fsft_size != 0) { 777 EFX_SET_OWORD_FIELD(oword, 778 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE, 779 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_FULL] + 780 FILTER_CTL_SRCH_FUDGE_FULL); 781 EFX_SET_OWORD_FIELD(oword, 782 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE, 783 fsfp->fsf_depth[EFX_FS_FILTER_TX_TCP_WILD] + 784 FILTER_CTL_SRCH_FUDGE_WILD); 785 EFX_SET_OWORD_FIELD(oword, 786 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE, 787 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_FULL] + 788 FILTER_CTL_SRCH_FUDGE_FULL); 789 EFX_SET_OWORD_FIELD(oword, 790 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE, 791 fsfp->fsf_depth[EFX_FS_FILTER_TX_UDP_WILD] + 792 FILTER_CTL_SRCH_FUDGE_WILD); 793 } 794 795 if (fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC].fsft_size != 0) { 796 EFX_SET_OWORD_FIELD( 797 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, 798 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_FULL] + 799 FILTER_CTL_SRCH_FUDGE_FULL); 800 EFX_SET_OWORD_FIELD( 801 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, 802 fsfp->fsf_depth[EFX_FS_FILTER_TX_MAC_WILD] + 803 FILTER_CTL_SRCH_FUDGE_WILD); 804 } 805 806 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword); 807} 808 809/* Build a filter entry and return its n-tuple key. */ 810static __checkReturn uint32_t 811falconsiena_filter_build( 812 __out efx_oword_t *filter, 813 __in falconsiena_filter_spec_t *spec) 814{ 815 uint32_t dword3; 816 uint32_t key; 817 uint8_t type = spec->fsfs_type; 818 uint32_t flags = spec->fsfs_flags; 819 820 switch (falconsiena_filter_tbl_id(type)) { 821 case EFX_FS_FILTER_TBL_RX_IP: { 822 boolean_t is_udp = (type == EFX_FS_FILTER_RX_UDP_FULL || 823 type == EFX_FS_FILTER_RX_UDP_WILD); 824 EFX_POPULATE_OWORD_7(*filter, 825 FRF_BZ_RSS_EN, 826 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 827 FRF_BZ_SCATTER_EN, 828 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 829 FRF_AZ_TCP_UDP, is_udp, 830 FRF_AZ_RXQ_ID, spec->fsfs_dmaq_id, 831 EFX_DWORD_2, spec->fsfs_dword[2], 832 EFX_DWORD_1, spec->fsfs_dword[1], 833 EFX_DWORD_0, spec->fsfs_dword[0]); 834 dword3 = is_udp; 835 break; 836 } 837 838#if EFSYS_OPT_SIENA 839 case EFX_FS_FILTER_TBL_RX_MAC: { 840 boolean_t is_wild = (type == EFX_FS_FILTER_RX_MAC_WILD); 841 EFX_POPULATE_OWORD_7(*filter, 842 FRF_CZ_RMFT_RSS_EN, 843 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 844 FRF_CZ_RMFT_SCATTER_EN, 845 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 846 FRF_CZ_RMFT_RXQ_ID, spec->fsfs_dmaq_id, 847 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild, 848 FRF_CZ_RMFT_DEST_MAC_DW1, spec->fsfs_dword[2], 849 FRF_CZ_RMFT_DEST_MAC_DW0, spec->fsfs_dword[1], 850 FRF_CZ_RMFT_VLAN_ID, spec->fsfs_dword[0]); 851 dword3 = is_wild; 852 break; 853 } 854#endif /* EFSYS_OPT_SIENA */ 855 856 case EFX_FS_FILTER_TBL_TX_IP: { 857 boolean_t is_udp = (type == EFX_FS_FILTER_TX_UDP_FULL || 858 type == EFX_FS_FILTER_TX_UDP_WILD); 859 EFX_POPULATE_OWORD_5(*filter, 860 FRF_CZ_TIFT_TCP_UDP, is_udp, 861 FRF_CZ_TIFT_TXQ_ID, spec->fsfs_dmaq_id, 862 EFX_DWORD_2, spec->fsfs_dword[2], 863 EFX_DWORD_1, spec->fsfs_dword[1], 864 EFX_DWORD_0, spec->fsfs_dword[0]); 865 dword3 = is_udp | spec->fsfs_dmaq_id << 1; 866 break; 867 } 868 869#if EFSYS_OPT_SIENA 870 case EFX_FS_FILTER_TBL_TX_MAC: { 871 boolean_t is_wild = (type == EFX_FS_FILTER_TX_MAC_WILD); 872 EFX_POPULATE_OWORD_5(*filter, 873 FRF_CZ_TMFT_TXQ_ID, spec->fsfs_dmaq_id, 874 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, 875 FRF_CZ_TMFT_SRC_MAC_DW1, spec->fsfs_dword[2], 876 FRF_CZ_TMFT_SRC_MAC_DW0, spec->fsfs_dword[1], 877 FRF_CZ_TMFT_VLAN_ID, spec->fsfs_dword[0]); 878 dword3 = is_wild | spec->fsfs_dmaq_id << 1; 879 break; 880 } 881#endif /* EFSYS_OPT_SIENA */ 882 883 default: 884 EFSYS_ASSERT(B_FALSE); 885 return (0); 886 } 887 888 key = 889 spec->fsfs_dword[0] ^ 890 spec->fsfs_dword[1] ^ 891 spec->fsfs_dword[2] ^ 892 dword3; 893 894 return (key); 895} 896 897static __checkReturn efx_rc_t 898falconsiena_filter_push_entry( 899 __inout efx_nic_t *enp, 900 __in falconsiena_filter_type_t type, 901 __in int index, 902 __in efx_oword_t *eop) 903{ 904 efx_rc_t rc; 905 906 switch (type) { 907 case EFX_FS_FILTER_RX_TCP_FULL: 908 case EFX_FS_FILTER_RX_TCP_WILD: 909 case EFX_FS_FILTER_RX_UDP_FULL: 910 case EFX_FS_FILTER_RX_UDP_WILD: 911 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index, 912 eop, B_TRUE); 913 break; 914 915#if EFSYS_OPT_SIENA 916 case EFX_FS_FILTER_RX_MAC_FULL: 917 case EFX_FS_FILTER_RX_MAC_WILD: 918 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index, 919 eop, B_TRUE); 920 break; 921 922 case EFX_FS_FILTER_TX_TCP_FULL: 923 case EFX_FS_FILTER_TX_TCP_WILD: 924 case EFX_FS_FILTER_TX_UDP_FULL: 925 case EFX_FS_FILTER_TX_UDP_WILD: 926 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index, 927 eop, B_TRUE); 928 break; 929 930 case EFX_FS_FILTER_TX_MAC_FULL: 931 case EFX_FS_FILTER_TX_MAC_WILD: 932 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index, 933 eop, B_TRUE); 934 break; 935#endif /* EFSYS_OPT_SIENA */ 936 937 default: 938 EFSYS_ASSERT(B_FALSE); 939 rc = ENOTSUP; 940 goto fail1; 941 } 942 return (0); 943 944fail1: 945 return (rc); 946} 947 948 949static __checkReturn boolean_t 950falconsiena_filter_equal( 951 __in const falconsiena_filter_spec_t *left, 952 __in const falconsiena_filter_spec_t *right) 953{ 954 falconsiena_filter_tbl_id_t tbl_id; 955 956 tbl_id = falconsiena_filter_tbl_id(left->fsfs_type); 957 958 959 if (left->fsfs_type != right->fsfs_type) 960 return (B_FALSE); 961 962 if (memcmp(left->fsfs_dword, right->fsfs_dword, 963 sizeof (left->fsfs_dword))) 964 return (B_FALSE); 965 966 if ((tbl_id == EFX_FS_FILTER_TBL_TX_IP || 967 tbl_id == EFX_FS_FILTER_TBL_TX_MAC) && 968 left->fsfs_dmaq_id != right->fsfs_dmaq_id) 969 return (B_FALSE); 970 971 return (B_TRUE); 972} 973 974static __checkReturn efx_rc_t 975falconsiena_filter_search( 976 __in falconsiena_filter_tbl_t *fsftp, 977 __in falconsiena_filter_spec_t *spec, 978 __in uint32_t key, 979 __in boolean_t for_insert, 980 __out int *filter_index, 981 __out unsigned int *depth_required) 982{ 983 unsigned hash, incr, filter_idx, depth; 984 985 hash = falconsiena_filter_tbl_hash(key); 986 incr = falconsiena_filter_tbl_increment(key); 987 988 filter_idx = hash & (fsftp->fsft_size - 1); 989 depth = 1; 990 991 for (;;) { 992 /* 993 * Return success if entry is used and matches this spec 994 * or entry is unused and we are trying to insert. 995 */ 996 if (falconsiena_filter_test_used(fsftp, filter_idx) ? 997 falconsiena_filter_equal(spec, 998 &fsftp->fsft_spec[filter_idx]) : 999 for_insert) { 1000 *filter_index = filter_idx; 1001 *depth_required = depth; 1002 return (0); 1003 } 1004 1005 /* Return failure if we reached the maximum search depth */ 1006 if (depth == FILTER_CTL_SRCH_MAX) 1007 return (for_insert ? EBUSY : ENOENT); 1008 1009 filter_idx = (filter_idx + incr) & (fsftp->fsft_size - 1); 1010 ++depth; 1011 } 1012} 1013 1014static void 1015falconsiena_filter_clear_entry( 1016 __in efx_nic_t *enp, 1017 __in falconsiena_filter_tbl_t *fsftp, 1018 __in int index) 1019{ 1020 efx_oword_t filter; 1021 1022 if (falconsiena_filter_test_used(fsftp, index)) { 1023 falconsiena_filter_clear_used(fsftp, index); 1024 1025 EFX_ZERO_OWORD(filter); 1026 falconsiena_filter_push_entry(enp, 1027 fsftp->fsft_spec[index].fsfs_type, 1028 index, &filter); 1029 1030 memset(&fsftp->fsft_spec[index], 1031 0, sizeof (fsftp->fsft_spec[0])); 1032 } 1033} 1034 1035 void 1036falconsiena_filter_tbl_clear( 1037 __in efx_nic_t *enp, 1038 __in falconsiena_filter_tbl_id_t tbl_id) 1039{ 1040 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; 1041 falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id]; 1042 int index; 1043 int state; 1044 1045 EFSYS_LOCK(enp->en_eslp, state); 1046 1047 for (index = 0; index < fsftp->fsft_size; ++index) { 1048 falconsiena_filter_clear_entry(enp, fsftp, index); 1049 } 1050 1051 if (fsftp->fsft_used == 0) 1052 falconsiena_filter_reset_search_depth(fsfp, tbl_id); 1053 1054 EFSYS_UNLOCK(enp->en_eslp, state); 1055} 1056 1057static __checkReturn efx_rc_t 1058falconsiena_filter_init( 1059 __in efx_nic_t *enp) 1060{ 1061 falconsiena_filter_t *fsfp; 1062 falconsiena_filter_tbl_t *fsftp; 1063 int tbl_id; 1064 efx_rc_t rc; 1065 1066 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (falconsiena_filter_t), fsfp); 1067 1068 if (!fsfp) { 1069 rc = ENOMEM; 1070 goto fail1; 1071 } 1072 1073 enp->en_filter.ef_falconsiena_filter = fsfp; 1074 1075 switch (enp->en_family) { 1076#if EFSYS_OPT_SIENA 1077 case EFX_FAMILY_SIENA: 1078 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_IP]; 1079 fsftp->fsft_size = FR_AZ_RX_FILTER_TBL0_ROWS; 1080 1081 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_RX_MAC]; 1082 fsftp->fsft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; 1083 1084 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_IP]; 1085 fsftp->fsft_size = FR_CZ_TX_FILTER_TBL0_ROWS; 1086 1087 fsftp = &fsfp->fsf_tbl[EFX_FS_FILTER_TBL_TX_MAC]; 1088 fsftp->fsft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS; 1089 break; 1090#endif /* EFSYS_OPT_SIENA */ 1091 1092 default: 1093 rc = ENOTSUP; 1094 goto fail2; 1095 } 1096 1097 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) { 1098 unsigned int bitmap_size; 1099 1100 fsftp = &fsfp->fsf_tbl[tbl_id]; 1101 if (fsftp->fsft_size == 0) 1102 continue; 1103 1104 EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) == 1105 sizeof (uint32_t)); 1106 bitmap_size = 1107 (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8; 1108 1109 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, fsftp->fsft_bitmap); 1110 if (!fsftp->fsft_bitmap) { 1111 rc = ENOMEM; 1112 goto fail3; 1113 } 1114 1115 EFSYS_KMEM_ALLOC(enp->en_esip, 1116 fsftp->fsft_size * sizeof (*fsftp->fsft_spec), 1117 fsftp->fsft_spec); 1118 if (!fsftp->fsft_spec) { 1119 rc = ENOMEM; 1120 goto fail4; 1121 } 1122 memset(fsftp->fsft_spec, 0, 1123 fsftp->fsft_size * sizeof (*fsftp->fsft_spec)); 1124 } 1125 1126 return (0); 1127 1128fail4: 1129 EFSYS_PROBE(fail4); 1130 1131fail3: 1132 EFSYS_PROBE(fail3); 1133 1134fail2: 1135 EFSYS_PROBE(fail2); 1136 falconsiena_filter_fini(enp); 1137 1138fail1: 1139 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1140 return (rc); 1141} 1142 1143static void 1144falconsiena_filter_fini( 1145 __in efx_nic_t *enp) 1146{ 1147 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; 1148 falconsiena_filter_tbl_id_t tbl_id; 1149 1150 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1151 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 1152 1153 if (fsfp == NULL) 1154 return; 1155 1156 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) { 1157 falconsiena_filter_tbl_t *fsftp = &fsfp->fsf_tbl[tbl_id]; 1158 unsigned int bitmap_size; 1159 1160 EFX_STATIC_ASSERT(sizeof (fsftp->fsft_bitmap[0]) == 1161 sizeof (uint32_t)); 1162 bitmap_size = 1163 (fsftp->fsft_size + (sizeof (uint32_t) * 8) - 1) / 8; 1164 1165 if (fsftp->fsft_bitmap != NULL) { 1166 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size, 1167 fsftp->fsft_bitmap); 1168 fsftp->fsft_bitmap = NULL; 1169 } 1170 1171 if (fsftp->fsft_spec != NULL) { 1172 EFSYS_KMEM_FREE(enp->en_esip, fsftp->fsft_size * 1173 sizeof (*fsftp->fsft_spec), fsftp->fsft_spec); 1174 fsftp->fsft_spec = NULL; 1175 } 1176 } 1177 1178 EFSYS_KMEM_FREE(enp->en_esip, sizeof (falconsiena_filter_t), 1179 enp->en_filter.ef_falconsiena_filter); 1180} 1181 1182/* Restore filter state after a reset */ 1183static __checkReturn efx_rc_t 1184falconsiena_filter_restore( 1185 __in efx_nic_t *enp) 1186{ 1187 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; 1188 falconsiena_filter_tbl_id_t tbl_id; 1189 falconsiena_filter_tbl_t *fsftp; 1190 falconsiena_filter_spec_t *spec; 1191 efx_oword_t filter; 1192 int filter_idx; 1193 int state; 1194 efx_rc_t rc; 1195 1196 EFSYS_LOCK(enp->en_eslp, state); 1197 1198 for (tbl_id = 0; tbl_id < EFX_FS_FILTER_NTBLS; tbl_id++) { 1199 fsftp = &fsfp->fsf_tbl[tbl_id]; 1200 for (filter_idx = 0; 1201 filter_idx < fsftp->fsft_size; 1202 filter_idx++) { 1203 if (!falconsiena_filter_test_used(fsftp, filter_idx)) 1204 continue; 1205 1206 spec = &fsftp->fsft_spec[filter_idx]; 1207 if ((rc = falconsiena_filter_build(&filter, spec)) != 0) 1208 goto fail1; 1209 if ((rc = falconsiena_filter_push_entry(enp, 1210 spec->fsfs_type, filter_idx, &filter)) != 0) 1211 goto fail2; 1212 } 1213 } 1214 1215 falconsiena_filter_push_rx_limits(enp); 1216 falconsiena_filter_push_tx_limits(enp); 1217 1218 EFSYS_UNLOCK(enp->en_eslp, state); 1219 1220 return (0); 1221 1222fail2: 1223 EFSYS_PROBE(fail2); 1224 1225fail1: 1226 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1227 1228 EFSYS_UNLOCK(enp->en_eslp, state); 1229 1230 return (rc); 1231} 1232 1233static __checkReturn efx_rc_t 1234falconsiena_filter_add( 1235 __in efx_nic_t *enp, 1236 __inout efx_filter_spec_t *spec, 1237 __in boolean_t may_replace) 1238{ 1239 efx_rc_t rc; 1240 falconsiena_filter_spec_t fs_spec; 1241 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; 1242 falconsiena_filter_tbl_id_t tbl_id; 1243 falconsiena_filter_tbl_t *fsftp; 1244 falconsiena_filter_spec_t *saved_fs_spec; 1245 efx_oword_t filter; 1246 int filter_idx; 1247 unsigned int depth; 1248 int state; 1249 uint32_t key; 1250 1251 1252 EFSYS_ASSERT3P(spec, !=, NULL); 1253 1254 if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0) 1255 goto fail1; 1256 1257 tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type); 1258 fsftp = &fsfp->fsf_tbl[tbl_id]; 1259 1260 if (fsftp->fsft_size == 0) { 1261 rc = EINVAL; 1262 goto fail2; 1263 } 1264 1265 key = falconsiena_filter_build(&filter, &fs_spec); 1266 1267 EFSYS_LOCK(enp->en_eslp, state); 1268 1269 rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_TRUE, 1270 &filter_idx, &depth); 1271 if (rc != 0) 1272 goto fail3; 1273 1274 EFSYS_ASSERT3U(filter_idx, <, fsftp->fsft_size); 1275 saved_fs_spec = &fsftp->fsft_spec[filter_idx]; 1276 1277 if (falconsiena_filter_test_used(fsftp, filter_idx)) { 1278 if (may_replace == B_FALSE) { 1279 rc = EEXIST; 1280 goto fail4; 1281 } 1282 } 1283 falconsiena_filter_set_used(fsftp, filter_idx); 1284 *saved_fs_spec = fs_spec; 1285 1286 if (fsfp->fsf_depth[fs_spec.fsfs_type] < depth) { 1287 fsfp->fsf_depth[fs_spec.fsfs_type] = depth; 1288 if (tbl_id == EFX_FS_FILTER_TBL_TX_IP || 1289 tbl_id == EFX_FS_FILTER_TBL_TX_MAC) 1290 falconsiena_filter_push_tx_limits(enp); 1291 else 1292 falconsiena_filter_push_rx_limits(enp); 1293 } 1294 1295 falconsiena_filter_push_entry(enp, fs_spec.fsfs_type, 1296 filter_idx, &filter); 1297 1298 EFSYS_UNLOCK(enp->en_eslp, state); 1299 return (0); 1300 1301fail4: 1302 EFSYS_PROBE(fail4); 1303 1304fail3: 1305 EFSYS_UNLOCK(enp->en_eslp, state); 1306 EFSYS_PROBE(fail3); 1307 1308fail2: 1309 EFSYS_PROBE(fail2); 1310 1311fail1: 1312 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1313 return (rc); 1314} 1315 1316static __checkReturn efx_rc_t 1317falconsiena_filter_delete( 1318 __in efx_nic_t *enp, 1319 __inout efx_filter_spec_t *spec) 1320{ 1321 efx_rc_t rc; 1322 falconsiena_filter_spec_t fs_spec; 1323 falconsiena_filter_t *fsfp = enp->en_filter.ef_falconsiena_filter; 1324 falconsiena_filter_tbl_id_t tbl_id; 1325 falconsiena_filter_tbl_t *fsftp; 1326 efx_oword_t filter; 1327 int filter_idx; 1328 unsigned int depth; 1329 int state; 1330 uint32_t key; 1331 1332 EFSYS_ASSERT3P(spec, !=, NULL); 1333 1334 if ((rc = falconsiena_filter_spec_from_gen_spec(&fs_spec, spec)) != 0) 1335 goto fail1; 1336 1337 tbl_id = falconsiena_filter_tbl_id(fs_spec.fsfs_type); 1338 fsftp = &fsfp->fsf_tbl[tbl_id]; 1339 1340 key = falconsiena_filter_build(&filter, &fs_spec); 1341 1342 EFSYS_LOCK(enp->en_eslp, state); 1343 1344 rc = falconsiena_filter_search(fsftp, &fs_spec, key, B_FALSE, 1345 &filter_idx, &depth); 1346 if (rc != 0) 1347 goto fail2; 1348 1349 falconsiena_filter_clear_entry(enp, fsftp, filter_idx); 1350 if (fsftp->fsft_used == 0) 1351 falconsiena_filter_reset_search_depth(fsfp, tbl_id); 1352 1353 EFSYS_UNLOCK(enp->en_eslp, state); 1354 return (0); 1355 1356fail2: 1357 EFSYS_UNLOCK(enp->en_eslp, state); 1358 EFSYS_PROBE(fail2); 1359 1360fail1: 1361 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1362 return (rc); 1363} 1364 1365#define MAX_SUPPORTED 4 1366 1367static __checkReturn efx_rc_t 1368falconsiena_filter_supported_filters( 1369 __in efx_nic_t *enp, 1370 __out uint32_t *list, 1371 __out size_t *length) 1372{ 1373 int index = 0; 1374 uint32_t rx_matches[MAX_SUPPORTED]; 1375 efx_rc_t rc; 1376 1377 if (list == NULL) { 1378 rc = EINVAL; 1379 goto fail1; 1380 } 1381 1382 rx_matches[index++] = 1383 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1384 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 1385 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; 1386 1387 rx_matches[index++] = 1388 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1389 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; 1390 1391 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) { 1392 rx_matches[index++] = 1393 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC; 1394 1395 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC; 1396 } 1397 1398 EFSYS_ASSERT3U(index, <=, MAX_SUPPORTED); 1399 1400 *length = index; 1401 memcpy(list, rx_matches, *length); 1402 1403 return (0); 1404 1405fail1: 1406 1407 return (rc); 1408} 1409 1410#undef MAX_SUPPORTED 1411 1412#endif /* EFSYS_OPT_SIENA */ 1413 1414#endif /* EFSYS_OPT_FILTER */ 1415