xref: /dpdk/drivers/common/sfc_efx/base/efx_tunnel.c (revision 672386c1e9e1f64f7aa3b1360ad22dc737ea8d72)
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
ef10_entry_staged(__in efx_tunnel_udp_entry_t * entry)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
efx_mcdi_set_tunnel_encap_udp_ports(__in efx_nic_t * enp,__in efx_tunnel_cfg_t * etcp,__in boolean_t unloading,__out boolean_t * resetting)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
efx_tunnel_init(__in efx_nic_t * enp)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
efx_tunnel_fini(__in efx_nic_t * enp)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
efx_tunnel_config_find_udp_tunnel_entry(__in efx_tunnel_cfg_t * etcp,__in uint16_t port,__out unsigned int * entryp)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
efx_tunnel_config_udp_add(__in efx_nic_t * enp,__in uint16_t port,__in efx_tunnel_protocol_t protocol)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
efx_tunnel_config_udp_do_remove(__in efx_tunnel_cfg_t * etcp,__in unsigned int entry)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
efx_tunnel_config_udp_remove_prepare(__in efx_tunnel_cfg_t * etcp,__in unsigned int entry)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
efx_tunnel_config_udp_remove(__in efx_nic_t * enp,__in uint16_t port,__in efx_tunnel_protocol_t protocol)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
efx_tunnel_table_all_available(__in efx_tunnel_cfg_t * etcp)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
efx_tunnel_config_clear(__in efx_nic_t * enp)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
efx_tunnel_reconfigure(__in efx_nic_t * enp)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
ef10_udp_encap_supported(__in efx_nic_t * enp)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
ef10_tunnel_reconfigure(__in efx_nic_t * enp)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
ef10_tunnel_fini(__in efx_nic_t * enp)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