Branch data Line data Source code
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 : 0 : ef10_entry_staged(
88 : : __in efx_tunnel_udp_entry_t *entry)
89 : : {
90 [ # # # # ]: 0 : switch (entry->etue_state) {
91 : 0 : case EFX_TUNNEL_UDP_ENTRY_ADDED:
92 : 0 : return (entry->etue_busy);
93 : 0 : case EFX_TUNNEL_UDP_ENTRY_REMOVED:
94 : 0 : return (!entry->etue_busy);
95 : : case EFX_TUNNEL_UDP_ENTRY_APPLIED:
96 : : return (B_TRUE);
97 : : default:
98 : 0 : EFSYS_ASSERT(0);
99 : : return (B_FALSE);
100 : : }
101 : : }
102 : :
103 : : static __checkReturn efx_rc_t
104 : 0 : 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 : 0 : 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 [ # # ]: 0 : if (etcp != NULL) {
122 [ # # ]: 0 : for (i = 0; i < etcp->etc_udp_entries_num; i++) {
123 [ # # ]: 0 : if (ef10_entry_staged(&etcp->etc_udp_entries[i]) !=
124 : : B_FALSE) {
125 : 0 : entries_num++;
126 : : }
127 : : }
128 : : }
129 : :
130 : 0 : req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS;
131 : 0 : req.emr_in_buf = payload;
132 : 0 : req.emr_in_length =
133 : 0 : MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num);
134 : 0 : req.emr_out_buf = payload;
135 : 0 : req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN;
136 : :
137 : 0 : EFX_POPULATE_WORD_1(flags,
138 : : MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING,
139 : : (unloading == B_TRUE) ? 1 : 0);
140 : 0 : MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS,
141 : : EFX_WORD_FIELD(flags, EFX_WORD_0));
142 : :
143 : 0 : MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES,
144 : : entries_num);
145 : :
146 [ # # ]: 0 : for (i = 0, entry = 0; entry < entries_num; ++entry, ++i) {
147 : : uint16_t mcdi_udp_protocol;
148 : :
149 [ # # ]: 0 : while (ef10_entry_staged(&etcp->etc_udp_entries[i]) == B_FALSE)
150 : 0 : i++;
151 : :
152 [ # # # ]: 0 : 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 : 0 : case EFX_TUNNEL_PROTOCOL_GENEVE:
157 : : mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE;
158 : 0 : break;
159 : 0 : default:
160 : : rc = EINVAL;
161 : 0 : 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 : 0 : 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 : 0 : efx_mcdi_execute(enp, &req);
181 : :
182 [ # # ]: 0 : if (req.emr_rc != 0) {
183 : : rc = req.emr_rc;
184 : 0 : goto fail2;
185 : : }
186 : :
187 [ # # ]: 0 : if (req.emr_out_length_used !=
188 : : MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) {
189 : : rc = EMSGSIZE;
190 : 0 : goto fail3;
191 : : }
192 : :
193 : 0 : *resetting = MCDI_OUT_WORD_FIELD(req,
194 : : SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS,
195 : : SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING);
196 : :
197 : 0 : 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 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
220 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
221 [ # # ]: 0 : 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 [ # # # # : 0 : 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 : 0 : case EFX_FAMILY_MEDFORD:
241 : : etop = &__efx_tunnel_ef10_ops;
242 : 0 : break;
243 : : #endif /* EFSYS_OPT_MEDFORD */
244 : :
245 : : #if EFSYS_OPT_MEDFORD2
246 : 0 : case EFX_FAMILY_MEDFORD2:
247 : : etop = &__efx_tunnel_ef10_ops;
248 : 0 : break;
249 : : #endif /* EFSYS_OPT_MEDFORD2 */
250 : :
251 : : #if EFSYS_OPT_RIVERHEAD
252 : 0 : case EFX_FAMILY_RIVERHEAD:
253 : : etop = &__efx_tunnel_rhead_ops;
254 : 0 : break;
255 : : #endif /* EFSYS_OPT_RIVERHEAD */
256 : :
257 : : default:
258 : 0 : EFSYS_ASSERT(0);
259 : : rc = ENOTSUP;
260 : : goto fail1;
261 : : }
262 : :
263 : 0 : memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
264 : 0 : etcp->etc_udp_entries_num = 0;
265 : :
266 : 0 : enp->en_etop = etop;
267 : 0 : 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 : 0 : efx_tunnel_fini(
282 : : __in efx_nic_t *enp)
283 : : {
284 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
285 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
286 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
287 : :
288 [ # # ]: 0 : if (enp->en_etop->eto_fini != NULL)
289 : 0 : enp->en_etop->eto_fini(enp);
290 : :
291 : 0 : enp->en_etop = NULL;
292 : 0 : enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
293 : 0 : }
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 [ # # # # ]: 0 : for (i = 0; i < etcp->etc_udp_entries_num; ++i) {
304 : : efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i];
305 : :
306 [ # # # # ]: 0 : if (p->etue_port == port &&
307 [ # # # # ]: 0 : 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 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
329 : :
330 [ # # ]: 0 : if (protocol >= EFX_TUNNEL_NPROTOS) {
331 : : rc = EINVAL;
332 : 0 : goto fail1;
333 : : }
334 : :
335 : 0 : if ((encp->enc_tunnel_encapsulations_supported &
336 [ # # ]: 0 : (1u << protocol)) == 0) {
337 : : rc = ENOTSUP;
338 : 0 : goto fail2;
339 : : }
340 : :
341 : 0 : 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 : 0 : goto fail3;
347 : : }
348 : :
349 : 0 : if (etcp->etc_udp_entries_num ==
350 [ # # ]: 0 : encp->enc_tunnel_config_udp_entries_max) {
351 : : rc = ENOSPC;
352 : 0 : goto fail4;
353 : : }
354 : :
355 : 0 : etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port;
356 : 0 : etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol =
357 : : protocol;
358 : 0 : etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_state =
359 : : EFX_TUNNEL_UDP_ENTRY_ADDED;
360 : :
361 : 0 : etcp->etc_udp_entries_num++;
362 : :
363 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
364 : :
365 : 0 : return (0);
366 : :
367 : : fail4:
368 : : EFSYS_PROBE(fail4);
369 : :
370 : 0 : fail3:
371 : : EFSYS_PROBE(fail3);
372 : 0 : 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 : 0 : efx_tunnel_config_udp_do_remove(
389 : : __in efx_tunnel_cfg_t *etcp,
390 : : __in unsigned int entry)
391 : : {
392 [ # # ]: 0 : EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0);
393 : 0 : etcp->etc_udp_entries_num--;
394 : :
395 [ # # ]: 0 : if (entry < etcp->etc_udp_entries_num) {
396 : 0 : memmove(&etcp->etc_udp_entries[entry],
397 : 0 : &etcp->etc_udp_entries[entry + 1],
398 : 0 : (etcp->etc_udp_entries_num - entry) *
399 : : sizeof (etcp->etc_udp_entries[0]));
400 : : }
401 : :
402 : 0 : memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0,
403 : : sizeof (etcp->etc_udp_entries[0]));
404 : :
405 : 0 : 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 : 0 : efx_tunnel_config_udp_remove_prepare(
415 : : __in efx_tunnel_cfg_t *etcp,
416 : : __in unsigned int entry)
417 : : {
418 : 0 : unsigned int next = entry + 1;
419 : :
420 [ # # # # ]: 0 : switch (etcp->etc_udp_entries[entry].etue_state) {
421 : 0 : case EFX_TUNNEL_UDP_ENTRY_ADDED:
422 : 0 : next = efx_tunnel_config_udp_do_remove(etcp, entry);
423 : 0 : break;
424 : : case EFX_TUNNEL_UDP_ENTRY_REMOVED:
425 : : break;
426 : 0 : case EFX_TUNNEL_UDP_ENTRY_APPLIED:
427 : 0 : etcp->etc_udp_entries[entry].etue_state =
428 : : EFX_TUNNEL_UDP_ENTRY_REMOVED;
429 : 0 : break;
430 : : default:
431 : 0 : EFSYS_ASSERT(0);
432 : : break;
433 : : }
434 : :
435 : 0 : return (next);
436 : : }
437 : :
438 : : __checkReturn efx_rc_t
439 : 0 : 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 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
450 : :
451 : 0 : EFSYS_LOCK(enp->en_eslp, state);
452 : :
453 : : rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
454 : : if (rc != 0)
455 : 0 : goto fail1;
456 : :
457 [ # # ]: 0 : if (etcp->etc_udp_entries[entry].etue_busy != B_FALSE) {
458 : : rc = EBUSY;
459 : 0 : goto fail2;
460 : : }
461 : :
462 [ # # ]: 0 : if (etcp->etc_udp_entries[entry].etue_protocol != protocol) {
463 : : rc = EINVAL;
464 : 0 : goto fail3;
465 : : }
466 : :
467 : 0 : (void) efx_tunnel_config_udp_remove_prepare(etcp, entry);
468 : :
469 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
470 : :
471 : 0 : return (0);
472 : :
473 : : fail3:
474 : : EFSYS_PROBE(fail3);
475 : :
476 : 0 : fail2:
477 : : EFSYS_PROBE(fail2);
478 : :
479 : 0 : fail1:
480 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
481 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
482 : :
483 : 0 : 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 [ # # # # ]: 0 : for (i = 0; i < etcp->etc_udp_entries_num; i++) {
493 [ # # # # ]: 0 : 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 : 0 : efx_tunnel_config_clear(
502 : : __in efx_nic_t *enp)
503 : : {
504 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
510 : :
511 : 0 : EFSYS_LOCK(enp->en_eslp, state);
512 : :
513 [ # # ]: 0 : if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
514 : : rc = EBUSY;
515 : 0 : goto fail1;
516 : : }
517 : :
518 : : i = 0;
519 [ # # ]: 0 : while (i < etcp->etc_udp_entries_num)
520 : 0 : i = efx_tunnel_config_udp_remove_prepare(etcp, i);
521 : :
522 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
523 : :
524 : 0 : return (0);
525 : :
526 : : fail1:
527 : : EFSYS_PROBE1(fail1, efx_rc_t, rc);
528 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
529 : :
530 : 0 : return (rc);
531 : : }
532 : :
533 : : __checkReturn efx_rc_t
534 : 0 : efx_tunnel_reconfigure(
535 : : __in efx_nic_t *enp)
536 : : {
537 : 0 : const efx_tunnel_ops_t *etop = enp->en_etop;
538 : 0 : 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 [ # # ]: 0 : EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
547 : :
548 [ # # ]: 0 : if (etop->eto_reconfigure == NULL) {
549 : : rc = ENOTSUP;
550 : 0 : goto fail1;
551 : : }
552 : :
553 : 0 : EFSYS_LOCK(enp->en_eslp, state);
554 : : locked = B_TRUE;
555 : :
556 [ # # ]: 0 : if (efx_tunnel_table_all_available(etcp) == B_FALSE) {
557 : : rc = EBUSY;
558 : 0 : goto fail2;
559 : : }
560 : :
561 [ # # ]: 0 : for (i = 0; i < etcp->etc_udp_entries_num; i++) {
562 : : entry = &etcp->etc_udp_entries[i];
563 [ # # ]: 0 : if (entry->etue_state != EFX_TUNNEL_UDP_ENTRY_APPLIED)
564 : 0 : entry->etue_busy = B_TRUE;
565 : : }
566 : :
567 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
568 : : locked = B_FALSE;
569 : :
570 : 0 : rc = enp->en_etop->eto_reconfigure(enp);
571 [ # # ]: 0 : if (rc != 0 && rc != EAGAIN)
572 : 0 : goto fail3;
573 : :
574 : : resetting = (rc == EAGAIN) ? B_TRUE : B_FALSE;
575 : :
576 : 0 : 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 [ # # ]: 0 : while (i < etcp->etc_udp_entries_num) {
588 : 0 : unsigned int next = i + 1;
589 : :
590 : : entry = &etcp->etc_udp_entries[i];
591 [ # # ]: 0 : if (entry->etue_busy != B_FALSE) {
592 : 0 : entry->etue_busy = B_FALSE;
593 : :
594 [ # # # # ]: 0 : switch (entry->etue_state) {
595 : : case EFX_TUNNEL_UDP_ENTRY_APPLIED:
596 : : break;
597 : 0 : case EFX_TUNNEL_UDP_ENTRY_ADDED:
598 : 0 : entry->etue_state =
599 : : EFX_TUNNEL_UDP_ENTRY_APPLIED;
600 : 0 : break;
601 : 0 : case EFX_TUNNEL_UDP_ENTRY_REMOVED:
602 : 0 : next = efx_tunnel_config_udp_do_remove(etcp, i);
603 : 0 : break;
604 : : default:
605 : 0 : EFSYS_ASSERT(0);
606 : : break;
607 : : }
608 : : }
609 : :
610 : : i = next;
611 : : }
612 : :
613 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
614 : : locked = B_FALSE;
615 : :
616 [ # # ]: 0 : return ((resetting == B_FALSE) ? 0 : EAGAIN);
617 : :
618 : : fail3:
619 : : EFSYS_PROBE(fail3);
620 : :
621 : : EFSYS_ASSERT(locked == B_FALSE);
622 : 0 : EFSYS_LOCK(enp->en_eslp, state);
623 : :
624 [ # # ]: 0 : for (i = 0; i < etcp->etc_udp_entries_num; i++)
625 : 0 : etcp->etc_udp_entries[i].etue_busy = B_FALSE;
626 : :
627 : 0 : 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 : 0 : 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 : 0 : return ((encp->enc_tunnel_encapsulations_supported &
652 : : udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE);
653 : : }
654 : :
655 : : static __checkReturn efx_rc_t
656 : 0 : ef10_tunnel_reconfigure(
657 : : __in efx_nic_t *enp)
658 : : {
659 : 0 : efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
660 : : efx_rc_t rc;
661 : 0 : boolean_t resetting = B_FALSE;
662 : : efsys_lock_state_t state;
663 : : efx_tunnel_cfg_t etc;
664 : :
665 : 0 : EFSYS_LOCK(enp->en_eslp, state);
666 : : memcpy(&etc, etcp, sizeof (etc));
667 : 0 : EFSYS_UNLOCK(enp->en_eslp, state);
668 : :
669 [ # # ]: 0 : 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 [ # # ]: 0 : if (etc.etc_udp_entries_num == 0)
676 : : return (0);
677 : : rc = ENOTSUP;
678 : 0 : goto fail1;
679 : : } else {
680 : : /*
681 : : * All PCI functions can see a reset upon the
682 : : * MCDI request completion
683 : : */
684 : 0 : rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE,
685 : : &resetting);
686 [ # # ]: 0 : if (rc != 0) {
687 : : /*
688 : : * Do not fail if the access is denied when no
689 : : * tunnel encap UDP ports are configured.
690 : : */
691 [ # # # # ]: 0 : if (rc != EACCES || etc.etc_udp_entries_num != 0)
692 : 0 : 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 [ # # ]: 0 : 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 : 0 : ef10_tunnel_fini(
713 : : __in efx_nic_t *enp)
714 : : {
715 : : boolean_t resetting;
716 : :
717 [ # # ]: 0 : 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 : 0 : (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE,
724 : : &resetting);
725 : : }
726 : 0 : }
727 : : #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */
728 : :
729 : : #endif /* EFSYS_OPT_TUNNEL */
|