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