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