1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright(c) 2019-2020 Xilinx, Inc.
4 * Copyright(c) 2007-2019 Solarflare Communications Inc.
11 * State diagram of the UDP tunnel table entries
12 * (efx_tunnel_udp_entry_state_t and busy flag):
15 * +--------| APPLIED |<-------+
18 * | efx_tunnel_reconfigure (end)
19 * efx_tunnel_config_udp_remove |
22 * +---------+ +------------+
25 * | efx_tunnel_reconfigure (begin)
26 * efx_tunnel_reconfigure (begin) |
29 * +--------------+ | ADDED |<---------+
30 * | BUSY REMOVED | +-----------+ |
31 * +--------------+ | |
32 * | efx_tunnel_config_udp_remove |
33 * efx_tunnel_reconfigure (end) | |
37 * +------->|| empty ||<-------+ |
39 * +---------+ efx_tunnel_config_udp_add
41 * +------------------------------+
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.
50 #if EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_RIVERHEAD
51 static const efx_tunnel_ops_t __efx_tunnel_dummy_ops = {
52 NULL, /* eto_reconfigure */
55 #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_RIVERHEAD */
57 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
58 static __checkReturn boolean_t
59 ef10_udp_encap_supported(
62 static __checkReturn efx_rc_t
63 ef10_tunnel_reconfigure(
70 static const efx_tunnel_ops_t __efx_tunnel_ef10_ops = {
71 ef10_tunnel_reconfigure, /* eto_reconfigure */
72 ef10_tunnel_fini, /* eto_fini */
74 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
76 /* Indicates that an entry is to be set */
77 static __checkReturn boolean_t
79 __in efx_tunnel_udp_entry_t *entry)
81 switch (entry->etue_state) {
82 case EFX_TUNNEL_UDP_ENTRY_ADDED:
83 return (entry->etue_busy);
84 case EFX_TUNNEL_UDP_ENTRY_REMOVED:
85 return (!entry->etue_busy);
86 case EFX_TUNNEL_UDP_ENTRY_APPLIED:
94 static __checkReturn efx_rc_t
95 efx_mcdi_set_tunnel_encap_udp_ports(
97 __in efx_tunnel_cfg_t *etcp,
98 __in boolean_t unloading,
99 __out boolean_t *resetting)
102 EFX_MCDI_DECLARE_BUF(payload,
103 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX,
104 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN);
108 unsigned int entries_num;
113 for (i = 0; i < etcp->etc_udp_entries_num; i++) {
114 if (ef10_entry_staged(&etcp->etc_udp_entries[i]) !=
121 req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS;
122 req.emr_in_buf = payload;
124 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num);
125 req.emr_out_buf = payload;
126 req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN;
128 EFX_POPULATE_WORD_1(flags,
129 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING,
130 (unloading == B_TRUE) ? 1 : 0);
131 MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS,
132 EFX_WORD_FIELD(flags, EFX_WORD_0));
134 MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES,
137 for (i = 0, entry = 0; entry < entries_num; ++entry, ++i) {
138 uint16_t mcdi_udp_protocol;
140 while (ef10_entry_staged(&etcp->etc_udp_entries[i]) == B_FALSE)
143 switch (etcp->etc_udp_entries[i].etue_protocol) {
144 case EFX_TUNNEL_PROTOCOL_VXLAN:
145 mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN;
147 case EFX_TUNNEL_PROTOCOL_GENEVE:
148 mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE;
156 * UDP port is MCDI native little-endian in the request
157 * and EFX_POPULATE_DWORD cares about conversion from
158 * host/CPU byte order to little-endian.
160 EFX_STATIC_ASSERT(sizeof (efx_dword_t) ==
161 TUNNEL_ENCAP_UDP_PORT_ENTRY_LEN);
162 EFX_POPULATE_DWORD_2(
163 MCDI_IN2(req, efx_dword_t,
164 SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES)[entry],
165 TUNNEL_ENCAP_UDP_PORT_ENTRY_UDP_PORT,
166 etcp->etc_udp_entries[i].etue_port,
167 TUNNEL_ENCAP_UDP_PORT_ENTRY_PROTOCOL,
171 efx_mcdi_execute(enp, &req);
173 if (req.emr_rc != 0) {
178 if (req.emr_out_length_used !=
179 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) {
184 *resetting = MCDI_OUT_WORD_FIELD(req,
185 SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS,
186 SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING);
197 EFSYS_PROBE1(fail1, efx_rc_t, rc);
202 __checkReturn efx_rc_t
206 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
207 const efx_tunnel_ops_t *etop;
210 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
211 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
212 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TUNNEL));
214 EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES ==
215 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM);
217 switch (enp->en_family) {
219 case EFX_FAMILY_SIENA:
220 etop = &__efx_tunnel_dummy_ops;
222 #endif /* EFSYS_OPT_SIENA */
224 #if EFSYS_OPT_HUNTINGTON
225 case EFX_FAMILY_HUNTINGTON:
226 etop = &__efx_tunnel_dummy_ops;
228 #endif /* EFSYS_OPT_HUNTINGTON */
230 #if EFSYS_OPT_MEDFORD
231 case EFX_FAMILY_MEDFORD:
232 etop = &__efx_tunnel_ef10_ops;
234 #endif /* EFSYS_OPT_MEDFORD */
236 #if EFSYS_OPT_MEDFORD2
237 case EFX_FAMILY_MEDFORD2:
238 etop = &__efx_tunnel_ef10_ops;
240 #endif /* EFSYS_OPT_MEDFORD2 */
242 #if EFSYS_OPT_RIVERHEAD
243 case EFX_FAMILY_RIVERHEAD:
244 etop = &__efx_tunnel_dummy_ops;
246 #endif /* EFSYS_OPT_RIVERHEAD */
254 memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
255 etcp->etc_udp_entries_num = 0;
258 enp->en_mod_flags |= EFX_MOD_TUNNEL;
263 EFSYS_PROBE1(fail1, efx_rc_t, rc);
266 enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
275 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
276 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
277 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
279 if (enp->en_etop->eto_fini != NULL)
280 enp->en_etop->eto_fini(enp);
283 enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
286 static __checkReturn efx_rc_t
287 efx_tunnel_config_find_udp_tunnel_entry(
288 __in efx_tunnel_cfg_t *etcp,
290 __out unsigned int *entryp)
294 for (i = 0; i < etcp->etc_udp_entries_num; ++i) {
295 efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i];
297 if (p->etue_port == port &&
298 p->etue_state != EFX_TUNNEL_UDP_ENTRY_REMOVED) {
307 __checkReturn efx_rc_t
308 efx_tunnel_config_udp_add(
310 __in uint16_t port /* host/cpu-endian */,
311 __in efx_tunnel_protocol_t protocol)
313 const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
314 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
315 efsys_lock_state_t state;
319 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
321 if (protocol >= EFX_TUNNEL_NPROTOS) {
326 if ((encp->enc_tunnel_encapsulations_supported &
327 (1u << protocol)) == 0) {
332 EFSYS_LOCK(enp->en_eslp, state);
334 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
340 if (etcp->etc_udp_entries_num ==
341 encp->enc_tunnel_config_udp_entries_max) {
346 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port;
347 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol =
349 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_state =
350 EFX_TUNNEL_UDP_ENTRY_ADDED;
352 etcp->etc_udp_entries_num++;
354 EFSYS_UNLOCK(enp->en_eslp, state);
363 EFSYS_UNLOCK(enp->en_eslp, state);
369 EFSYS_PROBE1(fail1, efx_rc_t, rc);
375 * Returns the index of the entry after the deleted one,
376 * or one past the last entry.
379 efx_tunnel_config_udp_do_remove(
380 __in efx_tunnel_cfg_t *etcp,
381 __in unsigned int entry)
383 EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0);
384 etcp->etc_udp_entries_num--;
386 if (entry < etcp->etc_udp_entries_num) {
387 memmove(&etcp->etc_udp_entries[entry],
388 &etcp->etc_udp_entries[entry + 1],
389 (etcp->etc_udp_entries_num - entry) *
390 sizeof (etcp->etc_udp_entries[0]));
393 memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0,
394 sizeof (etcp->etc_udp_entries[0]));
400 * Returns the index of the entry after the specified one,
401 * or one past the last entry. The index is correct whether
402 * the specified entry was removed or not.
405 efx_tunnel_config_udp_remove_prepare(
406 __in efx_tunnel_cfg_t *etcp,
407 __in unsigned int entry)
409 unsigned int next = entry + 1;
411 switch (etcp->etc_udp_entries[entry].etue_state) {
412 case EFX_TUNNEL_UDP_ENTRY_ADDED:
413 next = efx_tunnel_config_udp_do_remove(etcp, entry);
415 case EFX_TUNNEL_UDP_ENTRY_REMOVED:
417 case EFX_TUNNEL_UDP_ENTRY_APPLIED:
418 etcp->etc_udp_entries[entry].etue_state =
419 EFX_TUNNEL_UDP_ENTRY_REMOVED;
429 __checkReturn efx_rc_t
430 efx_tunnel_config_udp_remove(
432 __in uint16_t port /* host/cpu-endian */,
433 __in efx_tunnel_protocol_t protocol)
435 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
436 efsys_lock_state_t state;
440 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
442 EFSYS_LOCK(enp->en_eslp, state);
444 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
448 if (etcp->etc_udp_entries[entry].etue_busy != B_FALSE) {
453 if (etcp->etc_udp_entries[entry].etue_protocol != protocol) {
458 (void) efx_tunnel_config_udp_remove_prepare(etcp, entry);
460 EFSYS_UNLOCK(enp->en_eslp, state);
471 EFSYS_PROBE1(fail1, efx_rc_t, rc);
472 EFSYS_UNLOCK(enp->en_eslp, state);
478 efx_tunnel_table_all_available(
479 __in efx_tunnel_cfg_t *etcp)
483 for (i = 0; i < etcp->etc_udp_entries_num; i++) {
484 if (etcp->etc_udp_entries[i].etue_busy != B_FALSE)
491 __checkReturn efx_rc_t
492 efx_tunnel_config_clear(
495 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
496 efsys_lock_state_t state;
500 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
502 EFSYS_LOCK(enp->en_eslp, state);
504 if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
510 while (i < etcp->etc_udp_entries_num)
511 i = efx_tunnel_config_udp_remove_prepare(etcp, i);
513 EFSYS_UNLOCK(enp->en_eslp, state);
518 EFSYS_PROBE1(fail1, efx_rc_t, rc);
519 EFSYS_UNLOCK(enp->en_eslp, state);
524 __checkReturn efx_rc_t
525 efx_tunnel_reconfigure(
528 const efx_tunnel_ops_t *etop = enp->en_etop;
529 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
530 efx_tunnel_udp_entry_t *entry;
531 boolean_t locked = B_FALSE;
532 efsys_lock_state_t state;
537 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
539 if (etop->eto_reconfigure == NULL) {
544 EFSYS_LOCK(enp->en_eslp, state);
547 if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
552 for (i = 0; i < etcp->etc_udp_entries_num; i++) {
553 entry = &etcp->etc_udp_entries[i];
554 if (entry->etue_state != EFX_TUNNEL_UDP_ENTRY_APPLIED)
555 entry->etue_busy = B_TRUE;
558 EFSYS_UNLOCK(enp->en_eslp, state);
561 rc = enp->en_etop->eto_reconfigure(enp);
562 if (rc != 0 && rc != EAGAIN)
565 resetting = (rc == EAGAIN) ? B_TRUE : B_FALSE;
567 EFSYS_LOCK(enp->en_eslp, state);
571 * Delete entries marked for removal since they are no longer
572 * needed after successful NIC-specific reconfiguration.
573 * Added entries become applied because they are installed in
578 while (i < etcp->etc_udp_entries_num) {
579 unsigned int next = i + 1;
581 entry = &etcp->etc_udp_entries[i];
582 if (entry->etue_busy != B_FALSE) {
583 entry->etue_busy = B_FALSE;
585 switch (entry->etue_state) {
586 case EFX_TUNNEL_UDP_ENTRY_APPLIED:
588 case EFX_TUNNEL_UDP_ENTRY_ADDED:
590 EFX_TUNNEL_UDP_ENTRY_APPLIED;
592 case EFX_TUNNEL_UDP_ENTRY_REMOVED:
593 next = efx_tunnel_config_udp_do_remove(etcp, i);
604 EFSYS_UNLOCK(enp->en_eslp, state);
607 return ((resetting == B_FALSE) ? 0 : EAGAIN);
612 EFSYS_ASSERT(locked == B_FALSE);
613 EFSYS_LOCK(enp->en_eslp, state);
615 for (i = 0; i < etcp->etc_udp_entries_num; i++)
616 etcp->etc_udp_entries[i].etue_busy = B_FALSE;
618 EFSYS_UNLOCK(enp->en_eslp, state);
624 EFSYS_PROBE1(fail1, efx_rc_t, rc);
626 EFSYS_UNLOCK(enp->en_eslp, state);
631 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
632 static __checkReturn boolean_t
633 ef10_udp_encap_supported(
636 const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
637 uint32_t udp_tunnels_mask = 0;
639 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN);
640 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE);
642 return ((encp->enc_tunnel_encapsulations_supported &
643 udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE);
646 static __checkReturn efx_rc_t
647 ef10_tunnel_reconfigure(
650 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
652 boolean_t resetting = B_FALSE;
653 efsys_lock_state_t state;
654 efx_tunnel_cfg_t etc;
656 EFSYS_LOCK(enp->en_eslp, state);
657 memcpy(&etc, etcp, sizeof (etc));
658 EFSYS_UNLOCK(enp->en_eslp, state);
660 if (ef10_udp_encap_supported(enp) == B_FALSE) {
662 * It is OK to apply empty UDP tunnel ports when UDP
663 * tunnel encapsulations are not supported - just nothing
666 if (etc.etc_udp_entries_num == 0)
672 * All PCI functions can see a reset upon the
673 * MCDI request completion
675 rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE,
679 * Do not fail if the access is denied when no
680 * tunnel encap UDP ports are configured.
682 if (rc != EACCES || etc.etc_udp_entries_num != 0)
687 * Although the caller should be able to handle MC reboot,
688 * it might come in handy to report the impending reboot
689 * by returning EAGAIN
691 return ((resetting) ? EAGAIN : 0);
697 EFSYS_PROBE1(fail1, efx_rc_t, rc);
708 if (ef10_udp_encap_supported(enp) != B_FALSE) {
710 * The UNLOADING flag allows the MC to suppress the datapath
711 * reset if it was set on the last call to
712 * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions
714 (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE,
718 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
720 #endif /* EFSYS_OPT_TUNNEL */