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