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