1 /* 2 * Copyright 2007-2013 Solarflare Communications Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND 14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 19 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 23 * SUCH DAMAGE. 24 */ 25 26 #include "efsys.h" 27 #include "efx.h" 28 #include "efx_types.h" 29 #include "efx_regs.h" 30 #include "efx_impl.h" 31 #include "xphy.h" 32 #include "qt2022c2.h" 33 #include "qt2022c2_impl.h" 34 35 #if EFSYS_OPT_PHY_QT2022C2 36 37 static __checkReturn int 38 qt2022c2_led_cfg( 39 __in efx_nic_t *enp) 40 { 41 efx_port_t *epp = &(enp->en_port); 42 efx_word_t led1; 43 efx_word_t led2; 44 efx_word_t led3; 45 int rc; 46 47 #if EFSYS_OPT_PHY_LED_CONTROL 48 49 switch (epp->ep_phy_led_mode) { 50 case EFX_PHY_LED_DEFAULT: 51 EFX_POPULATE_WORD_2(led1, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE, 52 PMA_PMD_LED_PATH, LED_PATH_RX_DECODE); 53 EFX_POPULATE_WORD_2(led2, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE, 54 PMA_PMD_LED_PATH, LED_PATH_TX_DECODE); 55 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE); 56 break; 57 58 case EFX_PHY_LED_OFF: 59 EFX_POPULATE_WORD_1(led1, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE); 60 EFX_POPULATE_WORD_1(led2, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE); 61 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE); 62 break; 63 64 case EFX_PHY_LED_ON: 65 EFX_POPULATE_WORD_1(led1, PMA_PMD_LED_CFG, LED_CFG_ON_DECODE); 66 EFX_POPULATE_WORD_1(led2, PMA_PMD_LED_CFG, LED_CFG_ON_DECODE); 67 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_ON_DECODE); 68 break; 69 70 default: 71 EFSYS_ASSERT(B_FALSE); 72 break; 73 } 74 75 #else /* EFSYS_OPT_PHY_LED_CONTROL */ 76 77 EFX_POPULATE_WORD_2(led1, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE, 78 PMA_PMD_LED_PATH, LED_PATH_RX_DECODE); 79 EFX_POPULATE_WORD_2(led2, PMA_PMD_LED_CFG, LED_CFG_LSA_DECODE, 80 PMA_PMD_LED_PATH, LED_PATH_TX_DECODE); 81 EFX_POPULATE_WORD_1(led3, PMA_PMD_LED_CFG, LED_CFG_OFF_DECODE); 82 83 #endif /* EFSYS_OPT_PHY_LED_CONTROL */ 84 85 if ((rc = falcon_mdio_write(enp, epp->ep_port, PMA_PMD_MMD, 86 PMA_PMD_LED1_REG, &led1)) != 0) 87 goto fail1; 88 89 if ((rc = falcon_mdio_write(enp, epp->ep_port, PMA_PMD_MMD, 90 PMA_PMD_LED2_REG, &led2)) != 0) 91 goto fail2; 92 93 if ((rc = falcon_mdio_write(enp, epp->ep_port, PMA_PMD_MMD, 94 PMA_PMD_LED3_REG, &led3)) != 0) 95 goto fail3; 96 97 return (0); 98 99 fail3: 100 EFSYS_PROBE(fail2); 101 fail2: 102 EFSYS_PROBE(fail2); 103 fail1: 104 EFSYS_PROBE1(fail1, int, rc); 105 106 return (rc); 107 } 108 109 #if EFSYS_OPT_LOOPBACK 110 static __checkReturn int 111 qt2022c2_loopback_cfg( 112 __in efx_nic_t *enp) 113 { 114 efx_port_t *epp = &(enp->en_port); 115 int rc; 116 117 switch (epp->ep_loopback_type) { 118 case EFX_LOOPBACK_PHY_XS: { 119 efx_word_t word; 120 121 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD, 122 PHY_XS_VENDOR0_REG, &word)) != 0) 123 goto fail1; 124 125 EFX_SET_WORD_FIELD(word, XAUI_SYSTEM_LOOPBACK, 1); 126 127 if ((rc = falcon_mdio_write(enp, epp->ep_port, PHY_XS_MMD, 128 PHY_XS_VENDOR0_REG, &word)) != 0) 129 goto fail2; 130 131 break; 132 } 133 case EFX_LOOPBACK_PCS: 134 if ((rc = xphy_mmd_loopback_set(enp, epp->ep_port, PCS_MMD, 135 B_TRUE)) != 0) 136 goto fail1; 137 138 break; 139 140 case EFX_LOOPBACK_PMA_PMD: 141 if ((rc = xphy_mmd_loopback_set(enp, epp->ep_port, PMA_PMD_MMD, 142 B_TRUE)) != 0) 143 goto fail1; 144 145 break; 146 147 default: 148 break; 149 } 150 151 return (0); 152 153 fail2: 154 EFSYS_PROBE(fail2); 155 fail1: 156 EFSYS_PROBE1(fail1, int, rc); 157 158 return (rc); 159 } 160 #endif /* EFSYS_OPT_LOOPBACK */ 161 162 __checkReturn int 163 qt2022c2_reset( 164 __in efx_nic_t *enp) 165 { 166 /* Pull the external reset line */ 167 falcon_nic_phy_reset(enp); 168 169 return (0); 170 } 171 172 __checkReturn int 173 qt2022c2_reconfigure( 174 __in efx_nic_t *enp) 175 { 176 efx_port_t *epp = &(enp->en_port); 177 int rc; 178 179 if ((rc = xphy_pkg_wait(enp, epp->ep_port, QT2022C2_MMD_MASK)) != 0) 180 goto fail1; 181 182 if ((rc = qt2022c2_led_cfg(enp)) != 0) 183 goto fail2; 184 185 EFSYS_ASSERT3U(epp->ep_adv_cap_mask, ==, QT2022C2_ADV_CAP_MASK); 186 187 #if EFSYS_OPT_LOOPBACK 188 if ((rc = qt2022c2_loopback_cfg(enp)) != 0) 189 goto fail3; 190 #endif /* EFSYS_OPT_LOOPBACK */ 191 192 return (0); 193 194 #if EFSYS_OPT_LOOPBACK 195 fail3: 196 EFSYS_PROBE(fail3); 197 #endif /* EFSYS_OPT_LOOPBACK */ 198 199 fail2: 200 EFSYS_PROBE(fail2); 201 fail1: 202 EFSYS_PROBE1(fail1, int, rc); 203 204 return (rc); 205 } 206 207 __checkReturn int 208 qt2022c2_verify( 209 __in efx_nic_t *enp) 210 { 211 efx_port_t *epp = &(enp->en_port); 212 int rc; 213 214 if ((rc = xphy_pkg_verify(enp, epp->ep_port, QT2022C2_MMD_MASK)) != 0) 215 goto fail1; 216 217 return (0); 218 219 fail1: 220 EFSYS_PROBE1(fail1, int, rc); 221 222 return (rc); 223 } 224 225 __checkReturn int 226 qt2022c2_uplink_check( 227 __in efx_nic_t *enp, 228 __out boolean_t *upp) 229 { 230 efx_port_t *epp = &(enp->en_port); 231 efx_word_t word; 232 int rc; 233 234 if (epp->ep_mac_type != EFX_MAC_FALCON_XMAC) { 235 rc = ENOTSUP; 236 goto fail1; 237 } 238 239 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD, 240 PHY_XS_LANE_STATUS_REG, &word)) != 0) 241 goto fail2; 242 243 *upp = ((EFX_WORD_FIELD(word, PHY_XS_ALIGNED) != 0) && 244 (EFX_WORD_FIELD(word, PHY_XS_LANE0_SYNC) != 0) && 245 (EFX_WORD_FIELD(word, PHY_XS_LANE1_SYNC) != 0) && 246 (EFX_WORD_FIELD(word, PHY_XS_LANE2_SYNC) != 0) && 247 (EFX_WORD_FIELD(word, PHY_XS_LANE3_SYNC) != 0)); 248 249 return (0); 250 251 fail2: 252 EFSYS_PROBE(fail2); 253 fail1: 254 EFSYS_PROBE1(fail1, int, rc); 255 256 return (rc); 257 } 258 259 __checkReturn int 260 qt2022c2_downlink_check( 261 __in efx_nic_t *enp, 262 __out efx_link_mode_t *modep, 263 __out unsigned int *fcntlp, 264 __out uint32_t *lp_cap_maskp) 265 { 266 efx_port_t *epp = &(enp->en_port); 267 boolean_t up; 268 int rc; 269 270 #if EFSYS_OPT_LOOPBACK 271 switch (epp->ep_loopback_type) { 272 case EFX_LOOPBACK_PHY_XS: 273 rc = xphy_mmd_fault(enp, epp->ep_port, &up); 274 if (rc != 0) 275 goto fail1; 276 277 *modep = (up) ? EFX_LINK_10000FDX : EFX_LINK_DOWN; 278 goto done; 279 280 case EFX_LOOPBACK_PCS: 281 rc = xphy_mmd_check(enp, epp->ep_port, PHY_XS_MMD, &up); 282 if (rc != 0) 283 goto fail1; 284 285 *modep = (up) ? EFX_LINK_10000FDX : EFX_LINK_DOWN; 286 goto done; 287 288 default: 289 break; 290 } 291 #endif /* EFSYS_OPT_LOOPBACK */ 292 293 if ((rc = xphy_mmd_check(enp, epp->ep_port, PCS_MMD, &up)) != 0) 294 goto fail1; 295 296 *modep = (up) ? EFX_LINK_10000FDX : EFX_LINK_DOWN; 297 298 #if EFSYS_OPT_LOOPBACK 299 done: 300 #endif 301 *fcntlp = epp->ep_fcntl; 302 *lp_cap_maskp = epp->ep_lp_cap_mask; 303 304 return (0); 305 306 fail1: 307 EFSYS_PROBE1(fail1, int, rc); 308 309 return (rc); 310 } 311 312 __checkReturn int 313 qt2022c2_oui_get( 314 __in efx_nic_t *enp, 315 __out uint32_t *ouip) 316 { 317 efx_port_t *epp = &(enp->en_port); 318 int rc; 319 320 if ((rc = xphy_mmd_oui_get(enp, epp->ep_port, PMA_PMD_MMD, ouip)) != 0) 321 goto fail1; 322 323 return (0); 324 325 fail1: 326 EFSYS_PROBE1(fail1, int, rc); 327 328 return (rc); 329 } 330 331 #if EFSYS_OPT_PHY_STATS 332 333 #define QT2022C2_STAT_SET(_stat, _mask, _id, _val) \ 334 do { \ 335 (_mask) |= (1 << (_id)); \ 336 (_stat)[_id] = (uint32_t)(_val); \ 337 _NOTE(CONSTANTCONDITION) \ 338 } while (B_FALSE) 339 340 static __checkReturn int 341 qt2022c2_pma_pmd_stats_update( 342 __in efx_nic_t *enp, 343 __inout uint64_t *maskp, 344 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) 345 { 346 efx_port_t *epp = &(enp->en_port); 347 efx_word_t word; 348 int rc; 349 350 if ((rc = falcon_mdio_read(enp, epp->ep_port, PMA_PMD_MMD, 351 PMA_PMD_STATUS1_REG, &word)) != 0) 352 goto fail1; 353 354 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PMA_PMD_LINK_UP, 355 (EFX_WORD_FIELD(word, PMA_PMD_LINK_UP) != 0) ? 1 : 0); 356 357 if ((rc = falcon_mdio_read(enp, epp->ep_port, PMA_PMD_MMD, 358 PMA_PMD_STATUS2_REG, &word)) != 0) 359 goto fail2; 360 361 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PMA_PMD_RX_FAULT, 362 (EFX_WORD_FIELD(word, PMA_PMD_RX_FAULT) != 0) ? 1 : 0); 363 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PMA_PMD_TX_FAULT, 364 (EFX_WORD_FIELD(word, PMA_PMD_TX_FAULT) != 0) ? 1 : 0); 365 366 return (0); 367 368 fail2: 369 EFSYS_PROBE(fail2); 370 fail1: 371 EFSYS_PROBE1(fail1, int, rc); 372 373 return (rc); 374 } 375 376 static __checkReturn int 377 qt2022c2_pcs_stats_update( 378 __in efx_nic_t *enp, 379 __inout uint64_t *maskp, 380 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) 381 { 382 efx_port_t *epp = &(enp->en_port); 383 efx_word_t word; 384 int rc; 385 386 if ((rc = falcon_mdio_read(enp, epp->ep_port, PCS_MMD, 387 PCS_STATUS1_REG, &word)) != 0) 388 goto fail1; 389 390 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_LINK_UP, 391 (EFX_WORD_FIELD(word, PCS_LINK_UP) != 0) ? 1 : 0); 392 393 if ((rc = falcon_mdio_read(enp, epp->ep_port, PCS_MMD, 394 PCS_STATUS2_REG, &word)) != 0) 395 goto fail2; 396 397 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_RX_FAULT, 398 (EFX_WORD_FIELD(word, PCS_RX_FAULT) != 0) ? 1 : 0); 399 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_TX_FAULT, 400 (EFX_WORD_FIELD(word, PCS_TX_FAULT) != 0) ? 1 : 0); 401 402 if ((rc = falcon_mdio_read(enp, epp->ep_port, PCS_MMD, 403 PCS_10GBASE_R_STATUS2_REG, &word)) != 0) 404 goto fail3; 405 406 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_BER, 407 EFX_WORD_FIELD(word, PCS_BER)); 408 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PCS_BLOCK_ERRORS, 409 EFX_WORD_FIELD(word, PCS_ERR)); 410 411 return (0); 412 413 fail3: 414 EFSYS_PROBE(fail3); 415 fail2: 416 EFSYS_PROBE(fail2); 417 fail1: 418 EFSYS_PROBE1(fail1, int, rc); 419 420 return (rc); 421 } 422 423 static __checkReturn int 424 qt2022c2_phy_xs_stats_update( 425 __in efx_nic_t *enp, 426 __inout uint64_t *maskp, 427 __inout_ecount(EFX_PHY_NSTATS) uint32_t *stat) 428 { 429 efx_port_t *epp = &(enp->en_port); 430 efx_word_t word; 431 int rc; 432 433 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD, 434 PHY_XS_STATUS1_REG, &word)) != 0) 435 goto fail1; 436 437 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_LINK_UP, 438 (EFX_WORD_FIELD(word, PHY_XS_LINK_UP) != 0) ? 1 : 0); 439 440 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD, 441 PHY_XS_STATUS2_REG, &word)) != 0) 442 goto fail2; 443 444 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_RX_FAULT, 445 (EFX_WORD_FIELD(word, PHY_XS_RX_FAULT) != 0) ? 1 : 0); 446 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_TX_FAULT, 447 (EFX_WORD_FIELD(word, PHY_XS_TX_FAULT) != 0) ? 1 : 0); 448 449 if ((rc = falcon_mdio_read(enp, epp->ep_port, PHY_XS_MMD, 450 PHY_XS_LANE_STATUS_REG, &word)) != 0) 451 goto fail3; 452 453 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_ALIGN, 454 (EFX_WORD_FIELD(word, PHY_XS_ALIGNED) != 0) ? 1 : 0); 455 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_A, 456 (EFX_WORD_FIELD(word, PHY_XS_LANE0_SYNC) != 0) ? 1 : 0); 457 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_B, 458 (EFX_WORD_FIELD(word, PHY_XS_LANE1_SYNC) != 0) ? 1 : 0); 459 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_C, 460 (EFX_WORD_FIELD(word, PHY_XS_LANE2_SYNC) != 0) ? 1 : 0); 461 QT2022C2_STAT_SET(stat, *maskp, EFX_PHY_STAT_PHY_XS_SYNC_D, 462 (EFX_WORD_FIELD(word, PHY_XS_LANE3_SYNC) != 0) ? 1 : 0); 463 464 return (0); 465 466 fail3: 467 EFSYS_PROBE(fail3); 468 fail2: 469 EFSYS_PROBE(fail2); 470 fail1: 471 EFSYS_PROBE1(fail1, int, rc); 472 473 return (rc); 474 } 475 476 __checkReturn int 477 qt2022c2_stats_update( 478 __in efx_nic_t *enp, 479 __in efsys_mem_t *esmp, 480 __out_ecount(EFX_PHY_NSTATS) uint32_t *stat) 481 { 482 efx_port_t *epp = &(enp->en_port); 483 efx_nic_cfg_t *encp = &(enp->en_nic_cfg); 484 uint32_t oui; 485 uint64_t mask = 0; 486 int rc; 487 488 _NOTE(ARGUNUSED(esmp)) 489 490 if ((rc = xphy_mmd_oui_get(enp, epp->ep_port, PMA_PMD_MMD, &oui)) != 0) 491 goto fail1; 492 493 QT2022C2_STAT_SET(stat, mask, EFX_PHY_STAT_OUI, oui); 494 495 if ((rc = qt2022c2_pma_pmd_stats_update(enp, &mask, stat)) != 0) 496 goto fail2; 497 498 if ((rc = qt2022c2_pcs_stats_update(enp, &mask, stat)) != 0) 499 goto fail3; 500 501 if ((rc = qt2022c2_phy_xs_stats_update(enp, &mask, stat)) != 0) 502 goto fail4; 503 504 /* Ensure all the supported statistics are up to date */ 505 EFSYS_ASSERT(mask == encp->enc_phy_stat_mask); 506 507 return (0); 508 509 fail4: 510 EFSYS_PROBE(fail4); 511 fail3: 512 EFSYS_PROBE(fail3); 513 fail2: 514 EFSYS_PROBE(fail2); 515 fail1: 516 EFSYS_PROBE1(fail1, int, rc); 517 518 return (rc); 519 } 520 #endif /* EFSYS_OPT_PHY_STATS */ 521 522 #if EFSYS_OPT_PHY_PROPS 523 524 #if EFSYS_OPT_NAMES 525 const char __cs * 526 qt2022c2_prop_name( 527 __in efx_nic_t *enp, 528 __in unsigned int id) 529 { 530 _NOTE(ARGUNUSED(enp, id)) 531 532 EFSYS_ASSERT(B_FALSE); 533 534 return (NULL); 535 } 536 #endif /* EFSYS_OPT_NAMES */ 537 538 __checkReturn int 539 qt2022c2_prop_get( 540 __in efx_nic_t *enp, 541 __in unsigned int id, 542 __in uint32_t flags, 543 __out uint32_t *valp) 544 { 545 _NOTE(ARGUNUSED(enp, id, flags, valp)) 546 547 EFSYS_ASSERT(B_FALSE); 548 549 return (ENOTSUP); 550 } 551 552 __checkReturn int 553 qt2022c2_prop_set( 554 __in efx_nic_t *enp, 555 __in unsigned int id, 556 __in uint32_t val) 557 { 558 _NOTE(ARGUNUSED(enp, id, val)) 559 560 EFSYS_ASSERT(B_FALSE); 561 562 return (ENOTSUP); 563 } 564 #endif /* EFSYS_OPT_PHY_PROPS */ 565 566 #endif /* EFSYS_OPT_PHY_QT2022C2 */