1 /*- 2 * Copyright (c) 2007-2016 Solarflare Communications Inc. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 21 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 22 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 23 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 24 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * The views and conclusions contained in the software and documentation are 27 * those of the authors and should not be interpreted as representing official 28 * policies, either expressed or implied, of the FreeBSD Project. 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 #include "efx.h" 35 #include "efx_impl.h" 36 37 38 #if EFSYS_OPT_SIENA 39 static const efx_phy_ops_t __efx_phy_siena_ops = { 40 siena_phy_power, /* epo_power */ 41 NULL, /* epo_reset */ 42 siena_phy_reconfigure, /* epo_reconfigure */ 43 siena_phy_verify, /* epo_verify */ 44 siena_phy_oui_get, /* epo_oui_get */ 45 #if EFSYS_OPT_PHY_STATS 46 siena_phy_stats_update, /* epo_stats_update */ 47 #endif /* EFSYS_OPT_PHY_STATS */ 48 #if EFSYS_OPT_BIST 49 NULL, /* epo_bist_enable_offline */ 50 siena_phy_bist_start, /* epo_bist_start */ 51 siena_phy_bist_poll, /* epo_bist_poll */ 52 siena_phy_bist_stop, /* epo_bist_stop */ 53 #endif /* EFSYS_OPT_BIST */ 54 }; 55 #endif /* EFSYS_OPT_SIENA */ 56 57 #if EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD 58 static const efx_phy_ops_t __efx_phy_ef10_ops = { 59 ef10_phy_power, /* epo_power */ 60 NULL, /* epo_reset */ 61 ef10_phy_reconfigure, /* epo_reconfigure */ 62 ef10_phy_verify, /* epo_verify */ 63 ef10_phy_oui_get, /* epo_oui_get */ 64 #if EFSYS_OPT_PHY_STATS 65 ef10_phy_stats_update, /* epo_stats_update */ 66 #endif /* EFSYS_OPT_PHY_STATS */ 67 #if EFSYS_OPT_BIST 68 ef10_bist_enable_offline, /* epo_bist_enable_offline */ 69 ef10_bist_start, /* epo_bist_start */ 70 ef10_bist_poll, /* epo_bist_poll */ 71 ef10_bist_stop, /* epo_bist_stop */ 72 #endif /* EFSYS_OPT_BIST */ 73 }; 74 #endif /* EFSYS_OPT_HUNTINGTON || EFSYS_OPT_MEDFORD */ 75 76 __checkReturn efx_rc_t 77 efx_phy_probe( 78 __in efx_nic_t *enp) 79 { 80 efx_port_t *epp = &(enp->en_port); 81 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 82 const efx_phy_ops_t *epop; 83 efx_rc_t rc; 84 85 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 86 87 epp->ep_port = encp->enc_port; 88 epp->ep_phy_type = encp->enc_phy_type; 89 90 /* Hook in operations structure */ 91 switch (enp->en_family) { 92 #if EFSYS_OPT_SIENA 93 case EFX_FAMILY_SIENA: 94 epop = &__efx_phy_siena_ops; 95 break; 96 #endif /* EFSYS_OPT_SIENA */ 97 #if EFSYS_OPT_HUNTINGTON 98 case EFX_FAMILY_HUNTINGTON: 99 epop = &__efx_phy_ef10_ops; 100 break; 101 #endif /* EFSYS_OPT_HUNTINGTON */ 102 #if EFSYS_OPT_MEDFORD 103 case EFX_FAMILY_MEDFORD: 104 epop = &__efx_phy_ef10_ops; 105 break; 106 #endif /* EFSYS_OPT_MEDFORD */ 107 default: 108 rc = ENOTSUP; 109 goto fail1; 110 } 111 112 epp->ep_epop = epop; 113 114 return (0); 115 116 fail1: 117 EFSYS_PROBE1(fail1, efx_rc_t, rc); 118 119 epp->ep_port = 0; 120 epp->ep_phy_type = 0; 121 122 return (rc); 123 } 124 125 __checkReturn efx_rc_t 126 efx_phy_verify( 127 __in efx_nic_t *enp) 128 { 129 efx_port_t *epp = &(enp->en_port); 130 const efx_phy_ops_t *epop = epp->ep_epop; 131 132 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 133 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 134 135 return (epop->epo_verify(enp)); 136 } 137 138 #if EFSYS_OPT_PHY_LED_CONTROL 139 140 __checkReturn efx_rc_t 141 efx_phy_led_set( 142 __in efx_nic_t *enp, 143 __in efx_phy_led_mode_t mode) 144 { 145 efx_nic_cfg_t *encp = (&enp->en_nic_cfg); 146 efx_port_t *epp = &(enp->en_port); 147 const efx_phy_ops_t *epop = epp->ep_epop; 148 uint32_t mask; 149 efx_rc_t rc; 150 151 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 152 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 153 154 if (epp->ep_phy_led_mode == mode) 155 goto done; 156 157 mask = (1 << EFX_PHY_LED_DEFAULT); 158 mask |= encp->enc_led_mask; 159 160 if (!((1 << mode) & mask)) { 161 rc = ENOTSUP; 162 goto fail1; 163 } 164 165 EFSYS_ASSERT3U(mode, <, EFX_PHY_LED_NMODES); 166 epp->ep_phy_led_mode = mode; 167 168 if ((rc = epop->epo_reconfigure(enp)) != 0) 169 goto fail2; 170 171 done: 172 return (0); 173 174 fail2: 175 EFSYS_PROBE(fail2); 176 fail1: 177 EFSYS_PROBE1(fail1, efx_rc_t, rc); 178 179 return (rc); 180 } 181 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 182 183 void 184 efx_phy_adv_cap_get( 185 __in efx_nic_t *enp, 186 __in uint32_t flag, 187 __out uint32_t *maskp) 188 { 189 efx_port_t *epp = &(enp->en_port); 190 191 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 192 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PROBE); 193 194 switch (flag) { 195 case EFX_PHY_CAP_CURRENT: 196 *maskp = epp->ep_adv_cap_mask; 197 break; 198 case EFX_PHY_CAP_DEFAULT: 199 *maskp = epp->ep_default_adv_cap_mask; 200 break; 201 case EFX_PHY_CAP_PERM: 202 *maskp = epp->ep_phy_cap_mask; 203 break; 204 default: 205 EFSYS_ASSERT(B_FALSE); 206 break; 207 } 208 } 209 210 __checkReturn efx_rc_t 211 efx_phy_adv_cap_set( 212 __in efx_nic_t *enp, 213 __in uint32_t mask) 214 { 215 efx_port_t *epp = &(enp->en_port); 216 const efx_phy_ops_t *epop = epp->ep_epop; 217 uint32_t old_mask; 218 efx_rc_t rc; 219 220 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 221 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 222 223 if ((mask & ~epp->ep_phy_cap_mask) != 0) { 224 rc = ENOTSUP; 225 goto fail1; 226 } 227 228 if (epp->ep_adv_cap_mask == mask) 229 goto done; 230 231 old_mask = epp->ep_adv_cap_mask; 232 epp->ep_adv_cap_mask = mask; 233 234 if ((rc = epop->epo_reconfigure(enp)) != 0) 235 goto fail2; 236 237 done: 238 return (0); 239 240 fail2: 241 EFSYS_PROBE(fail2); 242 243 epp->ep_adv_cap_mask = old_mask; 244 /* Reconfigure for robustness */ 245 if (epop->epo_reconfigure(enp) != 0) { 246 /* 247 * We may have an inconsistent view of our advertised speed 248 * capabilities. 249 */ 250 EFSYS_ASSERT(0); 251 } 252 253 fail1: 254 EFSYS_PROBE1(fail1, efx_rc_t, rc); 255 256 return (rc); 257 } 258 259 void 260 efx_phy_lp_cap_get( 261 __in efx_nic_t *enp, 262 __out uint32_t *maskp) 263 { 264 efx_port_t *epp = &(enp->en_port); 265 266 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 267 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 268 269 *maskp = epp->ep_lp_cap_mask; 270 } 271 272 __checkReturn efx_rc_t 273 efx_phy_oui_get( 274 __in efx_nic_t *enp, 275 __out uint32_t *ouip) 276 { 277 efx_port_t *epp = &(enp->en_port); 278 const efx_phy_ops_t *epop = epp->ep_epop; 279 280 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 281 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 282 283 return (epop->epo_oui_get(enp, ouip)); 284 } 285 286 void 287 efx_phy_media_type_get( 288 __in efx_nic_t *enp, 289 __out efx_phy_media_type_t *typep) 290 { 291 efx_port_t *epp = &(enp->en_port); 292 293 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 294 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 295 296 if (epp->ep_module_type != EFX_PHY_MEDIA_INVALID) 297 *typep = epp->ep_module_type; 298 else 299 *typep = epp->ep_fixed_port_type; 300 } 301 302 __checkReturn efx_rc_t 303 efx_phy_module_get_info( 304 __in efx_nic_t *enp, 305 __in uint8_t dev_addr, 306 __in uint8_t offset, 307 __in uint8_t len, 308 __out_bcount(len) uint8_t *data) 309 { 310 efx_rc_t rc; 311 312 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 313 EFSYS_ASSERT(data != NULL); 314 315 if ((uint32_t)offset + len > 0xff) { 316 rc = EINVAL; 317 goto fail1; 318 } 319 320 if ((rc = efx_mcdi_phy_module_get_info(enp, dev_addr, 321 offset, len, data)) != 0) 322 goto fail2; 323 324 return (0); 325 326 fail2: 327 EFSYS_PROBE(fail2); 328 fail1: 329 EFSYS_PROBE1(fail1, efx_rc_t, rc); 330 331 return (rc); 332 } 333 334 #if EFSYS_OPT_PHY_STATS 335 336 #if EFSYS_OPT_NAMES 337 338 /* START MKCONFIG GENERATED PhyStatNamesBlock af9ffa24da3bc100 */ 339 static const char * const __efx_phy_stat_name[] = { 340 "oui", 341 "pma_pmd_link_up", 342 "pma_pmd_rx_fault", 343 "pma_pmd_tx_fault", 344 "pma_pmd_rev_a", 345 "pma_pmd_rev_b", 346 "pma_pmd_rev_c", 347 "pma_pmd_rev_d", 348 "pcs_link_up", 349 "pcs_rx_fault", 350 "pcs_tx_fault", 351 "pcs_ber", 352 "pcs_block_errors", 353 "phy_xs_link_up", 354 "phy_xs_rx_fault", 355 "phy_xs_tx_fault", 356 "phy_xs_align", 357 "phy_xs_sync_a", 358 "phy_xs_sync_b", 359 "phy_xs_sync_c", 360 "phy_xs_sync_d", 361 "an_link_up", 362 "an_master", 363 "an_local_rx_ok", 364 "an_remote_rx_ok", 365 "cl22ext_link_up", 366 "snr_a", 367 "snr_b", 368 "snr_c", 369 "snr_d", 370 "pma_pmd_signal_a", 371 "pma_pmd_signal_b", 372 "pma_pmd_signal_c", 373 "pma_pmd_signal_d", 374 "an_complete", 375 "pma_pmd_rev_major", 376 "pma_pmd_rev_minor", 377 "pma_pmd_rev_micro", 378 "pcs_fw_version_0", 379 "pcs_fw_version_1", 380 "pcs_fw_version_2", 381 "pcs_fw_version_3", 382 "pcs_fw_build_yy", 383 "pcs_fw_build_mm", 384 "pcs_fw_build_dd", 385 "pcs_op_mode", 386 }; 387 388 /* END MKCONFIG GENERATED PhyStatNamesBlock */ 389 390 const char * 391 efx_phy_stat_name( 392 __in efx_nic_t *enp, 393 __in efx_phy_stat_t type) 394 { 395 _NOTE(ARGUNUSED(enp)) 396 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 397 EFSYS_ASSERT3U(type, <, EFX_PHY_NSTATS); 398 399 return (__efx_phy_stat_name[type]); 400 } 401 402 #endif /* EFSYS_OPT_NAMES */ 403 404 __checkReturn efx_rc_t 405 efx_phy_stats_update( 406 __in efx_nic_t *enp, 407 __in efsys_mem_t *esmp, 408 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) 409 { 410 efx_port_t *epp = &(enp->en_port); 411 const efx_phy_ops_t *epop = epp->ep_epop; 412 413 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 414 EFSYS_ASSERT3U(enp->en_mod_flags, &, EFX_MOD_PORT); 415 416 return (epop->epo_stats_update(enp, esmp, stat)); 417 } 418 419 #endif /* EFSYS_OPT_PHY_STATS */ 420 421 422 #if EFSYS_OPT_BIST 423 424 __checkReturn efx_rc_t 425 efx_bist_enable_offline( 426 __in efx_nic_t *enp) 427 { 428 efx_port_t *epp = &(enp->en_port); 429 const efx_phy_ops_t *epop = epp->ep_epop; 430 efx_rc_t rc; 431 432 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 433 434 if (epop->epo_bist_enable_offline == NULL) { 435 rc = ENOTSUP; 436 goto fail1; 437 } 438 439 if ((rc = epop->epo_bist_enable_offline(enp)) != 0) 440 goto fail2; 441 442 return (0); 443 444 fail2: 445 EFSYS_PROBE(fail2); 446 fail1: 447 EFSYS_PROBE1(fail1, efx_rc_t, rc); 448 449 return (rc); 450 451 } 452 453 __checkReturn efx_rc_t 454 efx_bist_start( 455 __in efx_nic_t *enp, 456 __in efx_bist_type_t type) 457 { 458 efx_port_t *epp = &(enp->en_port); 459 const efx_phy_ops_t *epop = epp->ep_epop; 460 efx_rc_t rc; 461 462 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 463 464 EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); 465 EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); 466 EFSYS_ASSERT3U(epp->ep_current_bist, ==, EFX_BIST_TYPE_UNKNOWN); 467 468 if (epop->epo_bist_start == NULL) { 469 rc = ENOTSUP; 470 goto fail1; 471 } 472 473 if ((rc = epop->epo_bist_start(enp, type)) != 0) 474 goto fail2; 475 476 epp->ep_current_bist = type; 477 478 return (0); 479 480 fail2: 481 EFSYS_PROBE(fail2); 482 fail1: 483 EFSYS_PROBE1(fail1, efx_rc_t, rc); 484 485 return (rc); 486 } 487 488 __checkReturn efx_rc_t 489 efx_bist_poll( 490 __in efx_nic_t *enp, 491 __in efx_bist_type_t type, 492 __out efx_bist_result_t *resultp, 493 __out_opt uint32_t *value_maskp, 494 __out_ecount_opt(count) unsigned long *valuesp, 495 __in size_t count) 496 { 497 efx_port_t *epp = &(enp->en_port); 498 const efx_phy_ops_t *epop = epp->ep_epop; 499 efx_rc_t rc; 500 501 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 502 503 EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); 504 EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); 505 EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); 506 507 EFSYS_ASSERT(epop->epo_bist_poll != NULL); 508 if (epop->epo_bist_poll == NULL) { 509 rc = ENOTSUP; 510 goto fail1; 511 } 512 513 if ((rc = epop->epo_bist_poll(enp, type, resultp, value_maskp, 514 valuesp, count)) != 0) 515 goto fail2; 516 517 return (0); 518 519 fail2: 520 EFSYS_PROBE(fail2); 521 fail1: 522 EFSYS_PROBE1(fail1, efx_rc_t, rc); 523 524 return (rc); 525 } 526 527 void 528 efx_bist_stop( 529 __in efx_nic_t *enp, 530 __in efx_bist_type_t type) 531 { 532 efx_port_t *epp = &(enp->en_port); 533 const efx_phy_ops_t *epop = epp->ep_epop; 534 535 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 536 537 EFSYS_ASSERT3U(type, !=, EFX_BIST_TYPE_UNKNOWN); 538 EFSYS_ASSERT3U(type, <, EFX_BIST_TYPE_NTYPES); 539 EFSYS_ASSERT3U(epp->ep_current_bist, ==, type); 540 541 EFSYS_ASSERT(epop->epo_bist_stop != NULL); 542 543 if (epop->epo_bist_stop != NULL) 544 epop->epo_bist_stop(enp, type); 545 546 epp->ep_current_bist = EFX_BIST_TYPE_UNKNOWN; 547 } 548 549 #endif /* EFSYS_OPT_BIST */ 550 void 551 efx_phy_unprobe( 552 __in efx_nic_t *enp) 553 { 554 efx_port_t *epp = &(enp->en_port); 555 556 EFSYS_ASSERT3U(enp->en_magic, ==, EFX_NIC_MAGIC); 557 558 epp->ep_epop = NULL; 559 560 epp->ep_adv_cap_mask = 0; 561 562 epp->ep_port = 0; 563 epp->ep_phy_type = 0; 564 } 565