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