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 }