net/mlx5: remove redundant flag in device config
[dpdk.git] / drivers / common / sfc_efx / base / efx_tunnel.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2019-2021 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 */