common/sfc_efx/base: introduce states for UDP tunnel entries
[dpdk.git] / drivers / common / sfc_efx / base / efx_tunnel.c
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_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_RIVERHEAD
51 static const efx_tunnel_ops_t   __efx_tunnel_dummy_ops = {
52         NULL,   /* eto_reconfigure */
53         NULL,   /* eto_fini */
54 };
55 #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON || EFSYS_OPT_RIVERHEAD */
56
57 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
58 static  __checkReturn   boolean_t
59 ef10_udp_encap_supported(
60         __in            efx_nic_t *enp);
61
62 static  __checkReturn   efx_rc_t
63 ef10_tunnel_reconfigure(
64         __in            efx_nic_t *enp);
65
66 static                  void
67 ef10_tunnel_fini(
68         __in            efx_nic_t *enp);
69
70 static const efx_tunnel_ops_t   __efx_tunnel_ef10_ops = {
71         ef10_tunnel_reconfigure,        /* eto_reconfigure */
72         ef10_tunnel_fini,               /* eto_fini */
73 };
74 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
75
76 /* Indicates that an entry is to be set */
77 static  __checkReturn           boolean_t
78 ef10_entry_staged(
79         __in                    efx_tunnel_udp_entry_t *entry)
80 {
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:
87                 return (B_TRUE);
88         default:
89                 EFSYS_ASSERT(0);
90                 return (B_FALSE);
91         }
92 }
93
94 static  __checkReturn           efx_rc_t
95 efx_mcdi_set_tunnel_encap_udp_ports(
96         __in                    efx_nic_t *enp,
97         __in                    efx_tunnel_cfg_t *etcp,
98         __in                    boolean_t unloading,
99         __out                   boolean_t *resetting)
100 {
101         efx_mcdi_req_t req;
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);
105         efx_word_t flags;
106         efx_rc_t rc;
107         unsigned int i;
108         unsigned int entries_num;
109         unsigned int entry;
110
111         entries_num = 0;
112         if (etcp != NULL) {
113                 for (i = 0; i < etcp->etc_udp_entries_num; i++) {
114                         if (ef10_entry_staged(&etcp->etc_udp_entries[i]) !=
115                             B_FALSE) {
116                                 entries_num++;
117                         }
118                 }
119         }
120
121         req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS;
122         req.emr_in_buf = payload;
123         req.emr_in_length =
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;
127
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));
133
134         MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES,
135             entries_num);
136
137         for (i = 0, entry = 0; entry < entries_num; ++entry, ++i) {
138                 uint16_t mcdi_udp_protocol;
139
140                 while (ef10_entry_staged(&etcp->etc_udp_entries[i]) == B_FALSE)
141                         i++;
142
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;
146                         break;
147                 case EFX_TUNNEL_PROTOCOL_GENEVE:
148                         mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE;
149                         break;
150                 default:
151                         rc = EINVAL;
152                         goto fail1;
153                 }
154
155                 /*
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.
159                  */
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,
168                     mcdi_udp_protocol);
169         }
170
171         efx_mcdi_execute(enp, &req);
172
173         if (req.emr_rc != 0) {
174                 rc = req.emr_rc;
175                 goto fail2;
176         }
177
178         if (req.emr_out_length_used !=
179             MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) {
180                 rc = EMSGSIZE;
181                 goto fail3;
182         }
183
184         *resetting = MCDI_OUT_WORD_FIELD(req,
185             SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS,
186             SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING);
187
188         return (0);
189
190 fail3:
191         EFSYS_PROBE(fail3);
192
193 fail2:
194         EFSYS_PROBE(fail2);
195
196 fail1:
197         EFSYS_PROBE1(fail1, efx_rc_t, rc);
198
199         return (rc);
200 }
201
202         __checkReturn   efx_rc_t
203 efx_tunnel_init(
204         __in            efx_nic_t *enp)
205 {
206         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
207         const efx_tunnel_ops_t *etop;
208         efx_rc_t rc;
209
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));
213
214         EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES ==
215             MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM);
216
217         switch (enp->en_family) {
218 #if EFSYS_OPT_SIENA
219         case EFX_FAMILY_SIENA:
220                 etop = &__efx_tunnel_dummy_ops;
221                 break;
222 #endif /* EFSYS_OPT_SIENA */
223
224 #if EFSYS_OPT_HUNTINGTON
225         case EFX_FAMILY_HUNTINGTON:
226                 etop = &__efx_tunnel_dummy_ops;
227                 break;
228 #endif /* EFSYS_OPT_HUNTINGTON */
229
230 #if EFSYS_OPT_MEDFORD
231         case EFX_FAMILY_MEDFORD:
232                 etop = &__efx_tunnel_ef10_ops;
233                 break;
234 #endif /* EFSYS_OPT_MEDFORD */
235
236 #if EFSYS_OPT_MEDFORD2
237         case EFX_FAMILY_MEDFORD2:
238                 etop = &__efx_tunnel_ef10_ops;
239                 break;
240 #endif /* EFSYS_OPT_MEDFORD2 */
241
242 #if EFSYS_OPT_RIVERHEAD
243         case EFX_FAMILY_RIVERHEAD:
244                 etop = &__efx_tunnel_dummy_ops;
245                 break;
246 #endif /* EFSYS_OPT_RIVERHEAD */
247
248         default:
249                 EFSYS_ASSERT(0);
250                 rc = ENOTSUP;
251                 goto fail1;
252         }
253
254         memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
255         etcp->etc_udp_entries_num = 0;
256
257         enp->en_etop = etop;
258         enp->en_mod_flags |= EFX_MOD_TUNNEL;
259
260         return (0);
261
262 fail1:
263         EFSYS_PROBE1(fail1, efx_rc_t, rc);
264
265         enp->en_etop = NULL;
266         enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
267
268         return (rc);
269 }
270
271                         void
272 efx_tunnel_fini(
273         __in            efx_nic_t *enp)
274 {
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);
278
279         if (enp->en_etop->eto_fini != NULL)
280                 enp->en_etop->eto_fini(enp);
281
282         enp->en_etop = NULL;
283         enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
284 }
285
286 static  __checkReturn   efx_rc_t
287 efx_tunnel_config_find_udp_tunnel_entry(
288         __in            efx_tunnel_cfg_t *etcp,
289         __in            uint16_t port,
290         __out           unsigned int *entryp)
291 {
292         unsigned int i;
293
294         for (i = 0; i < etcp->etc_udp_entries_num; ++i) {
295                 efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i];
296
297                 if (p->etue_port == port &&
298                     p->etue_state != EFX_TUNNEL_UDP_ENTRY_REMOVED) {
299                         *entryp = i;
300                         return (0);
301                 }
302         }
303
304         return (ENOENT);
305 }
306
307         __checkReturn   efx_rc_t
308 efx_tunnel_config_udp_add(
309         __in            efx_nic_t *enp,
310         __in            uint16_t port /* host/cpu-endian */,
311         __in            efx_tunnel_protocol_t protocol)
312 {
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;
316         efx_rc_t rc;
317         unsigned int entry;
318
319         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
320
321         if (protocol >= EFX_TUNNEL_NPROTOS) {
322                 rc = EINVAL;
323                 goto fail1;
324         }
325
326         if ((encp->enc_tunnel_encapsulations_supported &
327             (1u << protocol)) == 0) {
328                 rc = ENOTSUP;
329                 goto fail2;
330         }
331
332         EFSYS_LOCK(enp->en_eslp, state);
333
334         rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
335         if (rc == 0) {
336                 rc = EEXIST;
337                 goto fail3;
338         }
339
340         if (etcp->etc_udp_entries_num ==
341             encp->enc_tunnel_config_udp_entries_max) {
342                 rc = ENOSPC;
343                 goto fail4;
344         }
345
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 =
348             protocol;
349         etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_state =
350             EFX_TUNNEL_UDP_ENTRY_ADDED;
351
352         etcp->etc_udp_entries_num++;
353
354         EFSYS_UNLOCK(enp->en_eslp, state);
355
356         return (0);
357
358 fail4:
359         EFSYS_PROBE(fail4);
360
361 fail3:
362         EFSYS_PROBE(fail3);
363         EFSYS_UNLOCK(enp->en_eslp, state);
364
365 fail2:
366         EFSYS_PROBE(fail2);
367
368 fail1:
369         EFSYS_PROBE1(fail1, efx_rc_t, rc);
370
371         return (rc);
372 }
373
374 /*
375  * Returns the index of the entry after the deleted one,
376  * or one past the last entry.
377  */
378 static                  unsigned int
379 efx_tunnel_config_udp_do_remove(
380         __in            efx_tunnel_cfg_t *etcp,
381         __in            unsigned int entry)
382 {
383         EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0);
384         etcp->etc_udp_entries_num--;
385
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]));
391         }
392
393         memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0,
394             sizeof (etcp->etc_udp_entries[0]));
395
396         return (entry);
397 }
398
399 /*
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.
403  */
404 static                  unsigned int
405 efx_tunnel_config_udp_remove_prepare(
406         __in            efx_tunnel_cfg_t *etcp,
407         __in            unsigned int entry)
408 {
409         unsigned int next = entry + 1;
410
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);
414                 break;
415         case EFX_TUNNEL_UDP_ENTRY_REMOVED:
416                 break;
417         case EFX_TUNNEL_UDP_ENTRY_APPLIED:
418                 etcp->etc_udp_entries[entry].etue_state =
419                     EFX_TUNNEL_UDP_ENTRY_REMOVED;
420                 break;
421         default:
422                 EFSYS_ASSERT(0);
423                 break;
424         }
425
426         return (next);
427 }
428
429         __checkReturn   efx_rc_t
430 efx_tunnel_config_udp_remove(
431         __in            efx_nic_t *enp,
432         __in            uint16_t port /* host/cpu-endian */,
433         __in            efx_tunnel_protocol_t protocol)
434 {
435         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
436         efsys_lock_state_t state;
437         unsigned int entry;
438         efx_rc_t rc;
439
440         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
441
442         EFSYS_LOCK(enp->en_eslp, state);
443
444         rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
445         if (rc != 0)
446                 goto fail1;
447
448         if (etcp->etc_udp_entries[entry].etue_busy != B_FALSE) {
449                 rc = EBUSY;
450                 goto fail2;
451         }
452
453         if (etcp->etc_udp_entries[entry].etue_protocol != protocol) {
454                 rc = EINVAL;
455                 goto fail3;
456         }
457
458         (void) efx_tunnel_config_udp_remove_prepare(etcp, entry);
459
460         EFSYS_UNLOCK(enp->en_eslp, state);
461
462         return (0);
463
464 fail3:
465         EFSYS_PROBE(fail3);
466
467 fail2:
468         EFSYS_PROBE(fail2);
469
470 fail1:
471         EFSYS_PROBE1(fail1, efx_rc_t, rc);
472         EFSYS_UNLOCK(enp->en_eslp, state);
473
474         return (rc);
475 }
476
477 static                  boolean_t
478 efx_tunnel_table_all_available(
479         __in                    efx_tunnel_cfg_t *etcp)
480 {
481         unsigned int i;
482
483         for (i = 0; i < etcp->etc_udp_entries_num; i++) {
484                 if (etcp->etc_udp_entries[i].etue_busy != B_FALSE)
485                         return (B_FALSE);
486         }
487
488         return (B_TRUE);
489 }
490
491         __checkReturn   efx_rc_t
492 efx_tunnel_config_clear(
493         __in                    efx_nic_t *enp)
494 {
495         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
496         efsys_lock_state_t state;
497         unsigned int i;
498         efx_rc_t rc;
499
500         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
501
502         EFSYS_LOCK(enp->en_eslp, state);
503
504         if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
505                 rc = EBUSY;
506                 goto fail1;
507         }
508
509         i = 0;
510         while (i < etcp->etc_udp_entries_num)
511                 i = efx_tunnel_config_udp_remove_prepare(etcp, i);
512
513         EFSYS_UNLOCK(enp->en_eslp, state);
514
515         return (0);
516
517 fail1:
518         EFSYS_PROBE1(fail1, efx_rc_t, rc);
519         EFSYS_UNLOCK(enp->en_eslp, state);
520
521         return (rc);
522 }
523
524         __checkReturn   efx_rc_t
525 efx_tunnel_reconfigure(
526         __in            efx_nic_t *enp)
527 {
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;
533         boolean_t resetting;
534         unsigned int i;
535         efx_rc_t rc;
536
537         EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
538
539         if (etop->eto_reconfigure == NULL) {
540                 rc = ENOTSUP;
541                 goto fail1;
542         }
543
544         EFSYS_LOCK(enp->en_eslp, state);
545         locked = B_TRUE;
546
547         if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
548                 rc = EBUSY;
549                 goto fail2;
550         }
551
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;
556         }
557
558         EFSYS_UNLOCK(enp->en_eslp, state);
559         locked = B_FALSE;
560
561         rc = enp->en_etop->eto_reconfigure(enp);
562         if (rc != 0 && rc != EAGAIN)
563                 goto fail3;
564
565         resetting = (rc == EAGAIN) ? B_TRUE : B_FALSE;
566
567         EFSYS_LOCK(enp->en_eslp, state);
568         locked = B_TRUE;
569
570         /*
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
574          * the hardware.
575          */
576
577         i = 0;
578         while (i < etcp->etc_udp_entries_num) {
579                 unsigned int next = i + 1;
580
581                 entry = &etcp->etc_udp_entries[i];
582                 if (entry->etue_busy != B_FALSE) {
583                         entry->etue_busy = B_FALSE;
584
585                         switch (entry->etue_state) {
586                         case EFX_TUNNEL_UDP_ENTRY_APPLIED:
587                                 break;
588                         case EFX_TUNNEL_UDP_ENTRY_ADDED:
589                                 entry->etue_state =
590                                     EFX_TUNNEL_UDP_ENTRY_APPLIED;
591                                 break;
592                         case EFX_TUNNEL_UDP_ENTRY_REMOVED:
593                                 next = efx_tunnel_config_udp_do_remove(etcp, i);
594                                 break;
595                         default:
596                                 EFSYS_ASSERT(0);
597                                 break;
598                         }
599                 }
600
601                 i = next;
602         }
603
604         EFSYS_UNLOCK(enp->en_eslp, state);
605         locked = B_FALSE;
606
607         return ((resetting == B_FALSE) ? 0 : EAGAIN);
608
609 fail3:
610         EFSYS_PROBE(fail3);
611
612         EFSYS_ASSERT(locked == B_FALSE);
613         EFSYS_LOCK(enp->en_eslp, state);
614
615         for (i = 0; i < etcp->etc_udp_entries_num; i++)
616                 etcp->etc_udp_entries[i].etue_busy = B_FALSE;
617
618         EFSYS_UNLOCK(enp->en_eslp, state);
619
620 fail2:
621         EFSYS_PROBE(fail2);
622
623 fail1:
624         EFSYS_PROBE1(fail1, efx_rc_t, rc);
625         if (locked)
626                 EFSYS_UNLOCK(enp->en_eslp, state);
627
628         return (rc);
629 }
630
631 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2
632 static  __checkReturn           boolean_t
633 ef10_udp_encap_supported(
634         __in            efx_nic_t *enp)
635 {
636         const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
637         uint32_t udp_tunnels_mask = 0;
638
639         udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN);
640         udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE);
641
642         return ((encp->enc_tunnel_encapsulations_supported &
643             udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE);
644 }
645
646 static  __checkReturn   efx_rc_t
647 ef10_tunnel_reconfigure(
648         __in            efx_nic_t *enp)
649 {
650         efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
651         efx_rc_t rc;
652         boolean_t resetting = B_FALSE;
653         efsys_lock_state_t state;
654         efx_tunnel_cfg_t etc;
655
656         EFSYS_LOCK(enp->en_eslp, state);
657         memcpy(&etc, etcp, sizeof (etc));
658         EFSYS_UNLOCK(enp->en_eslp, state);
659
660         if (ef10_udp_encap_supported(enp) == B_FALSE) {
661                 /*
662                  * It is OK to apply empty UDP tunnel ports when UDP
663                  * tunnel encapsulations are not supported - just nothing
664                  * should be done.
665                  */
666                 if (etc.etc_udp_entries_num == 0)
667                         return (0);
668                 rc = ENOTSUP;
669                 goto fail1;
670         } else {
671                 /*
672                  * All PCI functions can see a reset upon the
673                  * MCDI request completion
674                  */
675                 rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE,
676                     &resetting);
677                 if (rc != 0) {
678                         /*
679                          * Do not fail if the access is denied when no
680                          * tunnel encap UDP ports are configured.
681                          */
682                         if (rc != EACCES || etc.etc_udp_entries_num != 0)
683                                 goto fail2;
684                 }
685
686                 /*
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
690                  */
691                 return ((resetting) ? EAGAIN : 0);
692         }
693 fail2:
694         EFSYS_PROBE(fail2);
695
696 fail1:
697         EFSYS_PROBE1(fail1, efx_rc_t, rc);
698
699         return (rc);
700 }
701
702 static                  void
703 ef10_tunnel_fini(
704         __in            efx_nic_t *enp)
705 {
706         boolean_t resetting;
707
708         if (ef10_udp_encap_supported(enp) != B_FALSE) {
709                 /*
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
713                  */
714                 (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE,
715                     &resetting);
716         }
717 }
718 #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
719
720 #endif /* EFSYS_OPT_TUNNEL */