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