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