1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2007-2016 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_SIENA 40 static const efx_phy_ops_t __efx_phy_siena_ops = { 41 siena_phy_power, /* epo_power */ 42 NULL, /* epo_reset */ 43 siena_phy_reconfigure, /* epo_reconfigure */ 44 siena_phy_verify, /* epo_verify */ 45 siena_phy_oui_get, /* epo_oui_get */ 46 NULL, /* epo_link_state_get */ 47 #if EFSYS_OPT_PHY_STATS 48 siena_phy_stats_update, /* epo_stats_update */ 49 #endif /* EFSYS_OPT_PHY_STATS */ 50 #if EFSYS_OPT_BIST 51 NULL, /* epo_bist_enable_offline */ 52 siena_phy_bist_start, /* epo_bist_start */ 53 siena_phy_bist_poll, /* epo_bist_poll */ 54 siena_phy_bist_stop, /* epo_bist_stop */ 55 #endif /* EFSYS_OPT_BIST */ 56 }; 57 #endif /* EFSYS_OPT_SIENA */ 58 59 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 60 static const efx_phy_ops_t __efx_phy_ef10_ops = { 61 ef10_phy_power, /* epo_power */ 62 NULL, /* epo_reset */ 63 ef10_phy_reconfigure, /* epo_reconfigure */ 64 ef10_phy_verify, /* epo_verify */ 65 ef10_phy_oui_get, /* epo_oui_get */ 66 ef10_phy_link_state_get, /* epo_link_state_get */ 67 #if EFSYS_OPT_PHY_STATS 68 ef10_phy_stats_update, /* epo_stats_update */ 69 #endif /* EFSYS_OPT_PHY_STATS */ 70 #if EFSYS_OPT_BIST 71 ef10_bist_enable_offline, /* epo_bist_enable_offline */ 72 ef10_bist_start, /* epo_bist_start */ 73 ef10_bist_poll, /* epo_bist_poll */ 74 ef10_bist_stop, /* epo_bist_stop */ 75 #endif /* EFSYS_OPT_BIST */ 76 }; 77 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD || EFSYS_OPT_MEDFORD2 */ 78 79 __checkReturn efx_rc_t 80 efx_phy_probe( 81 __in efx_nic_t *enp) 82 { 83 efx_port_t *epp = &(enp->en_port); 84 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 85 const efx_phy_ops_t *epop; 86 efx_rc_t rc; 87 88 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 89 90 epp->ep_port = encp->enc_port; 91 epp->ep_phy_type = encp->enc_phy_type; 92 93 /* Hook in operations structure */ 94 switch (enp->en_family) { 95 #if EFSYS_OPT_SIENA 96 case EFX_FAMILY_SIENA: 97 epop = &__efx_phy_siena_ops; 98 break; 99 #endif /* EFSYS_OPT_SIENA */ 100 101 #if EFSYS_OPT_HUNTINGTON 102 case EFX_FAMILY_HUNTINGTON: 103 epop = &__efx_phy_ef10_ops; 104 break; 105 #endif /* EFSYS_OPT_HUNTINGTON */ 106 107 #if EFSYS_OPT_MEDFORD 108 case EFX_FAMILY_MEDFORD: 109 epop = &__efx_phy_ef10_ops; 110 break; 111 #endif /* EFSYS_OPT_MEDFORD */ 112 113 #if EFSYS_OPT_MEDFORD2 114 case EFX_FAMILY_MEDFORD2: 115 epop = &__efx_phy_ef10_ops; 116 break; 117 #endif /* EFSYS_OPT_MEDFORD2 */ 118 119 default: 120 rc = ENOTSUP; 121 goto fail1; 122 } 123 124 epp->ep_epop = epop; 125 126 return (0); 127 128 fail1: 129 EFSYS_PROBE1(fail1, efx_rc_t, rc); 130 131 epp->ep_port = 0; 132 epp->ep_phy_type = 0; 133 134 return (rc); 135 } 136 137 __checkReturn efx_rc_t 138 efx_phy_verify( 139 __in efx_nic_t *enp) 140 { 141 efx_port_t *epp = &(enp->en_port); 142 const efx_phy_ops_t *epop = epp->ep_epop; 143 144 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 145 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 146 147 return (epop->epo_verify(enp)); 148 } 149 150 #if EFSYS_OPT_PHY_LED_CONTROL 151 152 __checkReturn efx_rc_t 153 efx_phy_led_set( 154 __in efx_nic_t *enp, 155 __in efx_phy_led_mode_t mode) 156 { 157 efx_nic_cfg_t *encp = (&enp->en_nic_cfg); 158 efx_port_t *epp = &(enp->en_port); 159 const efx_phy_ops_t *epop = epp->ep_epop; 160 uint32_t mask; 161 efx_rc_t rc; 162 163 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 164 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 165 166 if (epp->ep_phy_led_mode == mode) 167 goto done; 168 169 mask = (1 << EFX_PHY_LED_DEFAULT); 170 mask |= encp->enc_led_mask; 171 172 if (!((1 << mode) & mask)) { 173 rc = ENOTSUP; 174 goto fail1; 175 } 176 177 EFSYS_ASSERT3U(mode, <, EFX_PHY_LED_NMODES); 178 epp->ep_phy_led_mode = mode; 179 180 if ((rc = epop->epo_reconfigure(enp)) != 0) 181 goto fail2; 182 183 done: 184 return (0); 185 186 fail2: 187 EFSYS_PROBE(fail2); 188 fail1: 189 EFSYS_PROBE1(fail1, efx_rc_t, rc); 190 191 return (rc); 192 } 193 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 194 195 void 196 efx_phy_adv_cap_get( 197 __in efx_nic_t *enp, 198 __in uint32_t flag, 199 __out uint32_t *maskp) 200 { 201 efx_port_t *epp = &(enp->en_port); 202 203 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 204 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 205 206 switch (flag) { 207 case EFX_PHY_CAP_CURRENT: 208 *maskp = epp->ep_adv_cap_mask; 209 break; 210 case EFX_PHY_CAP_DEFAULT: 211 *maskp = epp->ep_default_adv_cap_mask; 212 break; 213 case EFX_PHY_CAP_PERM: 214 *maskp = epp->ep_phy_cap_mask; 215 break; 216 default: 217 EFSYS_ASSERT(B_FALSE); 218 *maskp = 0; 219 break; 220 } 221 } 222 223 __checkReturn efx_rc_t 224 efx_phy_adv_cap_set( 225 __in efx_nic_t *enp, 226 __in uint32_t mask) 227 { 228 efx_port_t *epp = &(enp->en_port); 229 const efx_phy_ops_t *epop = epp->ep_epop; 230 uint32_t old_mask; 231 efx_rc_t rc; 232 233 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 234 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 235 236 if ((mask & ~epp->ep_phy_cap_mask) != 0) { 237 rc = ENOTSUP; 238 goto fail1; 239 } 240 241 if (epp->ep_adv_cap_mask == mask) 242 goto done; 243 244 old_mask = epp->ep_adv_cap_mask; 245 epp->ep_adv_cap_mask = mask; 246 247 if ((rc = epop->epo_reconfigure(enp)) != 0) 248 goto fail2; 249 250 done: 251 return (0); 252 253 fail2: 254 EFSYS_PROBE(fail2); 255 256 epp->ep_adv_cap_mask = old_mask; 257 /* Reconfigure for robustness */ 258 if (epop->epo_reconfigure(enp) != 0) { 259 /* 260 * We may have an inconsistent view of our advertised speed 261 * capabilities. 262 */ 263 EFSYS_ASSERT(0); 264 } 265 266 fail1: 267 EFSYS_PROBE1(fail1, efx_rc_t, rc); 268 269 return (rc); 270 } 271 272 void 273 efx_phy_lp_cap_get( 274 __in efx_nic_t *enp, 275 __out uint32_t *maskp) 276 { 277 efx_port_t *epp = &(enp->en_port); 278 279 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 280 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 281 282 *maskp = epp->ep_lp_cap_mask; 283 } 284 285 __checkReturn efx_rc_t 286 efx_phy_oui_get( 287 __in efx_nic_t *enp, 288 __out uint32_t *ouip) 289 { 290 efx_port_t *epp = &(enp->en_port); 291 const efx_phy_ops_t *epop = epp->ep_epop; 292 293 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 294 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 295 296 return (epop->epo_oui_get(enp, ouip)); 297 } 298 299 void 300 efx_phy_media_type_get( 301 __in efx_nic_t *enp, 302 __out efx_phy_media_type_t *typep) 303 { 304 efx_port_t *epp = &(enp->en_port); 305 306 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 307 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 308 309 if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID) 310 *typep = epp->ep_module_type; 311 else 312 *typep = epp->ep_fixed_port_type; 313 } 314 315 __checkReturn efx_rc_t 316 efx_phy_module_get_info( 317 __in efx_nic_t *enp, 318 __in uint8_t dev_addr, 319 __in size_t offset, 320 __in size_t len, 321 __out_bcount(len) uint8_t *data) 322 { 323 efx_rc_t rc; 324 325 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 326 EFSYS_ASSERT(data != NULL); 327 328 if ((offset > EFX_PHY_MEDIA_INFO_MAX_OFFSET) || 329 ((offset + len) > EFX_PHY_MEDIA_INFO_MAX_OFFSET)) { 330 rc = EINVAL; 331 goto fail1; 332 } 333 334 if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr, 335 offset, len, data)) != 0) 336 goto fail2; 337 338 return (0); 339 340 fail2: 341 EFSYS_PROBE(fail2); 342 fail1: 343 EFSYS_PROBE1(fail1, efx_rc_t, rc); 344 345 return (rc); 346 } 347 348 __checkReturn efx_rc_t 349 efx_phy_fec_type_get( 350 __in efx_nic_t *enp, 351 __out efx_phy_fec_type_t *typep) 352 { 353 efx_rc_t rc; 354 efx_phy_link_state_t epls; 355 356 if ((rc = efx_phy_link_state_get(enp, &epls)) != 0) 357 goto fail1; 358 359 *typep = epls.epls_fec; 360 361 return (0); 362 363 fail1: 364 EFSYS_PROBE1(fail1, efx_rc_t, rc); 365 366 return (rc); 367 } 368 369 __checkReturn efx_rc_t 370 efx_phy_link_state_get( 371 __in efx_nic_t *enp, 372 __out efx_phy_link_state_t *eplsp) 373 { 374 efx_port_t *epp = &(enp->en_port); 375 const efx_phy_ops_t *epop = epp->ep_epop; 376 efx_rc_t rc; 377 378 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 379 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 380 381 if (epop->epo_link_state_get == NULL) { 382 rc = ENOTSUP; 383 goto fail1; 384 } 385 386 if ((rc = epop->epo_link_state_get(enp, eplsp)) != 0) 387 goto fail2; 388 389 return (0); 390 391 fail2: 392 EFSYS_PROBE(fail2); 393 fail1: 394 EFSYS_PROBE1(fail1, efx_rc_t, rc); 395 396 return (rc); 397 } 398 399 #if EFSYS_OPT_PHY_STATS 400 401 #if EFSYS_OPT_NAMES 402 403 /* START MKCONFIG GENERATED PhyStatNamesBlock af9ffa24da3bc100 */ 404 static const char * const __efx_phy_stat_name[] = { 405 "oui", 406 "pma_pmd_link_up", 407 "pma_pmd_rx_fault", 408 "pma_pmd_tx_fault", 409 "pma_pmd_rev_a", 410 "pma_pmd_rev_b", 411 "pma_pmd_rev_c", 412 "pma_pmd_rev_d", 413 "pcs_link_up", 414 "pcs_rx_fault", 415 "pcs_tx_fault", 416 "pcs_ber", 417 "pcs_block_errors", 418 "phy_xs_link_up", 419 "phy_xs_rx_fault", 420 "phy_xs_tx_fault", 421 "phy_xs_align", 422 "phy_xs_sync_a", 423 "phy_xs_sync_b", 424 "phy_xs_sync_c", 425 "phy_xs_sync_d", 426 "an_link_up", 427 "an_master", 428 "an_local_rx_ok", 429 "an_remote_rx_ok", 430 "cl22ext_link_up", 431 "snr_a", 432 "snr_b", 433 "snr_c", 434 "snr_d", 435 "pma_pmd_signal_a", 436 "pma_pmd_signal_b", 437 "pma_pmd_signal_c", 438 "pma_pmd_signal_d", 439 "an_complete", 440 "pma_pmd_rev_major", 441 "pma_pmd_rev_minor", 442 "pma_pmd_rev_micro", 443 "pcs_fw_version_0", 444 "pcs_fw_version_1", 445 "pcs_fw_version_2", 446 "pcs_fw_version_3", 447 "pcs_fw_build_yy", 448 "pcs_fw_build_mm", 449 "pcs_fw_build_dd", 450 "pcs_op_mode", 451 }; 452 453 /* END MKCONFIG GENERATED PhyStatNamesBlock */ 454 455 const char * 456 efx_phy_stat_name( 457 __in efx_nic_t *enp, 458 __in efx_phy_stat_t type) 459 { 460 _NOTE(ARGUNUSED(enp)) 461 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 462 EFSYS_ASSERT3U(type, <, EFX_PHY_NSTATS); 463 464 return (__efx_phy_stat_name[type]); 465 } 466 467 #endif /* EFSYS_OPT_NAMES */ 468 469 __checkReturn efx_rc_t 470 efx_phy_stats_update( 471 __in efx_nic_t *enp, 472 __in efsys_mem_t *esmp, 473 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) 474 { 475 efx_port_t *epp = &(enp->en_port); 476 const efx_phy_ops_t *epop = epp->ep_epop; 477 478 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 479 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 480 481 return (epop->epo_stats_update(enp, esmp, stat)); 482 } 483 484 #endif /* EFSYS_OPT_PHY_STATS */ 485 486 #if EFSYS_OPT_BIST 487 488 __checkReturn efx_rc_t 489 efx_bist_enable_offline( 490 __in efx_nic_t *enp) 491 { 492 efx_port_t *epp = &(enp->en_port); 493 const efx_phy_ops_t *epop = epp->ep_epop; 494 efx_rc_t rc; 495 496 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 497 498 if (epop->epo_bist_enable_offline == NULL) { 499 rc = ENOTSUP; 500 goto fail1; 501 } 502 503 if ((rc = epop->epo_bist_enable_offline(enp)) != 0) 504 goto fail2; 505 506 return (0); 507 508 fail2: 509 EFSYS_PROBE(fail2); 510 fail1: 511 EFSYS_PROBE1(fail1, efx_rc_t, rc); 512 513 return (rc); 514 515 } 516 517 __checkReturn efx_rc_t 518 efx_bist_start( 519 __in efx_nic_t *enp, 520 __in efx_bist_type_t type) 521 { 522 efx_port_t *epp = &(enp->en_port); 523 const efx_phy_ops_t *epop = epp->ep_epop; 524 efx_rc_t rc; 525 526 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 527 528 EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); 529 EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); 530 EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN); 531 532 if (epop->epo_bist_start == NULL) { 533 rc = ENOTSUP; 534 goto fail1; 535 } 536 537 if ((rc = epop->epo_bist_start(enp, type)) != 0) 538 goto fail2; 539 540 epp->ep_current_bist = type; 541 542 return (0); 543 544 fail2: 545 EFSYS_PROBE(fail2); 546 fail1: 547 EFSYS_PROBE1(fail1, efx_rc_t, rc); 548 549 return (rc); 550 } 551 552 __checkReturn efx_rc_t 553 efx_bist_poll( 554 __in efx_nic_t *enp, 555 __in efx_bist_type_t type, 556 __out efx_bist_result_t *resultp, 557 __out_opt uint32_t *value_maskp, 558 __out_ecount_opt(count) unsigned long *valuesp, 559 __in size_t count) 560 { 561 efx_port_t *epp = &(enp->en_port); 562 const efx_phy_ops_t *epop = epp->ep_epop; 563 efx_rc_t rc; 564 565 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 566 567 EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); 568 EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); 569 EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); 570 571 EFSYS_ASSERT(epop->epo_bist_poll != NULL); 572 if (epop->epo_bist_poll == NULL) { 573 rc = ENOTSUP; 574 goto fail1; 575 } 576 577 if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp, 578 valuesp, count)) != 0) 579 goto fail2; 580 581 return (0); 582 583 fail2: 584 EFSYS_PROBE(fail2); 585 fail1: 586 EFSYS_PROBE1(fail1, efx_rc_t, rc); 587 588 return (rc); 589 } 590 591 void 592 efx_bist_stop( 593 __in efx_nic_t *enp, 594 __in efx_bist_type_t type) 595 { 596 efx_port_t *epp = &(enp->en_port); 597 const efx_phy_ops_t *epop = epp->ep_epop; 598 599 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 600 601 EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); 602 EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); 603 EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); 604 605 EFSYS_ASSERT(epop->epo_bist_stop != NULL); 606 607 if (epop->epo_bist_stop != NULL) 608 epop->epo_bist_stop(enp, type); 609 610 epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN; 611 } 612 613 #endif /* EFSYS_OPT_BIST */ 614 void 615 efx_phy_unprobe( 616 __in efx_nic_t *enp) 617 { 618 efx_port_t *epp = &(enp->en_port); 619 620 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 621 622 epp->ep_epop = NULL; 623 624 epp->ep_adv_cap_mask = 0; 625 626 epp->ep_port = 0; 627 epp->ep_phy_type = 0; 628 } 629