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