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