1 /* SPDX-License-Identifier: BSD-3-Clause
3 * Copyright (c) 2007-2018 Solarflare Communications Inc.
13 #if EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON
14 static const efx_tunnel_ops_t __efx_tunnel_dummy_ops = {
15 NULL, /* eto_udp_encap_supported */
16 NULL, /* eto_reconfigure */
18 #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON */
21 static __checkReturn boolean_t
22 medford_udp_encap_supported(
25 static __checkReturn efx_rc_t
26 medford_tunnel_reconfigure(
29 static const efx_tunnel_ops_t __efx_tunnel_medford_ops = {
30 medford_udp_encap_supported, /* eto_udp_encap_supported */
31 medford_tunnel_reconfigure, /* eto_reconfigure */
33 #endif /* EFSYS_OPT_MEDFORD */
35 static __checkReturn efx_rc_t
36 efx_mcdi_set_tunnel_encap_udp_ports(
38 __in efx_tunnel_cfg_t *etcp,
39 __in boolean_t unloading,
40 __out boolean_t *resetting)
43 uint8_t payload[MAX(MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX,
44 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN)];
48 unsigned int entries_num;
53 entries_num = etcp->etc_udp_entries_num;
55 (void) memset(payload, 0, sizeof (payload));
56 req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS;
57 req.emr_in_buf = payload;
59 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num);
60 req.emr_out_buf = payload;
61 req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN;
63 EFX_POPULATE_WORD_1(flags,
64 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING,
65 (unloading == B_TRUE) ? 1 : 0);
66 MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS,
67 EFX_WORD_FIELD(flags, EFX_WORD_0));
69 MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES,
72 for (i = 0; i < entries_num; ++i) {
73 uint16_t mcdi_udp_protocol;
75 switch (etcp->etc_udp_entries[i].etue_protocol) {
76 case EFX_TUNNEL_PROTOCOL_VXLAN:
77 mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN;
79 case EFX_TUNNEL_PROTOCOL_GENEVE:
80 mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE;
88 * UDP port is MCDI native little-endian in the request
89 * and EFX_POPULATE_DWORD cares about conversion from
90 * host/CPU byte order to little-endian.
92 EFX_STATIC_ASSERT(sizeof (efx_dword_t) ==
93 TUNNEL_ENCAP_UDP_PORT_ENTRY_LEN);
95 MCDI_IN2(req, efx_dword_t,
96 SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES)[i],
97 TUNNEL_ENCAP_UDP_PORT_ENTRY_UDP_PORT,
98 etcp->etc_udp_entries[i].etue_port,
99 TUNNEL_ENCAP_UDP_PORT_ENTRY_PROTOCOL,
103 efx_mcdi_execute(enp, &req);
105 if (req.emr_rc != 0) {
110 if (req.emr_out_length_used !=
111 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) {
116 *resetting = MCDI_OUT_WORD_FIELD(req,
117 SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS,
118 SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING);
129 EFSYS_PROBE1(fail1, efx_rc_t, rc);
134 __checkReturn efx_rc_t
138 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
139 const efx_tunnel_ops_t *etop;
142 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
143 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
144 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TUNNEL));
146 EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES ==
147 MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM);
149 switch (enp->en_family) {
151 case EFX_FAMILY_SIENA:
152 etop = &__efx_tunnel_dummy_ops;
154 #endif /* EFSYS_OPT_SIENA */
156 #if EFSYS_OPT_HUNTINGTON
157 case EFX_FAMILY_HUNTINGTON:
158 etop = &__efx_tunnel_dummy_ops;
160 #endif /* EFSYS_OPT_HUNTINGTON */
162 #if EFSYS_OPT_MEDFORD
163 case EFX_FAMILY_MEDFORD:
164 etop = &__efx_tunnel_medford_ops;
166 #endif /* EFSYS_OPT_MEDFORD */
174 memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
175 etcp->etc_udp_entries_num = 0;
178 enp->en_mod_flags |= EFX_MOD_TUNNEL;
183 EFSYS_PROBE1(fail1, efx_rc_t, rc);
186 enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
197 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC);
198 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE);
199 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
201 if ((enp->en_etop->eto_udp_encap_supported != NULL) &&
202 enp->en_etop->eto_udp_encap_supported(enp)) {
204 * The UNLOADING flag allows the MC to suppress the datapath
205 * reset if it was set on the last call to
206 * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions
208 (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE,
213 enp->en_mod_flags &= ~EFX_MOD_TUNNEL;
216 static __checkReturn efx_rc_t
217 efx_tunnel_config_find_udp_tunnel_entry(
218 __in efx_tunnel_cfg_t *etcp,
220 __out unsigned int *entryp)
224 for (i = 0; i < etcp->etc_udp_entries_num; ++i) {
225 efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i];
227 if (p->etue_port == port) {
236 __checkReturn efx_rc_t
237 efx_tunnel_config_udp_add(
239 __in uint16_t port /* host/cpu-endian */,
240 __in efx_tunnel_protocol_t protocol)
242 const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
243 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
244 efsys_lock_state_t state;
248 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
250 if (protocol >= EFX_TUNNEL_NPROTOS) {
255 if ((encp->enc_tunnel_encapsulations_supported &
256 (1u << protocol)) == 0) {
261 EFSYS_LOCK(enp->en_eslp, state);
263 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
269 if (etcp->etc_udp_entries_num ==
270 encp->enc_tunnel_config_udp_entries_max) {
275 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port;
276 etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol =
279 etcp->etc_udp_entries_num++;
281 EFSYS_UNLOCK(enp->en_eslp, state);
290 EFSYS_UNLOCK(enp->en_eslp, state);
296 EFSYS_PROBE1(fail1, efx_rc_t, rc);
301 __checkReturn efx_rc_t
302 efx_tunnel_config_udp_remove(
304 __in uint16_t port /* host/cpu-endian */,
305 __in efx_tunnel_protocol_t protocol)
307 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
308 efsys_lock_state_t state;
312 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
314 EFSYS_LOCK(enp->en_eslp, state);
316 rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry);
320 if (etcp->etc_udp_entries[entry].etue_protocol != protocol) {
325 EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0);
326 etcp->etc_udp_entries_num--;
328 if (entry < etcp->etc_udp_entries_num) {
329 memmove(&etcp->etc_udp_entries[entry],
330 &etcp->etc_udp_entries[entry + 1],
331 (etcp->etc_udp_entries_num - entry) *
332 sizeof (etcp->etc_udp_entries[0]));
335 memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0,
336 sizeof (etcp->etc_udp_entries[0]));
338 EFSYS_UNLOCK(enp->en_eslp, state);
346 EFSYS_PROBE1(fail1, efx_rc_t, rc);
347 EFSYS_UNLOCK(enp->en_eslp, state);
353 efx_tunnel_config_clear(
356 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
357 efsys_lock_state_t state;
359 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
361 EFSYS_LOCK(enp->en_eslp, state);
363 etcp->etc_udp_entries_num = 0;
364 memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries));
366 EFSYS_UNLOCK(enp->en_eslp, state);
369 __checkReturn efx_rc_t
370 efx_tunnel_reconfigure(
373 const efx_tunnel_ops_t *etop = enp->en_etop;
376 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL);
378 if (etop->eto_reconfigure == NULL) {
383 if ((rc = enp->en_etop->eto_reconfigure(enp)) != 0)
392 EFSYS_PROBE1(fail1, efx_rc_t, rc);
397 #if EFSYS_OPT_MEDFORD
398 static __checkReturn boolean_t
399 medford_udp_encap_supported(
402 const efx_nic_cfg_t *encp = &enp->en_nic_cfg;
403 uint32_t udp_tunnels_mask = 0;
405 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN);
406 udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE);
408 return ((encp->enc_tunnel_encapsulations_supported &
409 udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE);
412 static __checkReturn efx_rc_t
413 medford_tunnel_reconfigure(
416 efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg;
419 efsys_lock_state_t state;
420 efx_tunnel_cfg_t etc;
422 EFSYS_LOCK(enp->en_eslp, state);
423 memcpy(&etc, etcp, sizeof (etc));
424 EFSYS_UNLOCK(enp->en_eslp, state);
426 if (medford_udp_encap_supported(enp) == B_FALSE) {
428 * It is OK to apply empty UDP tunnel ports when UDP
429 * tunnel encapsulations are not supported - just nothing
432 if (etc.etc_udp_entries_num == 0)
438 * All PCI functions can see a reset upon the
439 * MCDI request completion
441 rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE,
447 * Although the caller should be able to handle MC reboot,
448 * it might come in handy to report the impending reboot
449 * by returning EAGAIN
451 return ((resetting) ? EAGAIN : 0);
457 EFSYS_PROBE1(fail1, efx_rc_t, rc);
461 #endif /* EFSYS_OPT_MEDFORD */
463 #endif /* EFSYS_OPT_TUNNEL */