1fdbe38cfSAndrew Rybchenko /*- 2fdbe38cfSAndrew Rybchenko * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3fdbe38cfSAndrew Rybchenko * 4fdbe38cfSAndrew Rybchenko * Copyright (c) 2017-2018 Solarflare Communications Inc. 5fdbe38cfSAndrew Rybchenko * All rights reserved. 6fdbe38cfSAndrew Rybchenko * 7fdbe38cfSAndrew Rybchenko * Redistribution and use in source and binary forms, with or without 8fdbe38cfSAndrew Rybchenko * modification, are permitted provided that the following conditions are met: 9fdbe38cfSAndrew Rybchenko * 10fdbe38cfSAndrew Rybchenko * 1. Redistributions of source code must retain the above copyright notice, 11fdbe38cfSAndrew Rybchenko * this list of conditions and the following disclaimer. 12fdbe38cfSAndrew Rybchenko * 2. Redistributions in binary form must reproduce the above copyright notice, 13fdbe38cfSAndrew Rybchenko * this list of conditions and the following disclaimer in the documentation 14fdbe38cfSAndrew Rybchenko * and/or other materials provided with the distribution. 15fdbe38cfSAndrew Rybchenko * 16fdbe38cfSAndrew Rybchenko * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17fdbe38cfSAndrew Rybchenko * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 18fdbe38cfSAndrew Rybchenko * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19fdbe38cfSAndrew Rybchenko * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 20fdbe38cfSAndrew Rybchenko * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 21fdbe38cfSAndrew Rybchenko * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 22fdbe38cfSAndrew Rybchenko * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 23fdbe38cfSAndrew Rybchenko * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 24fdbe38cfSAndrew Rybchenko * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 25fdbe38cfSAndrew Rybchenko * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 26fdbe38cfSAndrew Rybchenko * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27fdbe38cfSAndrew Rybchenko * 28fdbe38cfSAndrew Rybchenko * The views and conclusions contained in the software and documentation are 29fdbe38cfSAndrew Rybchenko * those of the authors and should not be interpreted as representing official 30fdbe38cfSAndrew Rybchenko * policies, either expressed or implied, of the FreeBSD Project. 31fdbe38cfSAndrew Rybchenko */ 32fdbe38cfSAndrew Rybchenko 33fdbe38cfSAndrew Rybchenko #include <sys/cdefs.h> 34fdbe38cfSAndrew Rybchenko __FBSDID("$FreeBSD$"); 35fdbe38cfSAndrew Rybchenko 36fdbe38cfSAndrew Rybchenko #include "efx.h" 37fdbe38cfSAndrew Rybchenko #include "efx_impl.h" 38fdbe38cfSAndrew Rybchenko 39fdbe38cfSAndrew Rybchenko 40fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_TUNNEL 41fdbe38cfSAndrew Rybchenko 42fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON 43fdbe38cfSAndrew Rybchenko static const efx_tunnel_ops_t __efx_tunnel_dummy_ops = { 44fdbe38cfSAndrew Rybchenko NULL, /* eto_udp_encap_supported */ 45fdbe38cfSAndrew Rybchenko NULL, /* eto_reconfigure */ 46fdbe38cfSAndrew Rybchenko }; 47fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON */ 48fdbe38cfSAndrew Rybchenko 49*edaff290SAndrew Rybchenko #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 50fdbe38cfSAndrew Rybchenko static __checkReturn boolean_t 51*edaff290SAndrew Rybchenko ef10_udp_encap_supported( 52fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp); 53fdbe38cfSAndrew Rybchenko 54fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 55*edaff290SAndrew Rybchenko ef10_tunnel_reconfigure( 56fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp); 57fdbe38cfSAndrew Rybchenko 58*edaff290SAndrew Rybchenko static const efx_tunnel_ops_t __efx_tunnel_ef10_ops = { 59*edaff290SAndrew Rybchenko ef10_udp_encap_supported, /* eto_udp_encap_supported */ 60*edaff290SAndrew Rybchenko ef10_tunnel_reconfigure, /* eto_reconfigure */ 61fdbe38cfSAndrew Rybchenko }; 62*edaff290SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 63fdbe38cfSAndrew Rybchenko 64fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 65fdbe38cfSAndrew Rybchenko efx_mcdi_set_tunnel_encap_udp_ports( 66fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp, 67fdbe38cfSAndrew Rybchenko __in efx_tunnel_cfg_t *etcp, 68fdbe38cfSAndrew Rybchenko __in boolean_t unloading, 69fdbe38cfSAndrew Rybchenko __out boolean_t *resetting) 70fdbe38cfSAndrew Rybchenko { 71fdbe38cfSAndrew Rybchenko efx_mcdi_req_t req; 72fdbe38cfSAndrew Rybchenko uint8_t payload[MAX(MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX, 73fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN)]; 74fdbe38cfSAndrew Rybchenko efx_word_t flags; 75fdbe38cfSAndrew Rybchenko efx_rc_t rc; 76fdbe38cfSAndrew Rybchenko unsigned int i; 77fdbe38cfSAndrew Rybchenko unsigned int entries_num; 78fdbe38cfSAndrew Rybchenko 79fdbe38cfSAndrew Rybchenko if (etcp == NULL) 80fdbe38cfSAndrew Rybchenko entries_num = 0; 81fdbe38cfSAndrew Rybchenko else 82fdbe38cfSAndrew Rybchenko entries_num = etcp->etc_udp_entries_num; 83fdbe38cfSAndrew Rybchenko 84fdbe38cfSAndrew Rybchenko (void) memset(payload, 0, sizeof (payload)); 85fdbe38cfSAndrew Rybchenko req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS; 86fdbe38cfSAndrew Rybchenko req.emr_in_buf = payload; 87fdbe38cfSAndrew Rybchenko req.emr_in_length = 88fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num); 89fdbe38cfSAndrew Rybchenko req.emr_out_buf = payload; 90fdbe38cfSAndrew Rybchenko req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN; 91fdbe38cfSAndrew Rybchenko 92fdbe38cfSAndrew Rybchenko EFX_POPULATE_WORD_1(flags, 93fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING, 94fdbe38cfSAndrew Rybchenko (unloading == B_TRUE) ? 1 : 0); 95fdbe38cfSAndrew Rybchenko MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS, 96fdbe38cfSAndrew Rybchenko EFX_WORD_FIELD(flags, EFX_WORD_0)); 97fdbe38cfSAndrew Rybchenko 98fdbe38cfSAndrew Rybchenko MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES, 99fdbe38cfSAndrew Rybchenko entries_num); 100fdbe38cfSAndrew Rybchenko 101fdbe38cfSAndrew Rybchenko for (i = 0; i < entries_num; ++i) { 102fdbe38cfSAndrew Rybchenko uint16_t mcdi_udp_protocol; 103fdbe38cfSAndrew Rybchenko 104fdbe38cfSAndrew Rybchenko switch (etcp->etc_udp_entries[i].etue_protocol) { 105fdbe38cfSAndrew Rybchenko case EFX_TUNNEL_PROTOCOL_VXLAN: 106fdbe38cfSAndrew Rybchenko mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN; 107fdbe38cfSAndrew Rybchenko break; 108fdbe38cfSAndrew Rybchenko case EFX_TUNNEL_PROTOCOL_GENEVE: 109fdbe38cfSAndrew Rybchenko mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE; 110fdbe38cfSAndrew Rybchenko break; 111fdbe38cfSAndrew Rybchenko default: 112fdbe38cfSAndrew Rybchenko rc = EINVAL; 113fdbe38cfSAndrew Rybchenko goto fail1; 114fdbe38cfSAndrew Rybchenko } 115fdbe38cfSAndrew Rybchenko 116fdbe38cfSAndrew Rybchenko /* 117fdbe38cfSAndrew Rybchenko * UDP port is MCDI native little-endian in the request 118fdbe38cfSAndrew Rybchenko * and EFX_POPULATE_DWORD cares about conversion from 119fdbe38cfSAndrew Rybchenko * host/CPU byte order to little-endian. 120fdbe38cfSAndrew Rybchenko */ 121fdbe38cfSAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (efx_dword_t) == 122fdbe38cfSAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_LEN); 123fdbe38cfSAndrew Rybchenko EFX_POPULATE_DWORD_2( 124fdbe38cfSAndrew Rybchenko MCDI_IN2(req, efx_dword_t, 125fdbe38cfSAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES)[i], 126fdbe38cfSAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_UDP_PORT, 127fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries[i].etue_port, 128fdbe38cfSAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_PROTOCOL, 129fdbe38cfSAndrew Rybchenko mcdi_udp_protocol); 130fdbe38cfSAndrew Rybchenko } 131fdbe38cfSAndrew Rybchenko 132fdbe38cfSAndrew Rybchenko efx_mcdi_execute(enp, &req); 133fdbe38cfSAndrew Rybchenko 134fdbe38cfSAndrew Rybchenko if (req.emr_rc != 0) { 135fdbe38cfSAndrew Rybchenko rc = req.emr_rc; 136fdbe38cfSAndrew Rybchenko goto fail2; 137fdbe38cfSAndrew Rybchenko } 138fdbe38cfSAndrew Rybchenko 139fdbe38cfSAndrew Rybchenko if (req.emr_out_length_used != 140fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) { 141fdbe38cfSAndrew Rybchenko rc = EMSGSIZE; 142fdbe38cfSAndrew Rybchenko goto fail3; 143fdbe38cfSAndrew Rybchenko } 144fdbe38cfSAndrew Rybchenko 145fdbe38cfSAndrew Rybchenko *resetting = MCDI_OUT_WORD_FIELD(req, 146fdbe38cfSAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS, 147fdbe38cfSAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING); 148fdbe38cfSAndrew Rybchenko 149fdbe38cfSAndrew Rybchenko return (0); 150fdbe38cfSAndrew Rybchenko 151fdbe38cfSAndrew Rybchenko fail3: 152fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail3); 153fdbe38cfSAndrew Rybchenko 154fdbe38cfSAndrew Rybchenko fail2: 155fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 156fdbe38cfSAndrew Rybchenko 157fdbe38cfSAndrew Rybchenko fail1: 158fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 159fdbe38cfSAndrew Rybchenko 160fdbe38cfSAndrew Rybchenko return (rc); 161fdbe38cfSAndrew Rybchenko } 162fdbe38cfSAndrew Rybchenko 163fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 164fdbe38cfSAndrew Rybchenko efx_tunnel_init( 165fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 166fdbe38cfSAndrew Rybchenko { 167fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 168fdbe38cfSAndrew Rybchenko const efx_tunnel_ops_t *etop; 169fdbe38cfSAndrew Rybchenko efx_rc_t rc; 170fdbe38cfSAndrew Rybchenko 171fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 172fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 173fdbe38cfSAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TUNNEL)); 174fdbe38cfSAndrew Rybchenko 175fdbe38cfSAndrew Rybchenko EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES == 176fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM); 177fdbe38cfSAndrew Rybchenko 178fdbe38cfSAndrew Rybchenko switch (enp->en_family) { 179fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_SIENA 180fdbe38cfSAndrew Rybchenko case EFX_FAMILY_SIENA: 181fdbe38cfSAndrew Rybchenko etop = &__efx_tunnel_dummy_ops; 182fdbe38cfSAndrew Rybchenko break; 183fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */ 184fdbe38cfSAndrew Rybchenko 185fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON 186fdbe38cfSAndrew Rybchenko case EFX_FAMILY_HUNTINGTON: 187fdbe38cfSAndrew Rybchenko etop = &__efx_tunnel_dummy_ops; 188fdbe38cfSAndrew Rybchenko break; 189fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */ 190fdbe38cfSAndrew Rybchenko 191fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_MEDFORD 192fdbe38cfSAndrew Rybchenko case EFX_FAMILY_MEDFORD: 193*edaff290SAndrew Rybchenko etop = &__efx_tunnel_ef10_ops; 194fdbe38cfSAndrew Rybchenko break; 195fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */ 196fdbe38cfSAndrew Rybchenko 197*edaff290SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2 198*edaff290SAndrew Rybchenko case EFX_FAMILY_MEDFORD2: 199*edaff290SAndrew Rybchenko etop = &__efx_tunnel_ef10_ops; 200*edaff290SAndrew Rybchenko break; 201*edaff290SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */ 202*edaff290SAndrew Rybchenko 203fdbe38cfSAndrew Rybchenko default: 204fdbe38cfSAndrew Rybchenko EFSYS_ASSERT(0); 205fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 206fdbe38cfSAndrew Rybchenko goto fail1; 207fdbe38cfSAndrew Rybchenko } 208fdbe38cfSAndrew Rybchenko 209fdbe38cfSAndrew Rybchenko memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries)); 210fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num = 0; 211fdbe38cfSAndrew Rybchenko 212fdbe38cfSAndrew Rybchenko enp->en_etop = etop; 213fdbe38cfSAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_TUNNEL; 214fdbe38cfSAndrew Rybchenko 215fdbe38cfSAndrew Rybchenko return (0); 216fdbe38cfSAndrew Rybchenko 217fdbe38cfSAndrew Rybchenko fail1: 218fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 219fdbe38cfSAndrew Rybchenko 220fdbe38cfSAndrew Rybchenko enp->en_etop = NULL; 221fdbe38cfSAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_TUNNEL; 222fdbe38cfSAndrew Rybchenko 223fdbe38cfSAndrew Rybchenko return (rc); 224fdbe38cfSAndrew Rybchenko } 225fdbe38cfSAndrew Rybchenko 226fdbe38cfSAndrew Rybchenko void 227fdbe38cfSAndrew Rybchenko efx_tunnel_fini( 228fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 229fdbe38cfSAndrew Rybchenko { 230fdbe38cfSAndrew Rybchenko boolean_t resetting; 231fdbe38cfSAndrew Rybchenko 232fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 233fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 234fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 235fdbe38cfSAndrew Rybchenko 236fdbe38cfSAndrew Rybchenko if ((enp->en_etop->eto_udp_encap_supported != NULL) && 237fdbe38cfSAndrew Rybchenko enp->en_etop->eto_udp_encap_supported(enp)) { 238fdbe38cfSAndrew Rybchenko /* 239fdbe38cfSAndrew Rybchenko * The UNLOADING flag allows the MC to suppress the datapath 240fdbe38cfSAndrew Rybchenko * reset if it was set on the last call to 241fdbe38cfSAndrew Rybchenko * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions 242fdbe38cfSAndrew Rybchenko */ 243fdbe38cfSAndrew Rybchenko (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE, 244fdbe38cfSAndrew Rybchenko &resetting); 245fdbe38cfSAndrew Rybchenko } 246fdbe38cfSAndrew Rybchenko 247fdbe38cfSAndrew Rybchenko enp->en_etop = NULL; 248fdbe38cfSAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_TUNNEL; 249fdbe38cfSAndrew Rybchenko } 250fdbe38cfSAndrew Rybchenko 251fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 252fdbe38cfSAndrew Rybchenko efx_tunnel_config_find_udp_tunnel_entry( 253fdbe38cfSAndrew Rybchenko __in efx_tunnel_cfg_t *etcp, 254fdbe38cfSAndrew Rybchenko __in uint16_t port, 255fdbe38cfSAndrew Rybchenko __out unsigned int *entryp) 256fdbe38cfSAndrew Rybchenko { 257fdbe38cfSAndrew Rybchenko unsigned int i; 258fdbe38cfSAndrew Rybchenko 259fdbe38cfSAndrew Rybchenko for (i = 0; i < etcp->etc_udp_entries_num; ++i) { 260fdbe38cfSAndrew Rybchenko efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i]; 261fdbe38cfSAndrew Rybchenko 262fdbe38cfSAndrew Rybchenko if (p->etue_port == port) { 263fdbe38cfSAndrew Rybchenko *entryp = i; 264fdbe38cfSAndrew Rybchenko return (0); 265fdbe38cfSAndrew Rybchenko } 266fdbe38cfSAndrew Rybchenko } 267fdbe38cfSAndrew Rybchenko 268fdbe38cfSAndrew Rybchenko return (ENOENT); 269fdbe38cfSAndrew Rybchenko } 270fdbe38cfSAndrew Rybchenko 271fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 272fdbe38cfSAndrew Rybchenko efx_tunnel_config_udp_add( 273fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp, 274fdbe38cfSAndrew Rybchenko __in uint16_t port /* host/cpu-endian */, 275fdbe38cfSAndrew Rybchenko __in efx_tunnel_protocol_t protocol) 276fdbe38cfSAndrew Rybchenko { 277fdbe38cfSAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 278fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 279fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 280fdbe38cfSAndrew Rybchenko efx_rc_t rc; 281fdbe38cfSAndrew Rybchenko unsigned int entry; 282fdbe38cfSAndrew Rybchenko 283fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 284fdbe38cfSAndrew Rybchenko 285fdbe38cfSAndrew Rybchenko if (protocol >= EFX_TUNNEL_NPROTOS) { 286fdbe38cfSAndrew Rybchenko rc = EINVAL; 287fdbe38cfSAndrew Rybchenko goto fail1; 288fdbe38cfSAndrew Rybchenko } 289fdbe38cfSAndrew Rybchenko 290fdbe38cfSAndrew Rybchenko if ((encp->enc_tunnel_encapsulations_supported & 291fdbe38cfSAndrew Rybchenko (1u << protocol)) == 0) { 292fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 293fdbe38cfSAndrew Rybchenko goto fail2; 294fdbe38cfSAndrew Rybchenko } 295fdbe38cfSAndrew Rybchenko 296fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 297fdbe38cfSAndrew Rybchenko 298fdbe38cfSAndrew Rybchenko rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry); 299fdbe38cfSAndrew Rybchenko if (rc == 0) { 300fdbe38cfSAndrew Rybchenko rc = EEXIST; 301fdbe38cfSAndrew Rybchenko goto fail3; 302fdbe38cfSAndrew Rybchenko } 303fdbe38cfSAndrew Rybchenko 304fdbe38cfSAndrew Rybchenko if (etcp->etc_udp_entries_num == 305fdbe38cfSAndrew Rybchenko encp->enc_tunnel_config_udp_entries_max) { 306fdbe38cfSAndrew Rybchenko rc = ENOSPC; 307fdbe38cfSAndrew Rybchenko goto fail4; 308fdbe38cfSAndrew Rybchenko } 309fdbe38cfSAndrew Rybchenko 310fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port; 311fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol = 312fdbe38cfSAndrew Rybchenko protocol; 313fdbe38cfSAndrew Rybchenko 314fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num++; 315fdbe38cfSAndrew Rybchenko 316fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 317fdbe38cfSAndrew Rybchenko 318fdbe38cfSAndrew Rybchenko return (0); 319fdbe38cfSAndrew Rybchenko 320fdbe38cfSAndrew Rybchenko fail4: 321fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail4); 322fdbe38cfSAndrew Rybchenko 323fdbe38cfSAndrew Rybchenko fail3: 324fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail3); 325fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 326fdbe38cfSAndrew Rybchenko 327fdbe38cfSAndrew Rybchenko fail2: 328fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 329fdbe38cfSAndrew Rybchenko 330fdbe38cfSAndrew Rybchenko fail1: 331fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 332fdbe38cfSAndrew Rybchenko 333fdbe38cfSAndrew Rybchenko return (rc); 334fdbe38cfSAndrew Rybchenko } 335fdbe38cfSAndrew Rybchenko 336fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 337fdbe38cfSAndrew Rybchenko efx_tunnel_config_udp_remove( 338fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp, 339fdbe38cfSAndrew Rybchenko __in uint16_t port /* host/cpu-endian */, 340fdbe38cfSAndrew Rybchenko __in efx_tunnel_protocol_t protocol) 341fdbe38cfSAndrew Rybchenko { 342fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 343fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 344fdbe38cfSAndrew Rybchenko unsigned int entry; 345fdbe38cfSAndrew Rybchenko efx_rc_t rc; 346fdbe38cfSAndrew Rybchenko 347fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 348fdbe38cfSAndrew Rybchenko 349fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 350fdbe38cfSAndrew Rybchenko 351fdbe38cfSAndrew Rybchenko rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry); 352fdbe38cfSAndrew Rybchenko if (rc != 0) 353fdbe38cfSAndrew Rybchenko goto fail1; 354fdbe38cfSAndrew Rybchenko 355fdbe38cfSAndrew Rybchenko if (etcp->etc_udp_entries[entry].etue_protocol != protocol) { 356fdbe38cfSAndrew Rybchenko rc = EINVAL; 357fdbe38cfSAndrew Rybchenko goto fail2; 358fdbe38cfSAndrew Rybchenko } 359fdbe38cfSAndrew Rybchenko 360fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0); 361fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num--; 362fdbe38cfSAndrew Rybchenko 363fdbe38cfSAndrew Rybchenko if (entry < etcp->etc_udp_entries_num) { 364fdbe38cfSAndrew Rybchenko memmove(&etcp->etc_udp_entries[entry], 365fdbe38cfSAndrew Rybchenko &etcp->etc_udp_entries[entry + 1], 366fdbe38cfSAndrew Rybchenko (etcp->etc_udp_entries_num - entry) * 367fdbe38cfSAndrew Rybchenko sizeof (etcp->etc_udp_entries[0])); 368fdbe38cfSAndrew Rybchenko } 369fdbe38cfSAndrew Rybchenko 370fdbe38cfSAndrew Rybchenko memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0, 371fdbe38cfSAndrew Rybchenko sizeof (etcp->etc_udp_entries[0])); 372fdbe38cfSAndrew Rybchenko 373fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 374fdbe38cfSAndrew Rybchenko 375fdbe38cfSAndrew Rybchenko return (0); 376fdbe38cfSAndrew Rybchenko 377fdbe38cfSAndrew Rybchenko fail2: 378fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 379fdbe38cfSAndrew Rybchenko 380fdbe38cfSAndrew Rybchenko fail1: 381fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 382fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 383fdbe38cfSAndrew Rybchenko 384fdbe38cfSAndrew Rybchenko return (rc); 385fdbe38cfSAndrew Rybchenko } 386fdbe38cfSAndrew Rybchenko 387fdbe38cfSAndrew Rybchenko void 388fdbe38cfSAndrew Rybchenko efx_tunnel_config_clear( 389fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 390fdbe38cfSAndrew Rybchenko { 391fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 392fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 393fdbe38cfSAndrew Rybchenko 394fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 395fdbe38cfSAndrew Rybchenko 396fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 397fdbe38cfSAndrew Rybchenko 398fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num = 0; 399fdbe38cfSAndrew Rybchenko memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries)); 400fdbe38cfSAndrew Rybchenko 401fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 402fdbe38cfSAndrew Rybchenko } 403fdbe38cfSAndrew Rybchenko 404fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 405fdbe38cfSAndrew Rybchenko efx_tunnel_reconfigure( 406fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 407fdbe38cfSAndrew Rybchenko { 408fdbe38cfSAndrew Rybchenko const efx_tunnel_ops_t *etop = enp->en_etop; 409fdbe38cfSAndrew Rybchenko efx_rc_t rc; 410fdbe38cfSAndrew Rybchenko 411fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 412fdbe38cfSAndrew Rybchenko 413fdbe38cfSAndrew Rybchenko if (etop->eto_reconfigure == NULL) { 414fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 415fdbe38cfSAndrew Rybchenko goto fail1; 416fdbe38cfSAndrew Rybchenko } 417fdbe38cfSAndrew Rybchenko 418fdbe38cfSAndrew Rybchenko if ((rc = enp->en_etop->eto_reconfigure(enp)) != 0) 419fdbe38cfSAndrew Rybchenko goto fail2; 420fdbe38cfSAndrew Rybchenko 421fdbe38cfSAndrew Rybchenko return (0); 422fdbe38cfSAndrew Rybchenko 423fdbe38cfSAndrew Rybchenko fail2: 424fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 425fdbe38cfSAndrew Rybchenko 426fdbe38cfSAndrew Rybchenko fail1: 427fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 428fdbe38cfSAndrew Rybchenko 429fdbe38cfSAndrew Rybchenko return (rc); 430fdbe38cfSAndrew Rybchenko } 431fdbe38cfSAndrew Rybchenko 432*edaff290SAndrew Rybchenko #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 433fdbe38cfSAndrew Rybchenko static __checkReturn boolean_t 434*edaff290SAndrew Rybchenko ef10_udp_encap_supported( 435fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 436fdbe38cfSAndrew Rybchenko { 437fdbe38cfSAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 438fdbe38cfSAndrew Rybchenko uint32_t udp_tunnels_mask = 0; 439fdbe38cfSAndrew Rybchenko 440fdbe38cfSAndrew Rybchenko udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN); 441fdbe38cfSAndrew Rybchenko udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE); 442fdbe38cfSAndrew Rybchenko 443fdbe38cfSAndrew Rybchenko return ((encp->enc_tunnel_encapsulations_supported & 444fdbe38cfSAndrew Rybchenko udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE); 445fdbe38cfSAndrew Rybchenko } 446fdbe38cfSAndrew Rybchenko 447fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 448*edaff290SAndrew Rybchenko ef10_tunnel_reconfigure( 449fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 450fdbe38cfSAndrew Rybchenko { 451fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 452fdbe38cfSAndrew Rybchenko efx_rc_t rc; 453fdbe38cfSAndrew Rybchenko boolean_t resetting; 454fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 455fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t etc; 456fdbe38cfSAndrew Rybchenko 457fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 458fdbe38cfSAndrew Rybchenko memcpy(&etc, etcp, sizeof (etc)); 459fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 460fdbe38cfSAndrew Rybchenko 461*edaff290SAndrew Rybchenko if (ef10_udp_encap_supported(enp) == B_FALSE) { 462fdbe38cfSAndrew Rybchenko /* 463fdbe38cfSAndrew Rybchenko * It is OK to apply empty UDP tunnel ports when UDP 464fdbe38cfSAndrew Rybchenko * tunnel encapsulations are not supported - just nothing 465fdbe38cfSAndrew Rybchenko * should be done. 466fdbe38cfSAndrew Rybchenko */ 467fdbe38cfSAndrew Rybchenko if (etc.etc_udp_entries_num == 0) 468fdbe38cfSAndrew Rybchenko return (0); 469fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 470fdbe38cfSAndrew Rybchenko goto fail1; 471fdbe38cfSAndrew Rybchenko } else { 472fdbe38cfSAndrew Rybchenko /* 473fdbe38cfSAndrew Rybchenko * All PCI functions can see a reset upon the 474fdbe38cfSAndrew Rybchenko * MCDI request completion 475fdbe38cfSAndrew Rybchenko */ 476fdbe38cfSAndrew Rybchenko rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE, 477fdbe38cfSAndrew Rybchenko &resetting); 478fdbe38cfSAndrew Rybchenko if (rc != 0) 479fdbe38cfSAndrew Rybchenko goto fail2; 480fdbe38cfSAndrew Rybchenko 481fdbe38cfSAndrew Rybchenko /* 482fdbe38cfSAndrew Rybchenko * Although the caller should be able to handle MC reboot, 483fdbe38cfSAndrew Rybchenko * it might come in handy to report the impending reboot 484fdbe38cfSAndrew Rybchenko * by returning EAGAIN 485fdbe38cfSAndrew Rybchenko */ 486fdbe38cfSAndrew Rybchenko return ((resetting) ? EAGAIN : 0); 487fdbe38cfSAndrew Rybchenko } 488fdbe38cfSAndrew Rybchenko fail2: 489fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 490fdbe38cfSAndrew Rybchenko 491fdbe38cfSAndrew Rybchenko fail1: 492fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 493fdbe38cfSAndrew Rybchenko 494fdbe38cfSAndrew Rybchenko return (rc); 495fdbe38cfSAndrew Rybchenko } 496*edaff290SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 497fdbe38cfSAndrew Rybchenko 498fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_TUNNEL */ 499