1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2020 Xilinx, Inc. 4 * Copyright(c) 2007-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 /* 11 * State diagram of the UDP tunnel table entries 12 * (efx_tunnel_udp_entry_state_t and busy flag): 13 * 14 * +---------+ 15 * +--------| APPLIED |<-------+ 16 * | +---------+ | 17 * | | 18 * | efx_tunnel_reconfigure (end) 19 * efx_tunnel_config_udp_remove | 20 * | +------------+ 21 * v | BUSY ADDED | 22 * +---------+ +------------+ 23 * | REMOVED | ^ 24 * +---------+ | 25 * | efx_tunnel_reconfigure (begin) 26 * efx_tunnel_reconfigure (begin) | 27 * | | 28 * v +-----------+ 29 * +--------------+ | ADDED |<---------+ 30 * | BUSY REMOVED | +-----------+ | 31 * +--------------+ | | 32 * | efx_tunnel_config_udp_remove | 33 * efx_tunnel_reconfigure (end) | | 34 * | | | 35 * | +---------+ | | 36 * | |+-------+| | | 37 * +------->|| empty ||<-------+ | 38 * |+-------+| | 39 * +---------+ efx_tunnel_config_udp_add 40 * | | 41 * +------------------------------+ 42 * 43 * Note that there is no BUSY APPLIED state since removing an applied entry 44 * should not be blocked by ongoing reconfiguration in another thread - 45 * reconfiguration will remove only busy entries. 46 */ 47 48 #if EFSYS_OPT_TUNNEL 49 50 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 51 static __checkReturn boolean_t 52 ef10_udp_encap_supported( 53 __in efx_nic_t *enp); 54 55 static __checkReturn efx_rc_t 56 ef10_tunnel_reconfigure( 57 __in efx_nic_t *enp); 58 59 static void 60 ef10_tunnel_fini( 61 __in efx_nic_t *enp); 62 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 63 64 #if EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON 65 static const efx_tunnel_ops_t __efx_tunnel_dummy_ops = { 66 NULL, /* eto_reconfigure */ 67 NULL, /* eto_fini */ 68 }; 69 #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON */ 70 71 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 72 static const efx_tunnel_ops_t __efx_tunnel_ef10_ops = { 73 ef10_tunnel_reconfigure, /* eto_reconfigure */ 74 ef10_tunnel_fini, /* eto_fini */ 75 }; 76 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 77 78 #if EFSYS_OPT_RIVERHEAD 79 static const efx_tunnel_ops_t __efx_tunnel_rhead_ops = { 80 rhead_tunnel_reconfigure, /* eto_reconfigure */ 81 rhead_tunnel_fini, /* eto_fini */ 82 }; 83 #endif /* EFSYS_OPT_RIVERHEAD */ 84 85 /* Indicates that an entry is to be set */ 86 static __checkReturn boolean_t 87 ef10_entry_staged( 88 __in efx_tunnel_udp_entry_t *entry) 89 { 90 switch (entry->etue_state) { 91 case EFX_TUNNEL_UDP_ENTRY_ADDED: 92 return (entry->etue_busy); 93 case EFX_TUNNEL_UDP_ENTRY_REMOVED: 94 return (!entry->etue_busy); 95 case EFX_TUNNEL_UDP_ENTRY_APPLIED: 96 return (B_TRUE); 97 default: 98 EFSYS_ASSERT(0); 99 return (B_FALSE); 100 } 101 } 102 103 static __checkReturn efx_rc_t 104 efx_mcdi_set_tunnel_encap_udp_ports( 105 __in efx_nic_t *enp, 106 __in efx_tunnel_cfg_t *etcp, 107 __in boolean_t unloading, 108 __out boolean_t *resetting) 109 { 110 efx_mcdi_req_t req; 111 EFX_MCDI_DECLARE_BUF(payload, 112 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX, 113 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN); 114 efx_word_t flags; 115 efx_rc_t rc; 116 unsigned int i; 117 unsigned int entries_num; 118 unsigned int entry; 119 120 entries_num = 0; 121 if (etcp != NULL) { 122 for (i = 0; i < etcp->etc_udp_entries_num; i++) { 123 if (ef10_entry_staged(&etcp->etc_udp_entries[i]) != 124 B_FALSE) { 125 entries_num++; 126 } 127 } 128 } 129 130 req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS; 131 req.emr_in_buf = payload; 132 req.emr_in_length = 133 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num); 134 req.emr_out_buf = payload; 135 req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN; 136 137 EFX_POPULATE_WORD_1(flags, 138 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING, 139 (unloading == B_TRUE) ? 1 : 0); 140 MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS, 141 EFX_WORD_FIELD(flags, EFX_WORD_0)); 142 143 MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES, 144 entries_num); 145 146 for (i = 0, entry = 0; entry < entries_num; ++entry, ++i) { 147 uint16_t mcdi_udp_protocol; 148 149 while (ef10_entry_staged(&etcp->etc_udp_entries[i]) == B_FALSE) 150 i++; 151 152 switch (etcp->etc_udp_entries[i].etue_protocol) { 153 case EFX_TUNNEL_PROTOCOL_VXLAN: 154 mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN; 155 break; 156 case EFX_TUNNEL_PROTOCOL_GENEVE: 157 mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE; 158 break; 159 default: 160 rc = EINVAL; 161 goto fail1; 162 } 163 164 /* 165 * UDP port is MCDI native little-endian in the request 166 * and EFX_POPULATE_DWORD cares about conversion from 167 * host/CPU byte order to little-endian. 168 */ 169 EFX_STATIC_ASSERT(sizeof (efx_dword_t) == 170 TUNNEL_ENCAP_UDP_PORT_ENTRY_LEN); 171 EFX_POPULATE_DWORD_2( 172 MCDI_IN2(req, efx_dword_t, 173 SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES)[entry], 174 TUNNEL_ENCAP_UDP_PORT_ENTRY_UDP_PORT, 175 etcp->etc_udp_entries[i].etue_port, 176 TUNNEL_ENCAP_UDP_PORT_ENTRY_PROTOCOL, 177 mcdi_udp_protocol); 178 } 179 180 efx_mcdi_execute(enp, &req); 181 182 if (req.emr_rc != 0) { 183 rc = req.emr_rc; 184 goto fail2; 185 } 186 187 if (req.emr_out_length_used != 188 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) { 189 rc = EMSGSIZE; 190 goto fail3; 191 } 192 193 *resetting = MCDI_OUT_WORD_FIELD(req, 194 SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS, 195 SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING); 196 197 return (0); 198 199 fail3: 200 EFSYS_PROBE(fail3); 201 202 fail2: 203 EFSYS_PROBE(fail2); 204 205 fail1: 206 EFSYS_PROBE1(fail1, efx_rc_t, rc); 207 208 return (rc); 209 } 210 211 __checkReturn efx_rc_t 212 efx_tunnel_init( 213 __in efx_nic_t *enp) 214 { 215 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 216 const efx_tunnel_ops_t *etop; 217 efx_rc_t rc; 218 219 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 220 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 221 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TUNNEL)); 222 223 EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES == 224 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM); 225 226 switch (enp->en_family) { 227 #if EFSYS_OPT_SIENA 228 case EFX_FAMILY_SIENA: 229 etop = &__efx_tunnel_dummy_ops; 230 break; 231 #endif /* EFSYS_OPT_SIENA */ 232 233 #if EFSYS_OPT_HUNTINGTON 234 case EFX_FAMILY_HUNTINGTON: 235 etop = &__efx_tunnel_dummy_ops; 236 break; 237 #endif /* EFSYS_OPT_HUNTINGTON */ 238 239 #if EFSYS_OPT_MEDFORD 240 case EFX_FAMILY_MEDFORD: 241 etop = &__efx_tunnel_ef10_ops; 242 break; 243 #endif /* EFSYS_OPT_MEDFORD */ 244 245 #if EFSYS_OPT_MEDFORD2 246 case EFX_FAMILY_MEDFORD2: 247 etop = &__efx_tunnel_ef10_ops; 248 break; 249 #endif /* EFSYS_OPT_MEDFORD2 */ 250 251 #if EFSYS_OPT_RIVERHEAD 252 case EFX_FAMILY_RIVERHEAD: 253 etop = &__efx_tunnel_rhead_ops; 254 break; 255 #endif /* EFSYS_OPT_RIVERHEAD */ 256 257 default: 258 EFSYS_ASSERT(0); 259 rc = ENOTSUP; 260 goto fail1; 261 } 262 263 memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries)); 264 etcp->etc_udp_entries_num = 0; 265 266 enp->en_etop = etop; 267 enp->en_mod_flags |= EFX_MOD_TUNNEL; 268 269 return (0); 270 271 fail1: 272 EFSYS_PROBE1(fail1, efx_rc_t, rc); 273 274 enp->en_etop = NULL; 275 enp->en_mod_flags &= ~EFX_MOD_TUNNEL; 276 277 return (rc); 278 } 279 280 void 281 efx_tunnel_fini( 282 __in efx_nic_t *enp) 283 { 284 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 285 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 286 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 287 288 if (enp->en_etop->eto_fini != NULL) 289 enp->en_etop->eto_fini(enp); 290 291 enp->en_etop = NULL; 292 enp->en_mod_flags &= ~EFX_MOD_TUNNEL; 293 } 294 295 static __checkReturn efx_rc_t 296 efx_tunnel_config_find_udp_tunnel_entry( 297 __in efx_tunnel_cfg_t *etcp, 298 __in uint16_t port, 299 __out unsigned int *entryp) 300 { 301 unsigned int i; 302 303 for (i = 0; i < etcp->etc_udp_entries_num; ++i) { 304 efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i]; 305 306 if (p->etue_port == port && 307 p->etue_state != EFX_TUNNEL_UDP_ENTRY_REMOVED) { 308 *entryp = i; 309 return (0); 310 } 311 } 312 313 return (ENOENT); 314 } 315 316 __checkReturn efx_rc_t 317 efx_tunnel_config_udp_add( 318 __in efx_nic_t *enp, 319 __in uint16_t port /* host/cpu-endian */, 320 __in efx_tunnel_protocol_t protocol) 321 { 322 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 323 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 324 efsys_lock_state_t state; 325 efx_rc_t rc; 326 unsigned int entry; 327 328 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 329 330 if (protocol >= EFX_TUNNEL_NPROTOS) { 331 rc = EINVAL; 332 goto fail1; 333 } 334 335 if ((encp->enc_tunnel_encapsulations_supported & 336 (1u << protocol)) == 0) { 337 rc = ENOTSUP; 338 goto fail2; 339 } 340 341 EFSYS_LOCK(enp->en_eslp, state); 342 343 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry); 344 if (rc == 0) { 345 rc = EEXIST; 346 goto fail3; 347 } 348 349 if (etcp->etc_udp_entries_num == 350 encp->enc_tunnel_config_udp_entries_max) { 351 rc = ENOSPC; 352 goto fail4; 353 } 354 355 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port; 356 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol = 357 protocol; 358 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_state = 359 EFX_TUNNEL_UDP_ENTRY_ADDED; 360 361 etcp->etc_udp_entries_num++; 362 363 EFSYS_UNLOCK(enp->en_eslp, state); 364 365 return (0); 366 367 fail4: 368 EFSYS_PROBE(fail4); 369 370 fail3: 371 EFSYS_PROBE(fail3); 372 EFSYS_UNLOCK(enp->en_eslp, state); 373 374 fail2: 375 EFSYS_PROBE(fail2); 376 377 fail1: 378 EFSYS_PROBE1(fail1, efx_rc_t, rc); 379 380 return (rc); 381 } 382 383 /* 384 * Returns the index of the entry after the deleted one, 385 * or one past the last entry. 386 */ 387 static unsigned int 388 efx_tunnel_config_udp_do_remove( 389 __in efx_tunnel_cfg_t *etcp, 390 __in unsigned int entry) 391 { 392 EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0); 393 etcp->etc_udp_entries_num--; 394 395 if (entry < etcp->etc_udp_entries_num) { 396 memmove(&etcp->etc_udp_entries[entry], 397 &etcp->etc_udp_entries[entry + 1], 398 (etcp->etc_udp_entries_num - entry) * 399 sizeof (etcp->etc_udp_entries[0])); 400 } 401 402 memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0, 403 sizeof (etcp->etc_udp_entries[0])); 404 405 return (entry); 406 } 407 408 /* 409 * Returns the index of the entry after the specified one, 410 * or one past the last entry. The index is correct whether 411 * the specified entry was removed or not. 412 */ 413 static unsigned int 414 efx_tunnel_config_udp_remove_prepare( 415 __in efx_tunnel_cfg_t *etcp, 416 __in unsigned int entry) 417 { 418 unsigned int next = entry + 1; 419 420 switch (etcp->etc_udp_entries[entry].etue_state) { 421 case EFX_TUNNEL_UDP_ENTRY_ADDED: 422 next = efx_tunnel_config_udp_do_remove(etcp, entry); 423 break; 424 case EFX_TUNNEL_UDP_ENTRY_REMOVED: 425 break; 426 case EFX_TUNNEL_UDP_ENTRY_APPLIED: 427 etcp->etc_udp_entries[entry].etue_state = 428 EFX_TUNNEL_UDP_ENTRY_REMOVED; 429 break; 430 default: 431 EFSYS_ASSERT(0); 432 break; 433 } 434 435 return (next); 436 } 437 438 __checkReturn efx_rc_t 439 efx_tunnel_config_udp_remove( 440 __in efx_nic_t *enp, 441 __in uint16_t port /* host/cpu-endian */, 442 __in efx_tunnel_protocol_t protocol) 443 { 444 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 445 efsys_lock_state_t state; 446 unsigned int entry; 447 efx_rc_t rc; 448 449 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 450 451 EFSYS_LOCK(enp->en_eslp, state); 452 453 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry); 454 if (rc != 0) 455 goto fail1; 456 457 if (etcp->etc_udp_entries[entry].etue_busy != B_FALSE) { 458 rc = EBUSY; 459 goto fail2; 460 } 461 462 if (etcp->etc_udp_entries[entry].etue_protocol != protocol) { 463 rc = EINVAL; 464 goto fail3; 465 } 466 467 (void) efx_tunnel_config_udp_remove_prepare(etcp, entry); 468 469 EFSYS_UNLOCK(enp->en_eslp, state); 470 471 return (0); 472 473 fail3: 474 EFSYS_PROBE(fail3); 475 476 fail2: 477 EFSYS_PROBE(fail2); 478 479 fail1: 480 EFSYS_PROBE1(fail1, efx_rc_t, rc); 481 EFSYS_UNLOCK(enp->en_eslp, state); 482 483 return (rc); 484 } 485 486 static boolean_t 487 efx_tunnel_table_all_available( 488 __in efx_tunnel_cfg_t *etcp) 489 { 490 unsigned int i; 491 492 for (i = 0; i < etcp->etc_udp_entries_num; i++) { 493 if (etcp->etc_udp_entries[i].etue_busy != B_FALSE) 494 return (B_FALSE); 495 } 496 497 return (B_TRUE); 498 } 499 500 __checkReturn efx_rc_t 501 efx_tunnel_config_clear( 502 __in efx_nic_t *enp) 503 { 504 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 505 efsys_lock_state_t state; 506 unsigned int i; 507 efx_rc_t rc; 508 509 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 510 511 EFSYS_LOCK(enp->en_eslp, state); 512 513 if (efx_tunnel_table_all_available(etcp) == B_FALSE) { 514 rc = EBUSY; 515 goto fail1; 516 } 517 518 i = 0; 519 while (i < etcp->etc_udp_entries_num) 520 i = efx_tunnel_config_udp_remove_prepare(etcp, i); 521 522 EFSYS_UNLOCK(enp->en_eslp, state); 523 524 return (0); 525 526 fail1: 527 EFSYS_PROBE1(fail1, efx_rc_t, rc); 528 EFSYS_UNLOCK(enp->en_eslp, state); 529 530 return (rc); 531 } 532 533 __checkReturn efx_rc_t 534 efx_tunnel_reconfigure( 535 __in efx_nic_t *enp) 536 { 537 const efx_tunnel_ops_t *etop = enp->en_etop; 538 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 539 efx_tunnel_udp_entry_t *entry; 540 boolean_t locked = B_FALSE; 541 efsys_lock_state_t state; 542 boolean_t resetting; 543 unsigned int i; 544 efx_rc_t rc; 545 546 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 547 548 if (etop->eto_reconfigure == NULL) { 549 rc = ENOTSUP; 550 goto fail1; 551 } 552 553 EFSYS_LOCK(enp->en_eslp, state); 554 locked = B_TRUE; 555 556 if (efx_tunnel_table_all_available(etcp) == B_FALSE) { 557 rc = EBUSY; 558 goto fail2; 559 } 560 561 for (i = 0; i < etcp->etc_udp_entries_num; i++) { 562 entry = &etcp->etc_udp_entries[i]; 563 if (entry->etue_state != EFX_TUNNEL_UDP_ENTRY_APPLIED) 564 entry->etue_busy = B_TRUE; 565 } 566 567 EFSYS_UNLOCK(enp->en_eslp, state); 568 locked = B_FALSE; 569 570 rc = enp->en_etop->eto_reconfigure(enp); 571 if (rc != 0 && rc != EAGAIN) 572 goto fail3; 573 574 resetting = (rc == EAGAIN) ? B_TRUE : B_FALSE; 575 576 EFSYS_LOCK(enp->en_eslp, state); 577 locked = B_TRUE; 578 579 /* 580 * Delete entries marked for removal since they are no longer 581 * needed after successful NIC-specific reconfiguration. 582 * Added entries become applied because they are installed in 583 * the hardware. 584 */ 585 586 i = 0; 587 while (i < etcp->etc_udp_entries_num) { 588 unsigned int next = i + 1; 589 590 entry = &etcp->etc_udp_entries[i]; 591 if (entry->etue_busy != B_FALSE) { 592 entry->etue_busy = B_FALSE; 593 594 switch (entry->etue_state) { 595 case EFX_TUNNEL_UDP_ENTRY_APPLIED: 596 break; 597 case EFX_TUNNEL_UDP_ENTRY_ADDED: 598 entry->etue_state = 599 EFX_TUNNEL_UDP_ENTRY_APPLIED; 600 break; 601 case EFX_TUNNEL_UDP_ENTRY_REMOVED: 602 next = efx_tunnel_config_udp_do_remove(etcp, i); 603 break; 604 default: 605 EFSYS_ASSERT(0); 606 break; 607 } 608 } 609 610 i = next; 611 } 612 613 EFSYS_UNLOCK(enp->en_eslp, state); 614 locked = B_FALSE; 615 616 return ((resetting == B_FALSE) ? 0 : EAGAIN); 617 618 fail3: 619 EFSYS_PROBE(fail3); 620 621 EFSYS_ASSERT(locked == B_FALSE); 622 EFSYS_LOCK(enp->en_eslp, state); 623 624 for (i = 0; i < etcp->etc_udp_entries_num; i++) 625 etcp->etc_udp_entries[i].etue_busy = B_FALSE; 626 627 EFSYS_UNLOCK(enp->en_eslp, state); 628 629 fail2: 630 EFSYS_PROBE(fail2); 631 632 fail1: 633 EFSYS_PROBE1(fail1, efx_rc_t, rc); 634 if (locked) 635 EFSYS_UNLOCK(enp->en_eslp, state); 636 637 return (rc); 638 } 639 640 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 641 static __checkReturn boolean_t 642 ef10_udp_encap_supported( 643 __in efx_nic_t *enp) 644 { 645 const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 646 uint32_t udp_tunnels_mask = 0; 647 648 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN); 649 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE); 650 651 return ((encp->enc_tunnel_encapsulations_supported & 652 udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE); 653 } 654 655 static __checkReturn efx_rc_t 656 ef10_tunnel_reconfigure( 657 __in efx_nic_t *enp) 658 { 659 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 660 efx_rc_t rc; 661 boolean_t resetting = B_FALSE; 662 efsys_lock_state_t state; 663 efx_tunnel_cfg_t etc; 664 665 EFSYS_LOCK(enp->en_eslp, state); 666 memcpy(&etc, etcp, sizeof (etc)); 667 EFSYS_UNLOCK(enp->en_eslp, state); 668 669 if (ef10_udp_encap_supported(enp) == B_FALSE) { 670 /* 671 * It is OK to apply empty UDP tunnel ports when UDP 672 * tunnel encapsulations are not supported - just nothing 673 * should be done. 674 */ 675 if (etc.etc_udp_entries_num == 0) 676 return (0); 677 rc = ENOTSUP; 678 goto fail1; 679 } else { 680 /* 681 * All PCI functions can see a reset upon the 682 * MCDI request completion 683 */ 684 rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE, 685 &resetting); 686 if (rc != 0) { 687 /* 688 * Do not fail if the access is denied when no 689 * tunnel encap UDP ports are configured. 690 */ 691 if (rc != EACCES || etc.etc_udp_entries_num != 0) 692 goto fail2; 693 } 694 695 /* 696 * Although the caller should be able to handle MC reboot, 697 * it might come in handy to report the impending reboot 698 * by returning EAGAIN 699 */ 700 return ((resetting) ? EAGAIN : 0); 701 } 702 fail2: 703 EFSYS_PROBE(fail2); 704 705 fail1: 706 EFSYS_PROBE1(fail1, efx_rc_t, rc); 707 708 return (rc); 709 } 710 711 static void 712 ef10_tunnel_fini( 713 __in efx_nic_t *enp) 714 { 715 boolean_t resetting; 716 717 if (ef10_udp_encap_supported(enp) != B_FALSE) { 718 /* 719 * The UNLOADING flag allows the MC to suppress the datapath 720 * reset if it was set on the last call to 721 * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions 722 */ 723 (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE, 724 &resetting); 725 } 726 } 727 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 728 729 #endif /* EFSYS_OPT_TUNNEL */ 730