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