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