1 /* SPDX-License-Identifier: BSD-3-Clause 2 * 3 * Copyright(c) 2019-2020 Xilinx, Inc. 4 * Copyright(c) 2018-2019 Solarflare Communications Inc. 5 */ 6 7 #include "efx.h" 8 #include "efx_impl.h" 9 10 11 #if EFSYS_OPT_EVB 12 13 #if EFSYS_OPT_SIENA 14 static const efx_evb_ops_t __efx_evb_dummy_ops = { 15 NULL, /* eeo_init */ 16 NULL, /* eeo_fini */ 17 NULL, /* eeo_vswitch_alloc */ 18 NULL, /* eeo_vswitch_free */ 19 NULL, /* eeo_vport_alloc */ 20 NULL, /* eeo_vport_free */ 21 NULL, /* eeo_vport_mac_addr_add */ 22 NULL, /* eeo_vport_mac_addr_del */ 23 NULL, /* eeo_vadaptor_alloc */ 24 NULL, /* eeo_vadaptor_free */ 25 NULL, /* eeo_vport_assign */ 26 NULL, /* eeo_vport_reconfigure */ 27 NULL, /* eeo_vport_stats */ 28 }; 29 #endif /* EFSYS_OPT_SIENA */ 30 31 #if EFX_OPTS_EF10() 32 static const efx_evb_ops_t __efx_evb_ef10_ops = { 33 ef10_evb_init, /* eeo_init */ 34 ef10_evb_fini, /* eeo_fini */ 35 ef10_evb_vswitch_alloc, /* eeo_vswitch_alloc */ 36 ef10_evb_vswitch_free, /* eeo_vswitch_free */ 37 ef10_evb_vport_alloc, /* eeo_vport_alloc */ 38 ef10_evb_vport_free, /* eeo_vport_free */ 39 ef10_evb_vport_mac_addr_add, /* eeo_vport_mac_addr_add */ 40 ef10_evb_vport_mac_addr_del, /* eeo_vport_mac_addr_del */ 41 ef10_evb_vadaptor_alloc, /* eeo_vadaptor_alloc */ 42 ef10_evb_vadaptor_free, /* eeo_vadaptor_free */ 43 ef10_evb_vport_assign, /* eeo_vport_assign */ 44 ef10_evb_vport_reconfigure, /* eeo_vport_reconfigure */ 45 ef10_evb_vport_stats, /* eeo_vport_stats */ 46 }; 47 #endif /* EFX_OPTS_EF10() */ 48 49 __checkReturn efx_rc_t 50 efx_evb_init( 51 __in efx_nic_t *enp) 52 { 53 const efx_evb_ops_t *eeop; 54 efx_rc_t rc; 55 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 56 57 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 58 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 59 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_EVB)); 60 61 switch (enp->en_family) { 62 #if EFSYS_OPT_SIENA 63 case EFX_FAMILY_SIENA: 64 eeop = &__efx_evb_dummy_ops; 65 break; 66 #endif /* EFSYS_OPT_SIENA */ 67 68 #if EFSYS_OPT_HUNTINGTON 69 case EFX_FAMILY_HUNTINGTON: 70 eeop = &__efx_evb_ef10_ops; 71 break; 72 #endif /* EFSYS_OPT_HUNTINGTON */ 73 74 #if EFSYS_OPT_MEDFORD 75 case EFX_FAMILY_MEDFORD: 76 eeop = &__efx_evb_ef10_ops; 77 break; 78 #endif /* EFSYS_OPT_MEDFORD */ 79 80 #if EFSYS_OPT_MEDFORD2 81 case EFX_FAMILY_MEDFORD2: 82 eeop = &__efx_evb_ef10_ops; 83 break; 84 #endif /* EFSYS_OPT_MEDFORD2 */ 85 86 default: 87 EFSYS_ASSERT(0); 88 rc = ENOTSUP; 89 goto fail1; 90 } 91 92 if (!encp->enc_datapath_cap_evb || !eeop->eeo_init) { 93 rc = ENOTSUP; 94 goto fail2; 95 } 96 97 if ((rc = eeop->eeo_init(enp)) != 0) 98 goto fail3; 99 100 enp->en_eeop = eeop; 101 enp->en_mod_flags |= EFX_MOD_EVB; 102 return (0); 103 104 fail3: 105 EFSYS_PROBE(fail3); 106 fail2: 107 EFSYS_PROBE(fail2); 108 fail1: 109 EFSYS_PROBE1(fail1, efx_rc_t, rc); 110 111 return (rc); 112 } 113 114 void 115 efx_evb_fini( 116 __in efx_nic_t *enp) 117 { 118 const efx_evb_ops_t *eeop = enp->en_eeop; 119 120 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 121 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_PROBE); 122 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_RX)); 123 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_TX)); 124 125 if (eeop && eeop->eeo_fini) 126 eeop->eeo_fini(enp); 127 128 enp->en_eeop = NULL; 129 enp->en_mod_flags &= ~EFX_MOD_EVB; 130 } 131 132 /* 133 * efx_is_zero_eth_addr returns TRUE if the passed MAC address has all bytes 134 * equal to zero. A vport is assigned a MAC address after creation and this 135 * function checks if that has happened. It is called in the clean-up function 136 * before calling eeo_vport_mac_addr_del to ensure that the vport actually had 137 * an allocated MAC address. 138 */ 139 140 __checkReturn boolean_t 141 efx_is_zero_eth_addr( 142 __in_bcount(EFX_MAC_ADDR_LEN) const uint8_t *addrp) 143 { 144 return (!(addrp[0] | addrp[1] | addrp[2] | 145 addrp[3] | addrp[4] | addrp[5])); 146 } 147 148 static void 149 efx_evb_free_vport( 150 __in efx_nic_t *enp, 151 __in efx_vswitch_id_t vswitch_id, 152 __inout efx_vport_config_t *configp) 153 { 154 const efx_evb_ops_t *eeop = enp->en_eeop; 155 156 /* If any callback fails, continue clean-up with others functions */ 157 if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) { 158 /* free vadaptor */ 159 if ((configp->evc_vport_id != EFX_VPORT_ID_INVALID) && 160 (eeop->eeo_vadaptor_free(enp, vswitch_id, 161 configp->evc_vport_id) != 0)) { 162 EFSYS_PROBE2(eeo_vadaptor_free, 163 uint16_t, configp->evc_function, 164 uint32_t, configp->evc_vport_id); 165 } 166 } else { 167 if (configp->evc_vport_assigned == B_TRUE) { 168 if (eeop->eeo_vport_assign(enp, vswitch_id, 169 EVB_PORT_ID_NULL, 170 configp->evc_function) != 0) { 171 EFSYS_PROBE1(eeo_vport_assign, 172 uint16_t, configp->evc_function); 173 } 174 configp->evc_vport_assigned = B_FALSE; 175 } 176 } 177 178 /* 179 * Call eeo_vport_mac_addr_del after checking that this vport is 180 * actually allocated a MAC address in call to efx_evb_configure_vport 181 */ 182 if (!efx_is_zero_eth_addr(configp->evc_mac_addr)) { 183 if (eeop->eeo_vport_mac_addr_del(enp, vswitch_id, 184 configp->evc_vport_id, 185 configp->evc_mac_addr) != 0) { 186 EFSYS_PROBE1(eeo_vport_mac_addr_del, 187 uint16_t, configp->evc_function); 188 } 189 memset(configp->evc_mac_addr, 0x00, EFX_MAC_ADDR_LEN); 190 } 191 192 if (configp->evc_vport_id != EFX_VPORT_ID_INVALID) { 193 if (eeop->eeo_vport_free(enp, vswitch_id, 194 configp->evc_vport_id) != 0) { 195 EFSYS_PROBE1(eeo_vport_free, 196 uint16_t, configp->evc_function); 197 } 198 configp->evc_vport_id = EFX_VPORT_ID_INVALID; 199 } 200 } 201 202 static void 203 efx_evb_free_vports( 204 __in efx_nic_t *enp, 205 __in efx_vswitch_id_t vswitch_id, 206 __in uint32_t num_vports, 207 __inout_ecount(num_vports) efx_vport_config_t *vport_configp) 208 { 209 efx_vport_config_t *configp; 210 uint32_t i; 211 212 if (vport_configp == NULL) { 213 EFSYS_PROBE(null_vport_config); 214 return; 215 } 216 217 for (i = 0; i < num_vports; i++) { 218 configp = vport_configp + i; 219 efx_evb_free_vport(enp, vswitch_id, configp); 220 } 221 } 222 223 static __checkReturn efx_rc_t 224 efx_evb_configure_vport( 225 __in efx_nic_t *enp, 226 __in efx_vswitch_id_t vswitch_id, 227 __in const efx_evb_ops_t *eeop, 228 __inout efx_vport_config_t *configp) 229 { 230 efx_rc_t rc; 231 efx_vport_id_t vport_id; 232 233 if ((rc = eeop->eeo_vport_alloc(enp, vswitch_id, 234 EFX_VPORT_TYPE_NORMAL, configp->evc_vid, 235 configp->evc_vlan_restrict, &vport_id)) != 0) 236 goto fail1; 237 238 configp->evc_vport_id = vport_id; 239 240 if ((rc = eeop->eeo_vport_mac_addr_add(enp, vswitch_id, 241 configp->evc_vport_id, 242 configp->evc_mac_addr)) != 0) 243 goto fail2; 244 245 if (EFX_VPORT_PCI_FUNCTION_IS_PF(configp)) { 246 if ((rc = eeop->eeo_vadaptor_alloc(enp, vswitch_id, 247 configp->evc_vport_id)) != 0) 248 goto fail3; 249 } else { 250 if ((rc = eeop->eeo_vport_assign(enp, vswitch_id, 251 configp->evc_vport_id, 252 configp->evc_function)) != 0) 253 goto fail4; 254 configp->evc_vport_assigned = B_TRUE; 255 } 256 257 return (0); 258 259 fail4: 260 EFSYS_PROBE(fail4); 261 fail3: 262 EFSYS_PROBE(fail3); 263 fail2: 264 EFSYS_PROBE(fail2); 265 fail1: 266 EFSYS_PROBE1(fail1, efx_rc_t, rc); 267 268 return (rc); 269 } 270 271 __checkReturn efx_rc_t 272 efx_evb_vswitch_create( 273 __in efx_nic_t *enp, 274 __in uint32_t num_vports, 275 __inout_ecount(num_vports) efx_vport_config_t *vport_configp, 276 __deref_out efx_vswitch_t **evpp) 277 { 278 efx_vswitch_t *evp; 279 efx_rc_t rc; 280 efx_vswitch_id_t vswitch_id; 281 efx_vport_config_t *configp; 282 const efx_evb_ops_t *eeop = enp->en_eeop; 283 uint32_t i; 284 285 /* vport_configp is a caller allocated array filled in with vports 286 * configuration. Index 0 carries the PF vport configuration and next 287 * num_vports - 1 indices carry VFs configuration. 288 */ 289 EFSYS_ASSERT((num_vports != 0) && (vport_configp != NULL) && 290 (evpp != NULL)); 291 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); 292 EFSYS_ASSERT(!(enp->en_mod_flags & EFX_MOD_NIC)); 293 294 if ((eeop->eeo_vswitch_alloc == NULL) || 295 (eeop->eeo_vport_alloc == NULL) || 296 (eeop->eeo_vport_free == NULL) || 297 (eeop->eeo_vport_mac_addr_add == NULL) || 298 (eeop->eeo_vport_mac_addr_del == NULL) || 299 (eeop->eeo_vadaptor_alloc == NULL) || 300 (eeop->eeo_vadaptor_free == NULL) || 301 (eeop->eeo_vport_assign == NULL) || 302 (eeop->eeo_vswitch_free == NULL)) { 303 rc = ENOTSUP; 304 goto fail1; 305 } 306 307 /* Allocate a vSwitch object */ 308 EFSYS_KMEM_ALLOC(enp->en_esip, sizeof (efx_vswitch_t), evp); 309 310 if (evp == NULL) { 311 rc = ENOMEM; 312 goto fail2; 313 } 314 315 if ((rc = eeop->eeo_vswitch_alloc(enp, &vswitch_id)) != 0) 316 goto fail3; 317 318 evp->ev_enp = enp; 319 evp->ev_num_vports = num_vports; 320 evp->ev_evcp = vport_configp; 321 evp->ev_vswitch_id = vswitch_id; 322 323 for (i = 0; i < num_vports; i++) { 324 configp = vport_configp + i; 325 326 if ((rc = efx_evb_configure_vport(enp, vswitch_id, eeop, 327 configp)) != 0) 328 goto fail4; 329 } 330 331 enp->en_vswitchp = evp; 332 *evpp = evp; 333 return (0); 334 335 fail4: 336 EFSYS_PROBE(fail4); 337 efx_evb_free_vports(enp, vswitch_id, i + 1, vport_configp); 338 /* Free the vSwitch */ 339 eeop->eeo_vswitch_free(enp, vswitch_id); 340 341 fail3: 342 EFSYS_PROBE(fail3); 343 /* Free the vSwitch object */ 344 EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp); 345 346 fail2: 347 EFSYS_PROBE(fail2); 348 349 fail1: 350 EFSYS_PROBE1(fail1, efx_rc_t, rc); 351 352 return (rc); 353 } 354 355 __checkReturn efx_rc_t 356 efx_evb_vport_mac_set( 357 __in efx_nic_t *enp, 358 __in efx_vswitch_t *evp, 359 __in efx_vport_id_t vport_id, 360 __in_bcount(EFX_MAC_ADDR_LEN) uint8_t *addrp) 361 { 362 const efx_evb_ops_t *eeop = enp->en_eeop; 363 efx_rc_t rc; 364 365 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); 366 367 if (eeop->eeo_vport_reconfigure == NULL) { 368 rc = ENOTSUP; 369 goto fail1; 370 } 371 372 if (addrp == NULL) { 373 rc = EINVAL; 374 goto fail2; 375 } 376 377 rc = eeop->eeo_vport_reconfigure(enp, evp->ev_vswitch_id, vport_id, 378 NULL, addrp, NULL); 379 if (rc != 0) 380 goto fail3; 381 382 return (0); 383 384 fail3: 385 EFSYS_PROBE(fail3); 386 fail2: 387 EFSYS_PROBE(fail2); 388 fail1: 389 EFSYS_PROBE1(fail1, efx_rc_t, rc); 390 return (rc); 391 } 392 393 __checkReturn efx_rc_t 394 efx_evb_vport_vlan_set( 395 __in efx_nic_t *enp, 396 __in efx_vswitch_t *evp, 397 __in efx_vport_id_t vport_id, 398 __in uint16_t vid) 399 { 400 const efx_evb_ops_t *eeop = enp->en_eeop; 401 efx_rc_t rc; 402 403 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); 404 405 if (eeop->eeo_vport_reconfigure == NULL) { 406 rc = ENOTSUP; 407 goto fail1; 408 } 409 410 rc = eeop->eeo_vport_reconfigure(enp, evp->ev_vswitch_id, vport_id, 411 &vid, NULL, NULL); 412 if (rc != 0) 413 goto fail2; 414 415 return (0); 416 417 fail2: 418 EFSYS_PROBE(fail2); 419 fail1: 420 EFSYS_PROBE1(fail1, efx_rc_t, rc); 421 return (rc); 422 } 423 424 __checkReturn efx_rc_t 425 efx_evb_vport_reset( 426 __in efx_nic_t *enp, 427 __in efx_vswitch_t *evp, 428 __in efx_vport_id_t vport_id, 429 __in_bcount(EFX_MAC_ADDR_LEN) uint8_t *addrp, 430 __in uint16_t vid, 431 __out boolean_t *is_fn_resetp) 432 { 433 const efx_evb_ops_t *eeop = enp->en_eeop; 434 efx_rc_t rc; 435 436 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); 437 438 if (eeop->eeo_vport_reconfigure == NULL) { 439 rc = ENOTSUP; 440 goto fail1; 441 } 442 443 if (is_fn_resetp == NULL) { 444 rc = EINVAL; 445 goto fail2; 446 } 447 448 rc = eeop->eeo_vport_reconfigure(enp, evp->ev_vswitch_id, vport_id, 449 &vid, addrp, is_fn_resetp); 450 if (rc != 0) 451 goto fail3; 452 453 return (0); 454 455 fail3: 456 EFSYS_PROBE(fail3); 457 fail2: 458 EFSYS_PROBE(fail2); 459 fail1: 460 EFSYS_PROBE1(fail1, efx_rc_t, rc); 461 return (rc); 462 } 463 __checkReturn efx_rc_t 464 efx_evb_vswitch_destroy( 465 __in efx_nic_t *enp, 466 __in efx_vswitch_t *evp) 467 { 468 const efx_evb_ops_t *eeop = enp->en_eeop; 469 efx_vswitch_id_t vswitch_id; 470 efx_rc_t rc; 471 472 EFSYS_ASSERT(evp != NULL); 473 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); 474 475 if ((eeop->eeo_vport_mac_addr_del == NULL) || 476 (eeop->eeo_vadaptor_free == NULL) || 477 (eeop->eeo_vport_assign == NULL) || 478 (eeop->eeo_vport_free == NULL) || 479 (eeop->eeo_vswitch_free == NULL)) { 480 rc = ENOTSUP; 481 goto fail1; 482 } 483 484 vswitch_id = evp->ev_vswitch_id; 485 efx_evb_free_vports(enp, vswitch_id, 486 evp->ev_num_vports, evp->ev_evcp); 487 488 /* Free the vSwitch object */ 489 EFSYS_KMEM_FREE(enp->en_esip, sizeof (efx_vswitch_t), evp); 490 enp->en_vswitchp = NULL; 491 492 /* Free the vSwitch */ 493 if ((rc = eeop->eeo_vswitch_free(enp, vswitch_id)) != 0) 494 goto fail2; 495 496 return (0); 497 498 fail2: 499 EFSYS_PROBE(fail2); 500 501 fail1: 502 EFSYS_PROBE1(fail1, efx_rc_t, rc); 503 return (rc); 504 } 505 506 __checkReturn efx_rc_t 507 efx_evb_vport_stats( 508 __in efx_nic_t *enp, 509 __in efx_vswitch_t *evp, 510 __in efx_vport_id_t vport_id, 511 __out efsys_mem_t *stats_bufferp) 512 { 513 efx_rc_t rc; 514 const efx_evb_ops_t *eeop = enp->en_eeop; 515 516 EFSYS_ASSERT(enp->en_mod_flags & EFX_MOD_EVB); 517 518 if (eeop->eeo_vport_stats == NULL) { 519 rc = ENOTSUP; 520 goto fail1; 521 } 522 523 if (stats_bufferp == NULL) { 524 rc = EINVAL; 525 goto fail2; 526 } 527 528 rc = eeop->eeo_vport_stats(enp, evp->ev_vswitch_id, 529 vport_id, stats_bufferp); 530 if (rc != 0) 531 goto fail3; 532 533 return (0); 534 535 fail3: 536 EFSYS_PROBE(fail3); 537 fail2: 538 EFSYS_PROBE(fail2); 539 fail1: 540 EFSYS_PROBE1(fail1, efx_rc_t, rc); 541 return (rc); 542 } 543 544 #endif 545