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