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/11/sys/dev/sfxge/common/efx_filter.c 342418 2018-12-25 06:55:13Z 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_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 void 403efx_filter_spec_set_ether_type( 404 __inout efx_filter_spec_t *spec, 405 __in uint16_t ether_type) 406{ 407 EFSYS_ASSERT3P(spec, !=, NULL); 408 409 spec->efs_ether_type = ether_type; 410 spec->efs_match_flags |= EFX_FILTER_MATCH_ETHER_TYPE; 411} 412 413/* 414 * Specify matching otherwise-unmatched unicast in a filter specification 415 */ 416__checkReturn efx_rc_t 417efx_filter_spec_set_uc_def( 418 __inout efx_filter_spec_t *spec) 419{ 420 EFSYS_ASSERT3P(spec, !=, NULL); 421 422 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_UCAST_DST; 423 return (0); 424} 425 426/* 427 * Specify matching otherwise-unmatched multicast in a filter specification 428 */ 429__checkReturn efx_rc_t 430efx_filter_spec_set_mc_def( 431 __inout efx_filter_spec_t *spec) 432{ 433 EFSYS_ASSERT3P(spec, !=, NULL); 434 435 spec->efs_match_flags |= EFX_FILTER_MATCH_UNKNOWN_MCAST_DST; 436 return (0); 437} 438 439 440__checkReturn efx_rc_t 441efx_filter_spec_set_encap_type( 442 __inout efx_filter_spec_t *spec, 443 __in efx_tunnel_protocol_t encap_type, 444 __in efx_filter_inner_frame_match_t inner_frame_match) 445{ 446 uint32_t match_flags = 0; 447 uint8_t ip_proto; 448 efx_rc_t rc; 449 450 EFSYS_ASSERT3P(spec, !=, NULL); 451 452 switch (encap_type) { 453 case EFX_TUNNEL_PROTOCOL_VXLAN: 454 case EFX_TUNNEL_PROTOCOL_GENEVE: 455 ip_proto = EFX_IPPROTO_UDP; 456 break; 457 case EFX_TUNNEL_PROTOCOL_NVGRE: 458 ip_proto = EFX_IPPROTO_GRE; 459 break; 460 default: 461 EFSYS_ASSERT(0); 462 rc = EINVAL; 463 goto fail1; 464 } 465 466 switch (inner_frame_match) { 467 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_MCAST_DST: 468 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_MCAST_DST; 469 break; 470 case EFX_FILTER_INNER_FRAME_MATCH_UNKNOWN_UCAST_DST: 471 match_flags |= EFX_FILTER_MATCH_IFRM_UNKNOWN_UCAST_DST; 472 break; 473 case EFX_FILTER_INNER_FRAME_MATCH_OTHER: 474 /* This is for when specific inner frames are to be matched. */ 475 break; 476 default: 477 EFSYS_ASSERT(0); 478 rc = EINVAL; 479 goto fail2; 480 } 481 482 spec->efs_encap_type = encap_type; 483 spec->efs_ip_proto = ip_proto; 484 spec->efs_match_flags |= (match_flags | EFX_FILTER_MATCH_IP_PROTO); 485 486 return (0); 487 488fail2: 489 EFSYS_PROBE(fail2); 490fail1: 491 EFSYS_PROBE1(fail1, efx_rc_t, rc); 492 493 return (rc); 494} 495 496 497 498#if EFSYS_OPT_SIENA 499 500/* 501 * "Fudge factors" - difference between programmed value and actual depth. 502 * Due to pipelined implementation we need to program H/W with a value that 503 * is larger than the hop limit we want. 504 */ 505#define FILTER_CTL_SRCH_FUDGE_WILD 3 506#define FILTER_CTL_SRCH_FUDGE_FULL 1 507 508/* 509 * Hard maximum hop limit. Hardware will time-out beyond 200-something. 510 * We also need to avoid infinite loops in efx_filter_search() when the 511 * table is full. 512 */ 513#define FILTER_CTL_SRCH_MAX 200 514 515static __checkReturn efx_rc_t 516siena_filter_spec_from_gen_spec( 517 __out siena_filter_spec_t *sf_spec, 518 __in efx_filter_spec_t *gen_spec) 519{ 520 efx_rc_t rc; 521 boolean_t is_full = B_FALSE; 522 523 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) 524 EFSYS_ASSERT3U(gen_spec->efs_flags, ==, EFX_FILTER_FLAG_TX); 525 else 526 EFSYS_ASSERT3U(gen_spec->efs_flags, &, EFX_FILTER_FLAG_RX); 527 528 /* Siena only has one RSS context */ 529 if ((gen_spec->efs_flags & EFX_FILTER_FLAG_RX_RSS) && 530 gen_spec->efs_rss_context != EFX_RSS_CONTEXT_DEFAULT) { 531 rc = EINVAL; 532 goto fail1; 533 } 534 535 sf_spec->sfs_flags = gen_spec->efs_flags; 536 sf_spec->sfs_dmaq_id = gen_spec->efs_dmaq_id; 537 538 switch (gen_spec->efs_match_flags) { 539 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 540 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 541 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT: 542 is_full = B_TRUE; 543 /* Fall through */ 544 case EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 545 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT: { 546 uint32_t rhost, host1, host2; 547 uint16_t rport, port1, port2; 548 549 if (gen_spec->efs_ether_type != EFX_ETHER_TYPE_IPV4) { 550 rc = ENOTSUP; 551 goto fail2; 552 } 553 if (gen_spec->efs_loc_port == 0 || 554 (is_full && gen_spec->efs_rem_port == 0)) { 555 rc = EINVAL; 556 goto fail3; 557 } 558 switch (gen_spec->efs_ip_proto) { 559 case EFX_IPPROTO_TCP: 560 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 561 sf_spec->sfs_type = (is_full ? 562 EFX_SIENA_FILTER_TX_TCP_FULL : 563 EFX_SIENA_FILTER_TX_TCP_WILD); 564 } else { 565 sf_spec->sfs_type = (is_full ? 566 EFX_SIENA_FILTER_RX_TCP_FULL : 567 EFX_SIENA_FILTER_RX_TCP_WILD); 568 } 569 break; 570 case EFX_IPPROTO_UDP: 571 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 572 sf_spec->sfs_type = (is_full ? 573 EFX_SIENA_FILTER_TX_UDP_FULL : 574 EFX_SIENA_FILTER_TX_UDP_WILD); 575 } else { 576 sf_spec->sfs_type = (is_full ? 577 EFX_SIENA_FILTER_RX_UDP_FULL : 578 EFX_SIENA_FILTER_RX_UDP_WILD); 579 } 580 break; 581 default: 582 rc = ENOTSUP; 583 goto fail4; 584 } 585 /* 586 * The filter is constructed in terms of source and destination, 587 * with the odd wrinkle that the ports are swapped in a UDP 588 * wildcard filter. We need to convert from local and remote 589 * addresses (zero for a wildcard). 590 */ 591 rhost = is_full ? gen_spec->efs_rem_host.eo_u32[0] : 0; 592 rport = is_full ? gen_spec->efs_rem_port : 0; 593 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 594 host1 = gen_spec->efs_loc_host.eo_u32[0]; 595 host2 = rhost; 596 } else { 597 host1 = rhost; 598 host2 = gen_spec->efs_loc_host.eo_u32[0]; 599 } 600 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 601 if (sf_spec->sfs_type == 602 EFX_SIENA_FILTER_TX_UDP_WILD) { 603 port1 = rport; 604 port2 = gen_spec->efs_loc_port; 605 } else { 606 port1 = gen_spec->efs_loc_port; 607 port2 = rport; 608 } 609 } else { 610 if (sf_spec->sfs_type == 611 EFX_SIENA_FILTER_RX_UDP_WILD) { 612 port1 = gen_spec->efs_loc_port; 613 port2 = rport; 614 } else { 615 port1 = rport; 616 port2 = gen_spec->efs_loc_port; 617 } 618 } 619 sf_spec->sfs_dword[0] = (host1 << 16) | port1; 620 sf_spec->sfs_dword[1] = (port2 << 16) | (host1 >> 16); 621 sf_spec->sfs_dword[2] = host2; 622 break; 623 } 624 625 case EFX_FILTER_MATCH_LOC_MAC | EFX_FILTER_MATCH_OUTER_VID: 626 is_full = B_TRUE; 627 /* Fall through */ 628 case EFX_FILTER_MATCH_LOC_MAC: 629 if (gen_spec->efs_flags & EFX_FILTER_FLAG_TX) { 630 sf_spec->sfs_type = (is_full ? 631 EFX_SIENA_FILTER_TX_MAC_FULL : 632 EFX_SIENA_FILTER_TX_MAC_WILD); 633 } else { 634 sf_spec->sfs_type = (is_full ? 635 EFX_SIENA_FILTER_RX_MAC_FULL : 636 EFX_SIENA_FILTER_RX_MAC_WILD); 637 } 638 sf_spec->sfs_dword[0] = is_full ? gen_spec->efs_outer_vid : 0; 639 sf_spec->sfs_dword[1] = 640 gen_spec->efs_loc_mac[2] << 24 | 641 gen_spec->efs_loc_mac[3] << 16 | 642 gen_spec->efs_loc_mac[4] << 8 | 643 gen_spec->efs_loc_mac[5]; 644 sf_spec->sfs_dword[2] = 645 gen_spec->efs_loc_mac[0] << 8 | 646 gen_spec->efs_loc_mac[1]; 647 break; 648 649 default: 650 EFSYS_ASSERT(B_FALSE); 651 rc = ENOTSUP; 652 goto fail5; 653 } 654 655 return (0); 656 657fail5: 658 EFSYS_PROBE(fail5); 659fail4: 660 EFSYS_PROBE(fail4); 661fail3: 662 EFSYS_PROBE(fail3); 663fail2: 664 EFSYS_PROBE(fail2); 665fail1: 666 EFSYS_PROBE1(fail1, efx_rc_t, rc); 667 668 return (rc); 669} 670 671/* 672 * The filter hash function is LFSR polynomial x^16 + x^3 + 1 of a 32-bit 673 * key derived from the n-tuple. 674 */ 675static uint16_t 676siena_filter_tbl_hash( 677 __in uint32_t key) 678{ 679 uint16_t tmp; 680 681 /* First 16 rounds */ 682 tmp = 0x1fff ^ (uint16_t)(key >> 16); 683 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 684 tmp = tmp ^ tmp >> 9; 685 686 /* Last 16 rounds */ 687 tmp = tmp ^ tmp << 13 ^ (uint16_t)(key & 0xffff); 688 tmp = tmp ^ tmp >> 3 ^ tmp >> 6; 689 tmp = tmp ^ tmp >> 9; 690 691 return (tmp); 692} 693 694/* 695 * To allow for hash collisions, filter search continues at these 696 * increments from the first possible entry selected by the hash. 697 */ 698static uint16_t 699siena_filter_tbl_increment( 700 __in uint32_t key) 701{ 702 return ((uint16_t)(key * 2 - 1)); 703} 704 705static __checkReturn boolean_t 706siena_filter_test_used( 707 __in siena_filter_tbl_t *sftp, 708 __in unsigned int index) 709{ 710 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 711 return ((sftp->sft_bitmap[index / 32] & (1 << (index % 32))) != 0); 712} 713 714static void 715siena_filter_set_used( 716 __in siena_filter_tbl_t *sftp, 717 __in unsigned int index) 718{ 719 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 720 sftp->sft_bitmap[index / 32] |= (1 << (index % 32)); 721 ++sftp->sft_used; 722} 723 724static void 725siena_filter_clear_used( 726 __in siena_filter_tbl_t *sftp, 727 __in unsigned int index) 728{ 729 EFSYS_ASSERT3P(sftp->sft_bitmap, !=, NULL); 730 sftp->sft_bitmap[index / 32] &= ~(1 << (index % 32)); 731 732 --sftp->sft_used; 733 EFSYS_ASSERT3U(sftp->sft_used, >=, 0); 734} 735 736 737static siena_filter_tbl_id_t 738siena_filter_tbl_id( 739 __in siena_filter_type_t type) 740{ 741 siena_filter_tbl_id_t tbl_id; 742 743 switch (type) { 744 case EFX_SIENA_FILTER_RX_TCP_FULL: 745 case EFX_SIENA_FILTER_RX_TCP_WILD: 746 case EFX_SIENA_FILTER_RX_UDP_FULL: 747 case EFX_SIENA_FILTER_RX_UDP_WILD: 748 tbl_id = EFX_SIENA_FILTER_TBL_RX_IP; 749 break; 750 751 case EFX_SIENA_FILTER_RX_MAC_FULL: 752 case EFX_SIENA_FILTER_RX_MAC_WILD: 753 tbl_id = EFX_SIENA_FILTER_TBL_RX_MAC; 754 break; 755 756 case EFX_SIENA_FILTER_TX_TCP_FULL: 757 case EFX_SIENA_FILTER_TX_TCP_WILD: 758 case EFX_SIENA_FILTER_TX_UDP_FULL: 759 case EFX_SIENA_FILTER_TX_UDP_WILD: 760 tbl_id = EFX_SIENA_FILTER_TBL_TX_IP; 761 break; 762 763 case EFX_SIENA_FILTER_TX_MAC_FULL: 764 case EFX_SIENA_FILTER_TX_MAC_WILD: 765 tbl_id = EFX_SIENA_FILTER_TBL_TX_MAC; 766 break; 767 768 default: 769 EFSYS_ASSERT(B_FALSE); 770 tbl_id = EFX_SIENA_FILTER_NTBLS; 771 break; 772 } 773 return (tbl_id); 774} 775 776static void 777siena_filter_reset_search_depth( 778 __inout siena_filter_t *sfp, 779 __in siena_filter_tbl_id_t tbl_id) 780{ 781 switch (tbl_id) { 782 case EFX_SIENA_FILTER_TBL_RX_IP: 783 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] = 0; 784 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] = 0; 785 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] = 0; 786 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] = 0; 787 break; 788 789 case EFX_SIENA_FILTER_TBL_RX_MAC: 790 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] = 0; 791 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] = 0; 792 break; 793 794 case EFX_SIENA_FILTER_TBL_TX_IP: 795 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] = 0; 796 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] = 0; 797 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] = 0; 798 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] = 0; 799 break; 800 801 case EFX_SIENA_FILTER_TBL_TX_MAC: 802 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] = 0; 803 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] = 0; 804 break; 805 806 default: 807 EFSYS_ASSERT(B_FALSE); 808 break; 809 } 810} 811 812static void 813siena_filter_push_rx_limits( 814 __in efx_nic_t *enp) 815{ 816 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 817 efx_oword_t oword; 818 819 EFX_BAR_READO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 820 821 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_FULL_SRCH_LIMIT, 822 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_FULL] + 823 FILTER_CTL_SRCH_FUDGE_FULL); 824 EFX_SET_OWORD_FIELD(oword, FRF_AZ_TCP_WILD_SRCH_LIMIT, 825 sfp->sf_depth[EFX_SIENA_FILTER_RX_TCP_WILD] + 826 FILTER_CTL_SRCH_FUDGE_WILD); 827 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_FULL_SRCH_LIMIT, 828 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_FULL] + 829 FILTER_CTL_SRCH_FUDGE_FULL); 830 EFX_SET_OWORD_FIELD(oword, FRF_AZ_UDP_WILD_SRCH_LIMIT, 831 sfp->sf_depth[EFX_SIENA_FILTER_RX_UDP_WILD] + 832 FILTER_CTL_SRCH_FUDGE_WILD); 833 834 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC].sft_size) { 835 EFX_SET_OWORD_FIELD(oword, 836 FRF_CZ_ETHERNET_FULL_SEARCH_LIMIT, 837 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_FULL] + 838 FILTER_CTL_SRCH_FUDGE_FULL); 839 EFX_SET_OWORD_FIELD(oword, 840 FRF_CZ_ETHERNET_WILDCARD_SEARCH_LIMIT, 841 sfp->sf_depth[EFX_SIENA_FILTER_RX_MAC_WILD] + 842 FILTER_CTL_SRCH_FUDGE_WILD); 843 } 844 845 EFX_BAR_WRITEO(enp, FR_AZ_RX_FILTER_CTL_REG, &oword); 846} 847 848static void 849siena_filter_push_tx_limits( 850 __in efx_nic_t *enp) 851{ 852 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 853 efx_oword_t oword; 854 855 EFX_BAR_READO(enp, FR_AZ_TX_CFG_REG, &oword); 856 857 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP].sft_size != 0) { 858 EFX_SET_OWORD_FIELD(oword, 859 FRF_CZ_TX_TCPIP_FILTER_FULL_SEARCH_RANGE, 860 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_FULL] + 861 FILTER_CTL_SRCH_FUDGE_FULL); 862 EFX_SET_OWORD_FIELD(oword, 863 FRF_CZ_TX_TCPIP_FILTER_WILD_SEARCH_RANGE, 864 sfp->sf_depth[EFX_SIENA_FILTER_TX_TCP_WILD] + 865 FILTER_CTL_SRCH_FUDGE_WILD); 866 EFX_SET_OWORD_FIELD(oword, 867 FRF_CZ_TX_UDPIP_FILTER_FULL_SEARCH_RANGE, 868 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_FULL] + 869 FILTER_CTL_SRCH_FUDGE_FULL); 870 EFX_SET_OWORD_FIELD(oword, 871 FRF_CZ_TX_UDPIP_FILTER_WILD_SEARCH_RANGE, 872 sfp->sf_depth[EFX_SIENA_FILTER_TX_UDP_WILD] + 873 FILTER_CTL_SRCH_FUDGE_WILD); 874 } 875 876 if (sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC].sft_size != 0) { 877 EFX_SET_OWORD_FIELD( 878 oword, FRF_CZ_TX_ETH_FILTER_FULL_SEARCH_RANGE, 879 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_FULL] + 880 FILTER_CTL_SRCH_FUDGE_FULL); 881 EFX_SET_OWORD_FIELD( 882 oword, FRF_CZ_TX_ETH_FILTER_WILD_SEARCH_RANGE, 883 sfp->sf_depth[EFX_SIENA_FILTER_TX_MAC_WILD] + 884 FILTER_CTL_SRCH_FUDGE_WILD); 885 } 886 887 EFX_BAR_WRITEO(enp, FR_AZ_TX_CFG_REG, &oword); 888} 889 890/* Build a filter entry and return its n-tuple key. */ 891static __checkReturn uint32_t 892siena_filter_build( 893 __out efx_oword_t *filter, 894 __in siena_filter_spec_t *spec) 895{ 896 uint32_t dword3; 897 uint32_t key; 898 uint8_t type = spec->sfs_type; 899 uint32_t flags = spec->sfs_flags; 900 901 switch (siena_filter_tbl_id(type)) { 902 case EFX_SIENA_FILTER_TBL_RX_IP: { 903 boolean_t is_udp = (type == EFX_SIENA_FILTER_RX_UDP_FULL || 904 type == EFX_SIENA_FILTER_RX_UDP_WILD); 905 EFX_POPULATE_OWORD_7(*filter, 906 FRF_BZ_RSS_EN, 907 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 908 FRF_BZ_SCATTER_EN, 909 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 910 FRF_AZ_TCP_UDP, is_udp, 911 FRF_AZ_RXQ_ID, spec->sfs_dmaq_id, 912 EFX_DWORD_2, spec->sfs_dword[2], 913 EFX_DWORD_1, spec->sfs_dword[1], 914 EFX_DWORD_0, spec->sfs_dword[0]); 915 dword3 = is_udp; 916 break; 917 } 918 919 case EFX_SIENA_FILTER_TBL_RX_MAC: { 920 boolean_t is_wild = (type == EFX_SIENA_FILTER_RX_MAC_WILD); 921 EFX_POPULATE_OWORD_7(*filter, 922 FRF_CZ_RMFT_RSS_EN, 923 (flags & EFX_FILTER_FLAG_RX_RSS) ? 1 : 0, 924 FRF_CZ_RMFT_SCATTER_EN, 925 (flags & EFX_FILTER_FLAG_RX_SCATTER) ? 1 : 0, 926 FRF_CZ_RMFT_RXQ_ID, spec->sfs_dmaq_id, 927 FRF_CZ_RMFT_WILDCARD_MATCH, is_wild, 928 FRF_CZ_RMFT_DEST_MAC_DW1, spec->sfs_dword[2], 929 FRF_CZ_RMFT_DEST_MAC_DW0, spec->sfs_dword[1], 930 FRF_CZ_RMFT_VLAN_ID, spec->sfs_dword[0]); 931 dword3 = is_wild; 932 break; 933 } 934 935 case EFX_SIENA_FILTER_TBL_TX_IP: { 936 boolean_t is_udp = (type == EFX_SIENA_FILTER_TX_UDP_FULL || 937 type == EFX_SIENA_FILTER_TX_UDP_WILD); 938 EFX_POPULATE_OWORD_5(*filter, 939 FRF_CZ_TIFT_TCP_UDP, is_udp, 940 FRF_CZ_TIFT_TXQ_ID, spec->sfs_dmaq_id, 941 EFX_DWORD_2, spec->sfs_dword[2], 942 EFX_DWORD_1, spec->sfs_dword[1], 943 EFX_DWORD_0, spec->sfs_dword[0]); 944 dword3 = is_udp | spec->sfs_dmaq_id << 1; 945 break; 946 } 947 948 case EFX_SIENA_FILTER_TBL_TX_MAC: { 949 boolean_t is_wild = (type == EFX_SIENA_FILTER_TX_MAC_WILD); 950 EFX_POPULATE_OWORD_5(*filter, 951 FRF_CZ_TMFT_TXQ_ID, spec->sfs_dmaq_id, 952 FRF_CZ_TMFT_WILDCARD_MATCH, is_wild, 953 FRF_CZ_TMFT_SRC_MAC_DW1, spec->sfs_dword[2], 954 FRF_CZ_TMFT_SRC_MAC_DW0, spec->sfs_dword[1], 955 FRF_CZ_TMFT_VLAN_ID, spec->sfs_dword[0]); 956 dword3 = is_wild | spec->sfs_dmaq_id << 1; 957 break; 958 } 959 960 default: 961 EFSYS_ASSERT(B_FALSE); 962 return (0); 963 } 964 965 key = 966 spec->sfs_dword[0] ^ 967 spec->sfs_dword[1] ^ 968 spec->sfs_dword[2] ^ 969 dword3; 970 971 return (key); 972} 973 974static __checkReturn efx_rc_t 975siena_filter_push_entry( 976 __inout efx_nic_t *enp, 977 __in siena_filter_type_t type, 978 __in int index, 979 __in efx_oword_t *eop) 980{ 981 efx_rc_t rc; 982 983 switch (type) { 984 case EFX_SIENA_FILTER_RX_TCP_FULL: 985 case EFX_SIENA_FILTER_RX_TCP_WILD: 986 case EFX_SIENA_FILTER_RX_UDP_FULL: 987 case EFX_SIENA_FILTER_RX_UDP_WILD: 988 EFX_BAR_TBL_WRITEO(enp, FR_AZ_RX_FILTER_TBL0, index, 989 eop, B_TRUE); 990 break; 991 992 case EFX_SIENA_FILTER_RX_MAC_FULL: 993 case EFX_SIENA_FILTER_RX_MAC_WILD: 994 EFX_BAR_TBL_WRITEO(enp, FR_CZ_RX_MAC_FILTER_TBL0, index, 995 eop, B_TRUE); 996 break; 997 998 case EFX_SIENA_FILTER_TX_TCP_FULL: 999 case EFX_SIENA_FILTER_TX_TCP_WILD: 1000 case EFX_SIENA_FILTER_TX_UDP_FULL: 1001 case EFX_SIENA_FILTER_TX_UDP_WILD: 1002 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_FILTER_TBL0, index, 1003 eop, B_TRUE); 1004 break; 1005 1006 case EFX_SIENA_FILTER_TX_MAC_FULL: 1007 case EFX_SIENA_FILTER_TX_MAC_WILD: 1008 EFX_BAR_TBL_WRITEO(enp, FR_CZ_TX_MAC_FILTER_TBL0, index, 1009 eop, B_TRUE); 1010 break; 1011 1012 default: 1013 EFSYS_ASSERT(B_FALSE); 1014 rc = ENOTSUP; 1015 goto fail1; 1016 } 1017 return (0); 1018 1019fail1: 1020 return (rc); 1021} 1022 1023 1024static __checkReturn boolean_t 1025siena_filter_equal( 1026 __in const siena_filter_spec_t *left, 1027 __in const siena_filter_spec_t *right) 1028{ 1029 siena_filter_tbl_id_t tbl_id; 1030 1031 tbl_id = siena_filter_tbl_id(left->sfs_type); 1032 1033 1034 if (left->sfs_type != right->sfs_type) 1035 return (B_FALSE); 1036 1037 if (memcmp(left->sfs_dword, right->sfs_dword, 1038 sizeof (left->sfs_dword))) 1039 return (B_FALSE); 1040 1041 if ((tbl_id == EFX_SIENA_FILTER_TBL_TX_IP || 1042 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) && 1043 left->sfs_dmaq_id != right->sfs_dmaq_id) 1044 return (B_FALSE); 1045 1046 return (B_TRUE); 1047} 1048 1049static __checkReturn efx_rc_t 1050siena_filter_search( 1051 __in siena_filter_tbl_t *sftp, 1052 __in siena_filter_spec_t *spec, 1053 __in uint32_t key, 1054 __in boolean_t for_insert, 1055 __out int *filter_index, 1056 __out unsigned int *depth_required) 1057{ 1058 unsigned int hash, incr, filter_idx, depth; 1059 1060 hash = siena_filter_tbl_hash(key); 1061 incr = siena_filter_tbl_increment(key); 1062 1063 filter_idx = hash & (sftp->sft_size - 1); 1064 depth = 1; 1065 1066 for (;;) { 1067 /* 1068 * Return success if entry is used and matches this spec 1069 * or entry is unused and we are trying to insert. 1070 */ 1071 if (siena_filter_test_used(sftp, filter_idx) ? 1072 siena_filter_equal(spec, 1073 &sftp->sft_spec[filter_idx]) : 1074 for_insert) { 1075 *filter_index = filter_idx; 1076 *depth_required = depth; 1077 return (0); 1078 } 1079 1080 /* Return failure if we reached the maximum search depth */ 1081 if (depth == FILTER_CTL_SRCH_MAX) 1082 return (for_insert ? EBUSY : ENOENT); 1083 1084 filter_idx = (filter_idx + incr) & (sftp->sft_size - 1); 1085 ++depth; 1086 } 1087} 1088 1089static void 1090siena_filter_clear_entry( 1091 __in efx_nic_t *enp, 1092 __in siena_filter_tbl_t *sftp, 1093 __in int index) 1094{ 1095 efx_oword_t filter; 1096 1097 if (siena_filter_test_used(sftp, index)) { 1098 siena_filter_clear_used(sftp, index); 1099 1100 EFX_ZERO_OWORD(filter); 1101 siena_filter_push_entry(enp, 1102 sftp->sft_spec[index].sfs_type, 1103 index, &filter); 1104 1105 memset(&sftp->sft_spec[index], 1106 0, sizeof (sftp->sft_spec[0])); 1107 } 1108} 1109 1110 void 1111siena_filter_tbl_clear( 1112 __in efx_nic_t *enp, 1113 __in siena_filter_tbl_id_t tbl_id) 1114{ 1115 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1116 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id]; 1117 int index; 1118 efsys_lock_state_t state; 1119 1120 EFSYS_LOCK(enp->en_eslp, state); 1121 1122 for (index = 0; index < sftp->sft_size; ++index) { 1123 siena_filter_clear_entry(enp, sftp, index); 1124 } 1125 1126 if (sftp->sft_used == 0) 1127 siena_filter_reset_search_depth(sfp, tbl_id); 1128 1129 EFSYS_UNLOCK(enp->en_eslp, state); 1130} 1131 1132static __checkReturn efx_rc_t 1133siena_filter_init( 1134 __in efx_nic_t *enp) 1135{ 1136 siena_filter_t *sfp; 1137 siena_filter_tbl_t *sftp; 1138 int tbl_id; 1139 efx_rc_t rc; 1140 1141 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (siena_filter_t), sfp); 1142 1143 if (!sfp) { 1144 rc = ENOMEM; 1145 goto fail1; 1146 } 1147 1148 enp->en_filter.ef_siena_filter = sfp; 1149 1150 switch (enp->en_family) { 1151 case EFX_FAMILY_SIENA: 1152 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_IP]; 1153 sftp->sft_size = FR_AZ_RX_FILTER_TBL0_ROWS; 1154 1155 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_RX_MAC]; 1156 sftp->sft_size = FR_CZ_RX_MAC_FILTER_TBL0_ROWS; 1157 1158 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_IP]; 1159 sftp->sft_size = FR_CZ_TX_FILTER_TBL0_ROWS; 1160 1161 sftp = &sfp->sf_tbl[EFX_SIENA_FILTER_TBL_TX_MAC]; 1162 sftp->sft_size = FR_CZ_TX_MAC_FILTER_TBL0_ROWS; 1163 break; 1164 1165 default: 1166 rc = ENOTSUP; 1167 goto fail2; 1168 } 1169 1170 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) { 1171 unsigned int bitmap_size; 1172 1173 sftp = &sfp->sf_tbl[tbl_id]; 1174 if (sftp->sft_size == 0) 1175 continue; 1176 1177 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) == 1178 sizeof (uint32_t)); 1179 bitmap_size = 1180 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8; 1181 1182 EFSYS_KMEM_ALLOC(enp->en_esip, bitmap_size, sftp->sft_bitmap); 1183 if (!sftp->sft_bitmap) { 1184 rc = ENOMEM; 1185 goto fail3; 1186 } 1187 1188 EFSYS_KMEM_ALLOC(enp->en_esip, 1189 sftp->sft_size * sizeof (*sftp->sft_spec), 1190 sftp->sft_spec); 1191 if (!sftp->sft_spec) { 1192 rc = ENOMEM; 1193 goto fail4; 1194 } 1195 memset(sftp->sft_spec, 0, 1196 sftp->sft_size * sizeof (*sftp->sft_spec)); 1197 } 1198 1199 return (0); 1200 1201fail4: 1202 EFSYS_PROBE(fail4); 1203 1204fail3: 1205 EFSYS_PROBE(fail3); 1206 1207fail2: 1208 EFSYS_PROBE(fail2); 1209 siena_filter_fini(enp); 1210 1211fail1: 1212 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1213 return (rc); 1214} 1215 1216static void 1217siena_filter_fini( 1218 __in efx_nic_t *enp) 1219{ 1220 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1221 siena_filter_tbl_id_t tbl_id; 1222 1223 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 1224 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 1225 1226 if (sfp == NULL) 1227 return; 1228 1229 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) { 1230 siena_filter_tbl_t *sftp = &sfp->sf_tbl[tbl_id]; 1231 unsigned int bitmap_size; 1232 1233 EFX_STATIC_ASSERT(sizeof (sftp->sft_bitmap[0]) == 1234 sizeof (uint32_t)); 1235 bitmap_size = 1236 (sftp->sft_size + (sizeof (uint32_t) * 8) - 1) / 8; 1237 1238 if (sftp->sft_bitmap != NULL) { 1239 EFSYS_KMEM_FREE(enp->en_esip, bitmap_size, 1240 sftp->sft_bitmap); 1241 sftp->sft_bitmap = NULL; 1242 } 1243 1244 if (sftp->sft_spec != NULL) { 1245 EFSYS_KMEM_FREE(enp->en_esip, sftp->sft_size * 1246 sizeof (*sftp->sft_spec), sftp->sft_spec); 1247 sftp->sft_spec = NULL; 1248 } 1249 } 1250 1251 EFSYS_KMEM_FREE(enp->en_esip, sizeof (siena_filter_t), 1252 enp->en_filter.ef_siena_filter); 1253} 1254 1255/* Restore filter state after a reset */ 1256static __checkReturn efx_rc_t 1257siena_filter_restore( 1258 __in efx_nic_t *enp) 1259{ 1260 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1261 siena_filter_tbl_id_t tbl_id; 1262 siena_filter_tbl_t *sftp; 1263 siena_filter_spec_t *spec; 1264 efx_oword_t filter; 1265 int filter_idx; 1266 efsys_lock_state_t state; 1267 uint32_t key; 1268 efx_rc_t rc; 1269 1270 EFSYS_LOCK(enp->en_eslp, state); 1271 1272 for (tbl_id = 0; tbl_id < EFX_SIENA_FILTER_NTBLS; tbl_id++) { 1273 sftp = &sfp->sf_tbl[tbl_id]; 1274 for (filter_idx = 0; 1275 filter_idx < sftp->sft_size; 1276 filter_idx++) { 1277 if (!siena_filter_test_used(sftp, filter_idx)) 1278 continue; 1279 1280 spec = &sftp->sft_spec[filter_idx]; 1281 if ((key = siena_filter_build(&filter, spec)) == 0) { 1282 rc = EINVAL; 1283 goto fail1; 1284 } 1285 if ((rc = siena_filter_push_entry(enp, 1286 spec->sfs_type, filter_idx, &filter)) != 0) 1287 goto fail2; 1288 } 1289 } 1290 1291 siena_filter_push_rx_limits(enp); 1292 siena_filter_push_tx_limits(enp); 1293 1294 EFSYS_UNLOCK(enp->en_eslp, state); 1295 1296 return (0); 1297 1298fail2: 1299 EFSYS_PROBE(fail2); 1300 1301fail1: 1302 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1303 1304 EFSYS_UNLOCK(enp->en_eslp, state); 1305 1306 return (rc); 1307} 1308 1309static __checkReturn efx_rc_t 1310siena_filter_add( 1311 __in efx_nic_t *enp, 1312 __inout efx_filter_spec_t *spec, 1313 __in boolean_t may_replace) 1314{ 1315 efx_rc_t rc; 1316 siena_filter_spec_t sf_spec; 1317 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1318 siena_filter_tbl_id_t tbl_id; 1319 siena_filter_tbl_t *sftp; 1320 siena_filter_spec_t *saved_sf_spec; 1321 efx_oword_t filter; 1322 int filter_idx; 1323 unsigned int depth; 1324 efsys_lock_state_t state; 1325 uint32_t key; 1326 1327 1328 EFSYS_ASSERT3P(spec, !=, NULL); 1329 1330 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0) 1331 goto fail1; 1332 1333 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type); 1334 sftp = &sfp->sf_tbl[tbl_id]; 1335 1336 if (sftp->sft_size == 0) { 1337 rc = EINVAL; 1338 goto fail2; 1339 } 1340 1341 key = siena_filter_build(&filter, &sf_spec); 1342 1343 EFSYS_LOCK(enp->en_eslp, state); 1344 1345 rc = siena_filter_search(sftp, &sf_spec, key, B_TRUE, 1346 &filter_idx, &depth); 1347 if (rc != 0) 1348 goto fail3; 1349 1350 EFSYS_ASSERT3U(filter_idx, <, sftp->sft_size); 1351 saved_sf_spec = &sftp->sft_spec[filter_idx]; 1352 1353 if (siena_filter_test_used(sftp, filter_idx)) { 1354 if (may_replace == B_FALSE) { 1355 rc = EEXIST; 1356 goto fail4; 1357 } 1358 } 1359 siena_filter_set_used(sftp, filter_idx); 1360 *saved_sf_spec = sf_spec; 1361 1362 if (sfp->sf_depth[sf_spec.sfs_type] < depth) { 1363 sfp->sf_depth[sf_spec.sfs_type] = depth; 1364 if (tbl_id == EFX_SIENA_FILTER_TBL_TX_IP || 1365 tbl_id == EFX_SIENA_FILTER_TBL_TX_MAC) 1366 siena_filter_push_tx_limits(enp); 1367 else 1368 siena_filter_push_rx_limits(enp); 1369 } 1370 1371 siena_filter_push_entry(enp, sf_spec.sfs_type, 1372 filter_idx, &filter); 1373 1374 EFSYS_UNLOCK(enp->en_eslp, state); 1375 return (0); 1376 1377fail4: 1378 EFSYS_PROBE(fail4); 1379 1380fail3: 1381 EFSYS_UNLOCK(enp->en_eslp, state); 1382 EFSYS_PROBE(fail3); 1383 1384fail2: 1385 EFSYS_PROBE(fail2); 1386 1387fail1: 1388 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1389 return (rc); 1390} 1391 1392static __checkReturn efx_rc_t 1393siena_filter_delete( 1394 __in efx_nic_t *enp, 1395 __inout efx_filter_spec_t *spec) 1396{ 1397 efx_rc_t rc; 1398 siena_filter_spec_t sf_spec; 1399 siena_filter_t *sfp = enp->en_filter.ef_siena_filter; 1400 siena_filter_tbl_id_t tbl_id; 1401 siena_filter_tbl_t *sftp; 1402 efx_oword_t filter; 1403 int filter_idx; 1404 unsigned int depth; 1405 efsys_lock_state_t state; 1406 uint32_t key; 1407 1408 EFSYS_ASSERT3P(spec, !=, NULL); 1409 1410 if ((rc = siena_filter_spec_from_gen_spec(&sf_spec, spec)) != 0) 1411 goto fail1; 1412 1413 tbl_id = siena_filter_tbl_id(sf_spec.sfs_type); 1414 sftp = &sfp->sf_tbl[tbl_id]; 1415 1416 key = siena_filter_build(&filter, &sf_spec); 1417 1418 EFSYS_LOCK(enp->en_eslp, state); 1419 1420 rc = siena_filter_search(sftp, &sf_spec, key, B_FALSE, 1421 &filter_idx, &depth); 1422 if (rc != 0) 1423 goto fail2; 1424 1425 siena_filter_clear_entry(enp, sftp, filter_idx); 1426 if (sftp->sft_used == 0) 1427 siena_filter_reset_search_depth(sfp, tbl_id); 1428 1429 EFSYS_UNLOCK(enp->en_eslp, state); 1430 return (0); 1431 1432fail2: 1433 EFSYS_UNLOCK(enp->en_eslp, state); 1434 EFSYS_PROBE(fail2); 1435 1436fail1: 1437 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1438 return (rc); 1439} 1440 1441#define SIENA_MAX_SUPPORTED_MATCHES 4 1442 1443static __checkReturn efx_rc_t 1444siena_filter_supported_filters( 1445 __in efx_nic_t *enp, 1446 __out_ecount(buffer_length) uint32_t *buffer, 1447 __in size_t buffer_length, 1448 __out size_t *list_lengthp) 1449{ 1450 uint32_t index = 0; 1451 uint32_t rx_matches[SIENA_MAX_SUPPORTED_MATCHES]; 1452 size_t list_length; 1453 efx_rc_t rc; 1454 1455 rx_matches[index++] = 1456 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1457 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT | 1458 EFX_FILTER_MATCH_REM_HOST | EFX_FILTER_MATCH_REM_PORT; 1459 1460 rx_matches[index++] = 1461 EFX_FILTER_MATCH_ETHER_TYPE | EFX_FILTER_MATCH_IP_PROTO | 1462 EFX_FILTER_MATCH_LOC_HOST | EFX_FILTER_MATCH_LOC_PORT; 1463 1464 if (enp->en_features & EFX_FEATURE_MAC_HEADER_FILTERS) { 1465 rx_matches[index++] = 1466 EFX_FILTER_MATCH_OUTER_VID | EFX_FILTER_MATCH_LOC_MAC; 1467 1468 rx_matches[index++] = EFX_FILTER_MATCH_LOC_MAC; 1469 } 1470 1471 EFSYS_ASSERT3U(index, <=, SIENA_MAX_SUPPORTED_MATCHES); 1472 list_length = index; 1473 1474 *list_lengthp = list_length; 1475 1476 if (buffer_length < list_length) { 1477 rc = ENOSPC; 1478 goto fail1; 1479 } 1480 1481 memcpy(buffer, rx_matches, list_length * sizeof (rx_matches[0])); 1482 1483 return (0); 1484 1485fail1: 1486 EFSYS_PROBE1(fail1, efx_rc_t, rc); 1487 1488 return (rc); 1489} 1490 1491#undef MAX_SUPPORTED 1492 1493#endif /* EFSYS_OPT_SIENA */ 1494 1495#endif /* EFSYS_OPT_FILTER */ 1496