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