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 42 static 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 49 static __checkReturn boolean_t 50 ef10_udp_encap_supported( 51 __in efx_nic_t *enp); 52 53 static __checkReturn efx_rc_t 54 ef10_tunnel_reconfigure( 55 __in efx_nic_t *enp); 56 57 static 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 63 static __checkReturn efx_rc_t 64 efx_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 150 fail3: 151 EFSYS_PROBE(fail3); 152 153 fail2: 154 EFSYS_PROBE(fail2); 155 156 fail1: 157 EFSYS_PROBE1(fail1, efx_rc_t, rc); 158 159 return (rc); 160 } 161 162 __checkReturn efx_rc_t 163 efx_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 216 fail1: 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 226 efx_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 250 static __checkReturn efx_rc_t 251 efx_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 271 efx_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 319 fail4: 320 EFSYS_PROBE(fail4); 321 322 fail3: 323 EFSYS_PROBE(fail3); 324 EFSYS_UNLOCK(enp->en_eslp, state); 325 326 fail2: 327 EFSYS_PROBE(fail2); 328 329 fail1: 330 EFSYS_PROBE1(fail1, efx_rc_t, rc); 331 332 return (rc); 333 } 334 335 __checkReturn efx_rc_t 336 efx_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 376 fail2: 377 EFSYS_PROBE(fail2); 378 379 fail1: 380 EFSYS_PROBE1(fail1, efx_rc_t, rc); 381 EFSYS_UNLOCK(enp->en_eslp, state); 382 383 return (rc); 384 } 385 386 void 387 efx_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 404 efx_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 422 fail2: 423 EFSYS_PROBE(fail2); 424 425 fail1: 426 EFSYS_PROBE1(fail1, efx_rc_t, rc); 427 428 return (rc); 429 } 430 431 #if EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 432 static __checkReturn boolean_t 433 ef10_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 446 static __checkReturn efx_rc_t 447 ef10_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 } 487 fail2: 488 EFSYS_PROBE(fail2); 489 490 fail1: 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