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