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