1fdbe38cfSAndrew Rybchenko /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 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 #if EFSYS_OPT_TUNNEL 40fdbe38cfSAndrew Rybchenko 41fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON 42fdbe38cfSAndrew Rybchenko static const efx_tunnel_ops_t __efx_tunnel_dummy_ops = { 43fdbe38cfSAndrew Rybchenko NULL, /* eto_udp_encap_supported */ 44fdbe38cfSAndrew Rybchenko NULL, /* eto_reconfigure */ 45fdbe38cfSAndrew Rybchenko }; 46fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA || EFSYS_OPT_HUNTINGTON */ 47fdbe38cfSAndrew Rybchenko 48edaff290SAndrew Rybchenko #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 49fdbe38cfSAndrew Rybchenko static __checkReturn boolean_t 50edaff290SAndrew Rybchenko ef10_udp_encap_supported( 51fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp); 52fdbe38cfSAndrew Rybchenko 53fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 54edaff290SAndrew Rybchenko ef10_tunnel_reconfigure( 55fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp); 56fdbe38cfSAndrew Rybchenko 57edaff290SAndrew Rybchenko static const efx_tunnel_ops_t __efx_tunnel_ef10_ops = { 58edaff290SAndrew Rybchenko ef10_udp_encap_supported, /* eto_udp_encap_supported */ 59edaff290SAndrew Rybchenko ef10_tunnel_reconfigure, /* eto_reconfigure */ 60fdbe38cfSAndrew Rybchenko }; 61edaff290SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 62fdbe38cfSAndrew Rybchenko 63fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 64fdbe38cfSAndrew Rybchenko efx_mcdi_set_tunnel_encap_udp_ports( 65fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp, 66fdbe38cfSAndrew Rybchenko __in efx_tunnel_cfg_t *etcp, 67fdbe38cfSAndrew Rybchenko __in boolean_t unloading, 68fdbe38cfSAndrew Rybchenko __out boolean_t *resetting) 69fdbe38cfSAndrew Rybchenko { 70fdbe38cfSAndrew Rybchenko efx_mcdi_req_t req; 71315bbbaaSAndrew Rybchenko EFX_MCDI_DECLARE_BUF(payload, 72315bbbaaSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LENMAX, 73315bbbaaSAndrew 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 req.emr_cmd = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS; 85fdbe38cfSAndrew Rybchenko req.emr_in_buf = payload; 86fdbe38cfSAndrew Rybchenko req.emr_in_length = 87fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_LEN(entries_num); 88fdbe38cfSAndrew Rybchenko req.emr_out_buf = payload; 89fdbe38cfSAndrew Rybchenko req.emr_out_length = MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN; 90fdbe38cfSAndrew Rybchenko 91fdbe38cfSAndrew Rybchenko EFX_POPULATE_WORD_1(flags, 92fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_UNLOADING, 93fdbe38cfSAndrew Rybchenko (unloading == B_TRUE) ? 1 : 0); 94fdbe38cfSAndrew Rybchenko MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_FLAGS, 95fdbe38cfSAndrew Rybchenko EFX_WORD_FIELD(flags, EFX_WORD_0)); 96fdbe38cfSAndrew Rybchenko 97fdbe38cfSAndrew Rybchenko MCDI_IN_SET_WORD(req, SET_TUNNEL_ENCAP_UDP_PORTS_IN_NUM_ENTRIES, 98fdbe38cfSAndrew Rybchenko entries_num); 99fdbe38cfSAndrew Rybchenko 100fdbe38cfSAndrew Rybchenko for (i = 0; i < entries_num; ++i) { 101fdbe38cfSAndrew Rybchenko uint16_t mcdi_udp_protocol; 102fdbe38cfSAndrew Rybchenko 103fdbe38cfSAndrew Rybchenko switch (etcp->etc_udp_entries[i].etue_protocol) { 104fdbe38cfSAndrew Rybchenko case EFX_TUNNEL_PROTOCOL_VXLAN: 105fdbe38cfSAndrew Rybchenko mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_VXLAN; 106fdbe38cfSAndrew Rybchenko break; 107fdbe38cfSAndrew Rybchenko case EFX_TUNNEL_PROTOCOL_GENEVE: 108fdbe38cfSAndrew Rybchenko mcdi_udp_protocol = TUNNEL_ENCAP_UDP_PORT_ENTRY_GENEVE; 109fdbe38cfSAndrew Rybchenko break; 110fdbe38cfSAndrew Rybchenko default: 111fdbe38cfSAndrew Rybchenko rc = EINVAL; 112fdbe38cfSAndrew Rybchenko goto fail1; 113fdbe38cfSAndrew Rybchenko } 114fdbe38cfSAndrew Rybchenko 115fdbe38cfSAndrew Rybchenko /* 116fdbe38cfSAndrew Rybchenko * UDP port is MCDI native little-endian in the request 117fdbe38cfSAndrew Rybchenko * and EFX_POPULATE_DWORD cares about conversion from 118fdbe38cfSAndrew Rybchenko * host/CPU byte order to little-endian. 119fdbe38cfSAndrew Rybchenko */ 120fdbe38cfSAndrew Rybchenko EFX_STATIC_ASSERT(sizeof (efx_dword_t) == 121fdbe38cfSAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_LEN); 122fdbe38cfSAndrew Rybchenko EFX_POPULATE_DWORD_2( 123fdbe38cfSAndrew Rybchenko MCDI_IN2(req, efx_dword_t, 124fdbe38cfSAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES)[i], 125fdbe38cfSAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_UDP_PORT, 126fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries[i].etue_port, 127fdbe38cfSAndrew Rybchenko TUNNEL_ENCAP_UDP_PORT_ENTRY_PROTOCOL, 128fdbe38cfSAndrew Rybchenko mcdi_udp_protocol); 129fdbe38cfSAndrew Rybchenko } 130fdbe38cfSAndrew Rybchenko 131fdbe38cfSAndrew Rybchenko efx_mcdi_execute(enp, &req); 132fdbe38cfSAndrew Rybchenko 133fdbe38cfSAndrew Rybchenko if (req.emr_rc != 0) { 134fdbe38cfSAndrew Rybchenko rc = req.emr_rc; 135fdbe38cfSAndrew Rybchenko goto fail2; 136fdbe38cfSAndrew Rybchenko } 137fdbe38cfSAndrew Rybchenko 138fdbe38cfSAndrew Rybchenko if (req.emr_out_length_used != 139fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_OUT_LEN) { 140fdbe38cfSAndrew Rybchenko rc = EMSGSIZE; 141fdbe38cfSAndrew Rybchenko goto fail3; 142fdbe38cfSAndrew Rybchenko } 143fdbe38cfSAndrew Rybchenko 144fdbe38cfSAndrew Rybchenko *resetting = MCDI_OUT_WORD_FIELD(req, 145fdbe38cfSAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_OUT_FLAGS, 146fdbe38cfSAndrew Rybchenko SET_TUNNEL_ENCAP_UDP_PORTS_OUT_RESETTING); 147fdbe38cfSAndrew Rybchenko 148fdbe38cfSAndrew Rybchenko return (0); 149fdbe38cfSAndrew Rybchenko 150fdbe38cfSAndrew Rybchenko fail3: 151fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail3); 152fdbe38cfSAndrew Rybchenko 153fdbe38cfSAndrew Rybchenko fail2: 154fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 155fdbe38cfSAndrew Rybchenko 156fdbe38cfSAndrew Rybchenko fail1: 157fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 158fdbe38cfSAndrew Rybchenko 159fdbe38cfSAndrew Rybchenko return (rc); 160fdbe38cfSAndrew Rybchenko } 161fdbe38cfSAndrew Rybchenko 162fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 163fdbe38cfSAndrew Rybchenko efx_tunnel_init( 164fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 165fdbe38cfSAndrew Rybchenko { 166fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 167fdbe38cfSAndrew Rybchenko const efx_tunnel_ops_t *etop; 168fdbe38cfSAndrew Rybchenko efx_rc_t rc; 169fdbe38cfSAndrew Rybchenko 170fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 171fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 172fdbe38cfSAndrew Rybchenko EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TUNNEL)); 173fdbe38cfSAndrew Rybchenko 174fdbe38cfSAndrew Rybchenko EFX_STATIC_ASSERT(EFX_TUNNEL_MAXNENTRIES == 175fdbe38cfSAndrew Rybchenko MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS_IN_ENTRIES_MAXNUM); 176fdbe38cfSAndrew Rybchenko 177fdbe38cfSAndrew Rybchenko switch (enp->en_family) { 178fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_SIENA 179fdbe38cfSAndrew Rybchenko case EFX_FAMILY_SIENA: 180fdbe38cfSAndrew Rybchenko etop = &__efx_tunnel_dummy_ops; 181fdbe38cfSAndrew Rybchenko break; 182fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_SIENA */ 183fdbe38cfSAndrew Rybchenko 184fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_HUNTINGTON 185fdbe38cfSAndrew Rybchenko case EFX_FAMILY_HUNTINGTON: 186fdbe38cfSAndrew Rybchenko etop = &__efx_tunnel_dummy_ops; 187fdbe38cfSAndrew Rybchenko break; 188fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_HUNTINGTON */ 189fdbe38cfSAndrew Rybchenko 190fdbe38cfSAndrew Rybchenko #if EFSYS_OPT_MEDFORD 191fdbe38cfSAndrew Rybchenko case EFX_FAMILY_MEDFORD: 192edaff290SAndrew Rybchenko etop = &__efx_tunnel_ef10_ops; 193fdbe38cfSAndrew Rybchenko break; 194fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD */ 195fdbe38cfSAndrew Rybchenko 196edaff290SAndrew Rybchenko #if EFSYS_OPT_MEDFORD2 197edaff290SAndrew Rybchenko case EFX_FAMILY_MEDFORD2: 198edaff290SAndrew Rybchenko etop = &__efx_tunnel_ef10_ops; 199edaff290SAndrew Rybchenko break; 200edaff290SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD2 */ 201edaff290SAndrew Rybchenko 202fdbe38cfSAndrew Rybchenko default: 203fdbe38cfSAndrew Rybchenko EFSYS_ASSERT(0); 204fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 205fdbe38cfSAndrew Rybchenko goto fail1; 206fdbe38cfSAndrew Rybchenko } 207fdbe38cfSAndrew Rybchenko 208fdbe38cfSAndrew Rybchenko memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries)); 209fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num = 0; 210fdbe38cfSAndrew Rybchenko 211fdbe38cfSAndrew Rybchenko enp->en_etop = etop; 212fdbe38cfSAndrew Rybchenko enp->en_mod_flags |= EFX_MOD_TUNNEL; 213fdbe38cfSAndrew Rybchenko 214fdbe38cfSAndrew Rybchenko return (0); 215fdbe38cfSAndrew Rybchenko 216fdbe38cfSAndrew Rybchenko fail1: 217fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 218fdbe38cfSAndrew Rybchenko 219fdbe38cfSAndrew Rybchenko enp->en_etop = NULL; 220fdbe38cfSAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_TUNNEL; 221fdbe38cfSAndrew Rybchenko 222fdbe38cfSAndrew Rybchenko return (rc); 223fdbe38cfSAndrew Rybchenko } 224fdbe38cfSAndrew Rybchenko 225fdbe38cfSAndrew Rybchenko void 226fdbe38cfSAndrew Rybchenko efx_tunnel_fini( 227fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 228fdbe38cfSAndrew Rybchenko { 229fdbe38cfSAndrew Rybchenko boolean_t resetting; 230fdbe38cfSAndrew Rybchenko 231fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 232fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 233fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 234fdbe38cfSAndrew Rybchenko 235fdbe38cfSAndrew Rybchenko if ((enp->en_etop->eto_udp_encap_supported != NULL) && 236fdbe38cfSAndrew Rybchenko enp->en_etop->eto_udp_encap_supported(enp)) { 237fdbe38cfSAndrew Rybchenko /* 238fdbe38cfSAndrew Rybchenko * The UNLOADING flag allows the MC to suppress the datapath 239fdbe38cfSAndrew Rybchenko * reset if it was set on the last call to 240fdbe38cfSAndrew Rybchenko * MC_CMD_SET_TUNNEL_ENCAP_UDP_PORTS by all functions 241fdbe38cfSAndrew Rybchenko */ 242fdbe38cfSAndrew Rybchenko (void) efx_mcdi_set_tunnel_encap_udp_ports(enp, NULL, B_TRUE, 243fdbe38cfSAndrew Rybchenko &resetting); 244fdbe38cfSAndrew Rybchenko } 245fdbe38cfSAndrew Rybchenko 246fdbe38cfSAndrew Rybchenko enp->en_etop = NULL; 247fdbe38cfSAndrew Rybchenko enp->en_mod_flags &= ~EFX_MOD_TUNNEL; 248fdbe38cfSAndrew Rybchenko } 249fdbe38cfSAndrew Rybchenko 250fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 251fdbe38cfSAndrew Rybchenko efx_tunnel_config_find_udp_tunnel_entry( 252fdbe38cfSAndrew Rybchenko __in efx_tunnel_cfg_t *etcp, 253fdbe38cfSAndrew Rybchenko __in uint16_t port, 254fdbe38cfSAndrew Rybchenko __out unsigned int *entryp) 255fdbe38cfSAndrew Rybchenko { 256fdbe38cfSAndrew Rybchenko unsigned int i; 257fdbe38cfSAndrew Rybchenko 258fdbe38cfSAndrew Rybchenko for (i = 0; i < etcp->etc_udp_entries_num; ++i) { 259fdbe38cfSAndrew Rybchenko efx_tunnel_udp_entry_t *p = &etcp->etc_udp_entries[i]; 260fdbe38cfSAndrew Rybchenko 261fdbe38cfSAndrew Rybchenko if (p->etue_port == port) { 262fdbe38cfSAndrew Rybchenko *entryp = i; 263fdbe38cfSAndrew Rybchenko return (0); 264fdbe38cfSAndrew Rybchenko } 265fdbe38cfSAndrew Rybchenko } 266fdbe38cfSAndrew Rybchenko 267fdbe38cfSAndrew Rybchenko return (ENOENT); 268fdbe38cfSAndrew Rybchenko } 269fdbe38cfSAndrew Rybchenko 270fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 271fdbe38cfSAndrew Rybchenko efx_tunnel_config_udp_add( 272fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp, 273fdbe38cfSAndrew Rybchenko __in uint16_t port /* host/cpu-endian */, 274fdbe38cfSAndrew Rybchenko __in efx_tunnel_protocol_t protocol) 275fdbe38cfSAndrew Rybchenko { 276fdbe38cfSAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 277fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 278fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 279fdbe38cfSAndrew Rybchenko efx_rc_t rc; 280fdbe38cfSAndrew Rybchenko unsigned int entry; 281fdbe38cfSAndrew Rybchenko 282fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 283fdbe38cfSAndrew Rybchenko 284fdbe38cfSAndrew Rybchenko if (protocol >= EFX_TUNNEL_NPROTOS) { 285fdbe38cfSAndrew Rybchenko rc = EINVAL; 286fdbe38cfSAndrew Rybchenko goto fail1; 287fdbe38cfSAndrew Rybchenko } 288fdbe38cfSAndrew Rybchenko 289fdbe38cfSAndrew Rybchenko if ((encp->enc_tunnel_encapsulations_supported & 290fdbe38cfSAndrew Rybchenko (1u << protocol)) == 0) { 291fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 292fdbe38cfSAndrew Rybchenko goto fail2; 293fdbe38cfSAndrew Rybchenko } 294fdbe38cfSAndrew Rybchenko 295fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 296fdbe38cfSAndrew Rybchenko 297fdbe38cfSAndrew Rybchenko rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry); 298fdbe38cfSAndrew Rybchenko if (rc == 0) { 299fdbe38cfSAndrew Rybchenko rc = EEXIST; 300fdbe38cfSAndrew Rybchenko goto fail3; 301fdbe38cfSAndrew Rybchenko } 302fdbe38cfSAndrew Rybchenko 303fdbe38cfSAndrew Rybchenko if (etcp->etc_udp_entries_num == 304fdbe38cfSAndrew Rybchenko encp->enc_tunnel_config_udp_entries_max) { 305fdbe38cfSAndrew Rybchenko rc = ENOSPC; 306fdbe38cfSAndrew Rybchenko goto fail4; 307fdbe38cfSAndrew Rybchenko } 308fdbe38cfSAndrew Rybchenko 309fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_port = port; 310fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries[etcp->etc_udp_entries_num].etue_protocol = 311fdbe38cfSAndrew Rybchenko protocol; 312fdbe38cfSAndrew Rybchenko 313fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num++; 314fdbe38cfSAndrew Rybchenko 315fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 316fdbe38cfSAndrew Rybchenko 317fdbe38cfSAndrew Rybchenko return (0); 318fdbe38cfSAndrew Rybchenko 319fdbe38cfSAndrew Rybchenko fail4: 320fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail4); 321fdbe38cfSAndrew Rybchenko 322fdbe38cfSAndrew Rybchenko fail3: 323fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail3); 324fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 325fdbe38cfSAndrew Rybchenko 326fdbe38cfSAndrew Rybchenko fail2: 327fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 328fdbe38cfSAndrew Rybchenko 329fdbe38cfSAndrew Rybchenko fail1: 330fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 331fdbe38cfSAndrew Rybchenko 332fdbe38cfSAndrew Rybchenko return (rc); 333fdbe38cfSAndrew Rybchenko } 334fdbe38cfSAndrew Rybchenko 335fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 336fdbe38cfSAndrew Rybchenko efx_tunnel_config_udp_remove( 337fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp, 338fdbe38cfSAndrew Rybchenko __in uint16_t port /* host/cpu-endian */, 339fdbe38cfSAndrew Rybchenko __in efx_tunnel_protocol_t protocol) 340fdbe38cfSAndrew Rybchenko { 341fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 342fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 343fdbe38cfSAndrew Rybchenko unsigned int entry; 344fdbe38cfSAndrew Rybchenko efx_rc_t rc; 345fdbe38cfSAndrew Rybchenko 346fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 347fdbe38cfSAndrew Rybchenko 348fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 349fdbe38cfSAndrew Rybchenko 350fdbe38cfSAndrew Rybchenko rc = efx_tunnel_config_find_udp_tunnel_entry(etcp, port, &entry); 351fdbe38cfSAndrew Rybchenko if (rc != 0) 352fdbe38cfSAndrew Rybchenko goto fail1; 353fdbe38cfSAndrew Rybchenko 354fdbe38cfSAndrew Rybchenko if (etcp->etc_udp_entries[entry].etue_protocol != protocol) { 355fdbe38cfSAndrew Rybchenko rc = EINVAL; 356fdbe38cfSAndrew Rybchenko goto fail2; 357fdbe38cfSAndrew Rybchenko } 358fdbe38cfSAndrew Rybchenko 359fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(etcp->etc_udp_entries_num, >, 0); 360fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num--; 361fdbe38cfSAndrew Rybchenko 362fdbe38cfSAndrew Rybchenko if (entry < etcp->etc_udp_entries_num) { 363fdbe38cfSAndrew Rybchenko memmove(&etcp->etc_udp_entries[entry], 364fdbe38cfSAndrew Rybchenko &etcp->etc_udp_entries[entry + 1], 365fdbe38cfSAndrew Rybchenko (etcp->etc_udp_entries_num - entry) * 366fdbe38cfSAndrew Rybchenko sizeof (etcp->etc_udp_entries[0])); 367fdbe38cfSAndrew Rybchenko } 368fdbe38cfSAndrew Rybchenko 369fdbe38cfSAndrew Rybchenko memset(&etcp->etc_udp_entries[etcp->etc_udp_entries_num], 0, 370fdbe38cfSAndrew Rybchenko sizeof (etcp->etc_udp_entries[0])); 371fdbe38cfSAndrew Rybchenko 372fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 373fdbe38cfSAndrew Rybchenko 374fdbe38cfSAndrew Rybchenko return (0); 375fdbe38cfSAndrew Rybchenko 376fdbe38cfSAndrew Rybchenko fail2: 377fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 378fdbe38cfSAndrew Rybchenko 379fdbe38cfSAndrew Rybchenko fail1: 380fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 381fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 382fdbe38cfSAndrew Rybchenko 383fdbe38cfSAndrew Rybchenko return (rc); 384fdbe38cfSAndrew Rybchenko } 385fdbe38cfSAndrew Rybchenko 386fdbe38cfSAndrew Rybchenko void 387fdbe38cfSAndrew Rybchenko efx_tunnel_config_clear( 388fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 389fdbe38cfSAndrew Rybchenko { 390fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 391fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 392fdbe38cfSAndrew Rybchenko 393fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 394fdbe38cfSAndrew Rybchenko 395fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 396fdbe38cfSAndrew Rybchenko 397fdbe38cfSAndrew Rybchenko etcp->etc_udp_entries_num = 0; 398fdbe38cfSAndrew Rybchenko memset(etcp->etc_udp_entries, 0, sizeof (etcp->etc_udp_entries)); 399fdbe38cfSAndrew Rybchenko 400fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 401fdbe38cfSAndrew Rybchenko } 402fdbe38cfSAndrew Rybchenko 403fdbe38cfSAndrew Rybchenko __checkReturn efx_rc_t 404fdbe38cfSAndrew Rybchenko efx_tunnel_reconfigure( 405fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 406fdbe38cfSAndrew Rybchenko { 407fdbe38cfSAndrew Rybchenko const efx_tunnel_ops_t *etop = enp->en_etop; 408fdbe38cfSAndrew Rybchenko efx_rc_t rc; 409fdbe38cfSAndrew Rybchenko 410fdbe38cfSAndrew Rybchenko EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_TUNNEL); 411fdbe38cfSAndrew Rybchenko 412fdbe38cfSAndrew Rybchenko if (etop->eto_reconfigure == NULL) { 413fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 414fdbe38cfSAndrew Rybchenko goto fail1; 415fdbe38cfSAndrew Rybchenko } 416fdbe38cfSAndrew Rybchenko 417fdbe38cfSAndrew Rybchenko if ((rc = enp->en_etop->eto_reconfigure(enp)) != 0) 418fdbe38cfSAndrew Rybchenko goto fail2; 419fdbe38cfSAndrew Rybchenko 420fdbe38cfSAndrew Rybchenko return (0); 421fdbe38cfSAndrew Rybchenko 422fdbe38cfSAndrew Rybchenko fail2: 423fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 424fdbe38cfSAndrew Rybchenko 425fdbe38cfSAndrew Rybchenko fail1: 426fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 427fdbe38cfSAndrew Rybchenko 428fdbe38cfSAndrew Rybchenko return (rc); 429fdbe38cfSAndrew Rybchenko } 430fdbe38cfSAndrew Rybchenko 431edaff290SAndrew Rybchenko #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 432fdbe38cfSAndrew Rybchenko static __checkReturn boolean_t 433edaff290SAndrew Rybchenko ef10_udp_encap_supported( 434fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 435fdbe38cfSAndrew Rybchenko { 436fdbe38cfSAndrew Rybchenko const efx_nic_cfg_t *encp = &enp->en_nic_cfg; 437fdbe38cfSAndrew Rybchenko uint32_t udp_tunnels_mask = 0; 438fdbe38cfSAndrew Rybchenko 439fdbe38cfSAndrew Rybchenko udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_VXLAN); 440fdbe38cfSAndrew Rybchenko udp_tunnels_mask |= (1u << EFX_TUNNEL_PROTOCOL_GENEVE); 441fdbe38cfSAndrew Rybchenko 442fdbe38cfSAndrew Rybchenko return ((encp->enc_tunnel_encapsulations_supported & 443fdbe38cfSAndrew Rybchenko udp_tunnels_mask) == 0 ? B_FALSE : B_TRUE); 444fdbe38cfSAndrew Rybchenko } 445fdbe38cfSAndrew Rybchenko 446fdbe38cfSAndrew Rybchenko static __checkReturn efx_rc_t 447edaff290SAndrew Rybchenko ef10_tunnel_reconfigure( 448fdbe38cfSAndrew Rybchenko __in efx_nic_t *enp) 449fdbe38cfSAndrew Rybchenko { 450fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t *etcp = &enp->en_tunnel_cfg; 451fdbe38cfSAndrew Rybchenko efx_rc_t rc; 452fdbe38cfSAndrew Rybchenko boolean_t resetting; 453fdbe38cfSAndrew Rybchenko efsys_lock_state_t state; 454fdbe38cfSAndrew Rybchenko efx_tunnel_cfg_t etc; 455fdbe38cfSAndrew Rybchenko 456fdbe38cfSAndrew Rybchenko EFSYS_LOCK(enp->en_eslp, state); 457fdbe38cfSAndrew Rybchenko memcpy(&etc, etcp, sizeof (etc)); 458fdbe38cfSAndrew Rybchenko EFSYS_UNLOCK(enp->en_eslp, state); 459fdbe38cfSAndrew Rybchenko 460edaff290SAndrew Rybchenko if (ef10_udp_encap_supported(enp) == B_FALSE) { 461fdbe38cfSAndrew Rybchenko /* 462fdbe38cfSAndrew Rybchenko * It is OK to apply empty UDP tunnel ports when UDP 463fdbe38cfSAndrew Rybchenko * tunnel encapsulations are not supported - just nothing 464fdbe38cfSAndrew Rybchenko * should be done. 465fdbe38cfSAndrew Rybchenko */ 466fdbe38cfSAndrew Rybchenko if (etc.etc_udp_entries_num == 0) 467fdbe38cfSAndrew Rybchenko return (0); 468fdbe38cfSAndrew Rybchenko rc = ENOTSUP; 469fdbe38cfSAndrew Rybchenko goto fail1; 470fdbe38cfSAndrew Rybchenko } else { 471fdbe38cfSAndrew Rybchenko /* 472fdbe38cfSAndrew Rybchenko * All PCI functions can see a reset upon the 473fdbe38cfSAndrew Rybchenko * MCDI request completion 474fdbe38cfSAndrew Rybchenko */ 475fdbe38cfSAndrew Rybchenko rc = efx_mcdi_set_tunnel_encap_udp_ports(enp, &etc, B_FALSE, 476fdbe38cfSAndrew Rybchenko &resetting); 477fdbe38cfSAndrew Rybchenko if (rc != 0) 478fdbe38cfSAndrew Rybchenko goto fail2; 479fdbe38cfSAndrew Rybchenko 480fdbe38cfSAndrew Rybchenko /* 481fdbe38cfSAndrew Rybchenko * Although the caller should be able to handle MC reboot, 482fdbe38cfSAndrew Rybchenko * it might come in handy to report the impending reboot 483fdbe38cfSAndrew Rybchenko * by returning EAGAIN 484fdbe38cfSAndrew Rybchenko */ 485fdbe38cfSAndrew Rybchenko return ((resetting) ? EAGAIN : 0); 486fdbe38cfSAndrew Rybchenko } 487fdbe38cfSAndrew Rybchenko fail2: 488fdbe38cfSAndrew Rybchenko EFSYS_PROBE(fail2); 489fdbe38cfSAndrew Rybchenko 490fdbe38cfSAndrew Rybchenko fail1: 491fdbe38cfSAndrew Rybchenko EFSYS_PROBE1(fail1, efx_rc_t, rc); 492fdbe38cfSAndrew Rybchenko 493fdbe38cfSAndrew Rybchenko return (rc); 494fdbe38cfSAndrew Rybchenko } 495edaff290SAndrew Rybchenko #endif /* EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 496fdbe38cfSAndrew Rybchenko 497fdbe38cfSAndrew Rybchenko #endif /* EFSYS_OPT_TUNNEL */ 498