1 /*
   2  * Copyright (c) 2009-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 #if EFSYS_OPT_SIENA
  35 
  36 static                  void
  37 siena_phy_decode_cap(
  38         __in            uint32_t mcdi_cap,
  39         __out           uint32_t *maskp)
  40 {
  41         uint32_t mask;
  42 
  43         mask = 0;
  44         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10HDX_LBN))
  45                 mask |= (1 << EFX_PHY_CAP_10HDX);
  46         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10FDX_LBN))
  47                 mask |= (1 << EFX_PHY_CAP_10FDX);
  48         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100HDX_LBN))
  49                 mask |= (1 << EFX_PHY_CAP_100HDX);
  50         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_100FDX_LBN))
  51                 mask |= (1 << EFX_PHY_CAP_100FDX);
  52         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000HDX_LBN))
  53                 mask |= (1 << EFX_PHY_CAP_1000HDX);
  54         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_1000FDX_LBN))
  55                 mask |= (1 << EFX_PHY_CAP_1000FDX);
  56         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_10000FDX_LBN))
  57                 mask |= (1 << EFX_PHY_CAP_10000FDX);
  58         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_PAUSE_LBN))
  59                 mask |= (1 << EFX_PHY_CAP_PAUSE);
  60         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_ASYM_LBN))
  61                 mask |= (1 << EFX_PHY_CAP_ASYM);
  62         if (mcdi_cap & (1 << MC_CMD_PHY_CAP_AN_LBN))
  63                 mask |= (1 << EFX_PHY_CAP_AN);
  64 
  65         *maskp = mask;
  66 }
  67 
  68 static                  void
  69 siena_phy_decode_link_mode(
  70         __in            efx_nic_t *enp,
  71         __in            uint32_t link_flags,
  72         __in            unsigned int speed,
  73         __in            unsigned int fcntl,
  74         __out           efx_link_mode_t *link_modep,
  75         __out           unsigned int *fcntlp)
  76 {
  77         boolean_t fd = !!(link_flags &
  78                     (1 << MC_CMD_GET_LINK_OUT_FULL_DUPLEX_LBN));
  79         boolean_t up = !!(link_flags &
  80                     (1 << MC_CMD_GET_LINK_OUT_LINK_UP_LBN));
  81 
  82         _NOTE(ARGUNUSED(enp))
  83 
  84         if (!up)
  85                 *link_modep = EFX_LINK_DOWN;
  86         else if (speed == 10000 && fd)
  87                 *link_modep = EFX_LINK_10000FDX;
  88         else if (speed == 1000)
  89                 *link_modep = fd ? EFX_LINK_1000FDX : EFX_LINK_1000HDX;
  90         else if (speed == 100)
  91                 *link_modep = fd ? EFX_LINK_100FDX : EFX_LINK_100HDX;
  92         else if (speed == 10)
  93                 *link_modep = fd ? EFX_LINK_10FDX : EFX_LINK_10HDX;
  94         else
  95                 *link_modep = EFX_LINK_UNKNOWN;
  96 
  97         if (fcntl == MC_CMD_FCNTL_OFF)
  98                 *fcntlp = 0;
  99         else if (fcntl == MC_CMD_FCNTL_RESPOND)
 100                 *fcntlp = EFX_FCNTL_RESPOND;
 101         else if (fcntl == MC_CMD_FCNTL_BIDIR)
 102                 *fcntlp = EFX_FCNTL_RESPOND | EFX_FCNTL_GENERATE;
 103         else {
 104                 EFSYS_PROBE1(mc_pcol_error, int, fcntl);
 105                 *fcntlp = 0;
 106         }
 107 }
 108 
 109                         void
 110 siena_phy_link_ev(
 111         __in            efx_nic_t *enp,
 112         __in            efx_qword_t *eqp,
 113         __out           efx_link_mode_t *link_modep)
 114 {
 115         efx_port_t *epp = &(enp->en_port);
 116         unsigned int link_flags;
 117         unsigned int speed;
 118         unsigned int fcntl;
 119         efx_link_mode_t link_mode;
 120         uint32_t lp_cap_mask;
 121 
 122         /*
 123          * Convert the LINKCHANGE speed enumeration into mbit/s, in the
 124          * same way as GET_LINK encodes the speed
 125          */
 126         switch (MCDI_EV_FIELD(eqp, LINKCHANGE_SPEED)) {
 127         case MCDI_EVENT_LINKCHANGE_SPEED_100M:
 128                 speed = 100;
 129                 break;
 130         case MCDI_EVENT_LINKCHANGE_SPEED_1G:
 131                 speed = 1000;
 132                 break;
 133         case MCDI_EVENT_LINKCHANGE_SPEED_10G:
 134                 speed = 10000;
 135                 break;
 136         default:
 137                 speed = 0;
 138                 break;
 139         }
 140 
 141         link_flags = MCDI_EV_FIELD(eqp, LINKCHANGE_LINK_FLAGS);
 142         siena_phy_decode_link_mode(enp, link_flags, speed,
 143                                     MCDI_EV_FIELD(eqp, LINKCHANGE_FCNTL),
 144                                     &link_mode, &fcntl);
 145         siena_phy_decode_cap(MCDI_EV_FIELD(eqp, LINKCHANGE_LP_CAP),
 146                             &lp_cap_mask);
 147 
 148         /*
 149          * It's safe to update ep_lp_cap_mask without the driver's port lock
 150          * because presumably any concurrently running efx_port_poll() is
 151          * only going to arrive at the same value.
 152          *
 153          * ep_fcntl has two meanings. It's either the link common fcntl
 154          * (if the PHY supports AN), or it's the forced link state. If
 155          * the former, it's safe to update the value for the same reason as
 156          * for ep_lp_cap_mask. If the latter, then just ignore the value,
 157          * because we can race with efx_mac_fcntl_set().
 158          */
 159         epp->ep_lp_cap_mask = lp_cap_mask;
 160         if (epp->ep_phy_cap_mask & (1 << EFX_PHY_CAP_AN))
 161                 epp->ep_fcntl = fcntl;
 162 
 163         *link_modep = link_mode;
 164 }
 165 
 166         __checkReturn   efx_rc_t
 167 siena_phy_power(
 168         __in            efx_nic_t *enp,
 169         __in            boolean_t power)
 170 {
 171         efx_rc_t rc;
 172 
 173         if (!power)
 174                 return (0);
 175 
 176         /* Check if the PHY is a zombie */
 177         if ((rc = siena_phy_verify(enp)) != 0)
 178                 goto fail1;
 179 
 180         enp->en_reset_flags |= EFX_RESET_PHY;
 181 
 182         return (0);
 183 
 184 fail1:
 185         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 186 
 187         return (rc);
 188 }
 189 
 190         __checkReturn   efx_rc_t
 191 siena_phy_get_link(
 192         __in            efx_nic_t *enp,
 193         __out           siena_link_state_t *slsp)
 194 {
 195         efx_mcdi_req_t req;
 196         uint8_t payload[MAX(MC_CMD_GET_LINK_IN_LEN,
 197                             MC_CMD_GET_LINK_OUT_LEN)];
 198         efx_rc_t rc;
 199 
 200         (void) memset(payload, 0, sizeof (payload));
 201         req.emr_cmd = MC_CMD_GET_LINK;
 202         req.emr_in_buf = payload;
 203         req.emr_in_length = MC_CMD_GET_LINK_IN_LEN;
 204         req.emr_out_buf = payload;
 205         req.emr_out_length = MC_CMD_GET_LINK_OUT_LEN;
 206 
 207         efx_mcdi_execute(enp, &req);
 208 
 209         if (req.emr_rc != 0) {
 210                 rc = req.emr_rc;
 211                 goto fail1;
 212         }
 213 
 214         if (req.emr_out_length_used < MC_CMD_GET_LINK_OUT_LEN) {
 215                 rc = EMSGSIZE;
 216                 goto fail2;
 217         }
 218 
 219         siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_CAP),
 220                             &slsp->sls_adv_cap_mask);
 221         siena_phy_decode_cap(MCDI_OUT_DWORD(req, GET_LINK_OUT_LP_CAP),
 222                             &slsp->sls_lp_cap_mask);
 223 
 224         siena_phy_decode_link_mode(enp, MCDI_OUT_DWORD(req, GET_LINK_OUT_FLAGS),
 225                             MCDI_OUT_DWORD(req, GET_LINK_OUT_LINK_SPEED),
 226                             MCDI_OUT_DWORD(req, GET_LINK_OUT_FCNTL),
 227                             &slsp->sls_link_mode, &slsp->sls_fcntl);
 228 
 229 #if EFSYS_OPT_LOOPBACK
 230         /* Assert the MC_CMD_LOOPBACK and EFX_LOOPBACK namespace agree */
 231         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_NONE == EFX_LOOPBACK_OFF);
 232         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_DATA == EFX_LOOPBACK_DATA);
 233         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMAC == EFX_LOOPBACK_GMAC);
 234         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGMII == EFX_LOOPBACK_XGMII);
 235         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGXS == EFX_LOOPBACK_XGXS);
 236         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI == EFX_LOOPBACK_XAUI);
 237         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII == EFX_LOOPBACK_GMII);
 238         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII == EFX_LOOPBACK_SGMII);
 239         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XGBR == EFX_LOOPBACK_XGBR);
 240         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI == EFX_LOOPBACK_XFI);
 241         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XAUI_FAR == EFX_LOOPBACK_XAUI_FAR);
 242         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GMII_FAR == EFX_LOOPBACK_GMII_FAR);
 243         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_SGMII_FAR == EFX_LOOPBACK_SGMII_FAR);
 244         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_XFI_FAR == EFX_LOOPBACK_XFI_FAR);
 245         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_GPHY == EFX_LOOPBACK_GPHY);
 246         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PHYXS == EFX_LOOPBACK_PHY_XS);
 247         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PCS == EFX_LOOPBACK_PCS);
 248         EFX_STATIC_ASSERT(MC_CMD_LOOPBACK_PMAPMD == EFX_LOOPBACK_PMA_PMD);
 249 
 250         slsp->sls_loopback = MCDI_OUT_DWORD(req, GET_LINK_OUT_LOOPBACK_MODE);
 251 #endif  /* EFSYS_OPT_LOOPBACK */
 252 
 253         slsp->sls_mac_up = MCDI_OUT_DWORD(req, GET_LINK_OUT_MAC_FAULT) == 0;
 254 
 255         return (0);
 256 
 257 fail2:
 258         EFSYS_PROBE(fail2);
 259 fail1:
 260         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 261 
 262         return (rc);
 263 }
 264 
 265         __checkReturn   efx_rc_t
 266 siena_phy_reconfigure(
 267         __in            efx_nic_t *enp)
 268 {
 269         efx_port_t *epp = &(enp->en_port);
 270         efx_mcdi_req_t req;
 271         uint8_t payload[MAX(MAX(MC_CMD_SET_ID_LED_IN_LEN,
 272                                 MC_CMD_SET_ID_LED_OUT_LEN),
 273                             MAX(MC_CMD_SET_LINK_IN_LEN,
 274                                 MC_CMD_SET_LINK_OUT_LEN))];
 275         uint32_t cap_mask;
 276         unsigned int led_mode;
 277         unsigned int speed;
 278         efx_rc_t rc;
 279 
 280         (void) memset(payload, 0, sizeof (payload));
 281         req.emr_cmd = MC_CMD_SET_LINK;
 282         req.emr_in_buf = payload;
 283         req.emr_in_length = MC_CMD_SET_LINK_IN_LEN;
 284         req.emr_out_buf = payload;
 285         req.emr_out_length = MC_CMD_SET_LINK_OUT_LEN;
 286 
 287         cap_mask = epp->ep_adv_cap_mask;
 288         MCDI_IN_POPULATE_DWORD_10(req, SET_LINK_IN_CAP,
 289                 PHY_CAP_10HDX, (cap_mask >> EFX_PHY_CAP_10HDX) & 0x1,
 290                 PHY_CAP_10FDX, (cap_mask >> EFX_PHY_CAP_10FDX) & 0x1,
 291                 PHY_CAP_100HDX, (cap_mask >> EFX_PHY_CAP_100HDX) & 0x1,
 292                 PHY_CAP_100FDX, (cap_mask >> EFX_PHY_CAP_100FDX) & 0x1,
 293                 PHY_CAP_1000HDX, (cap_mask >> EFX_PHY_CAP_1000HDX) & 0x1,
 294                 PHY_CAP_1000FDX, (cap_mask >> EFX_PHY_CAP_1000FDX) & 0x1,
 295                 PHY_CAP_10000FDX, (cap_mask >> EFX_PHY_CAP_10000FDX) & 0x1,
 296                 PHY_CAP_PAUSE, (cap_mask >> EFX_PHY_CAP_PAUSE) & 0x1,
 297                 PHY_CAP_ASYM, (cap_mask >> EFX_PHY_CAP_ASYM) & 0x1,
 298                 PHY_CAP_AN, (cap_mask >> EFX_PHY_CAP_AN) & 0x1);
 299 
 300 #if EFSYS_OPT_LOOPBACK
 301         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE,
 302                     epp->ep_loopback_type);
 303         switch (epp->ep_loopback_link_mode) {
 304         case EFX_LINK_100FDX:
 305                 speed = 100;
 306                 break;
 307         case EFX_LINK_1000FDX:
 308                 speed = 1000;
 309                 break;
 310         case EFX_LINK_10000FDX:
 311                 speed = 10000;
 312                 break;
 313         default:
 314                 speed = 0;
 315         }
 316 #else
 317         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_MODE, MC_CMD_LOOPBACK_NONE);
 318         speed = 0;
 319 #endif  /* EFSYS_OPT_LOOPBACK */
 320         MCDI_IN_SET_DWORD(req, SET_LINK_IN_LOOPBACK_SPEED, speed);
 321 
 322 #if EFSYS_OPT_PHY_FLAGS
 323         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, epp->ep_phy_flags);
 324 #else
 325         MCDI_IN_SET_DWORD(req, SET_LINK_IN_FLAGS, 0);
 326 #endif  /* EFSYS_OPT_PHY_FLAGS */
 327 
 328         efx_mcdi_execute(enp, &req);
 329 
 330         if (req.emr_rc != 0) {
 331                 rc = req.emr_rc;
 332                 goto fail1;
 333         }
 334 
 335         /* And set the blink mode */
 336         (void) memset(payload, 0, sizeof (payload));
 337         req.emr_cmd = MC_CMD_SET_ID_LED;
 338         req.emr_in_buf = payload;
 339         req.emr_in_length = MC_CMD_SET_ID_LED_IN_LEN;
 340         req.emr_out_buf = payload;
 341         req.emr_out_length = MC_CMD_SET_ID_LED_OUT_LEN;
 342 
 343 #if EFSYS_OPT_PHY_LED_CONTROL
 344         switch (epp->ep_phy_led_mode) {
 345         case EFX_PHY_LED_DEFAULT:
 346                 led_mode = MC_CMD_LED_DEFAULT;
 347                 break;
 348         case EFX_PHY_LED_OFF:
 349                 led_mode = MC_CMD_LED_OFF;
 350                 break;
 351         case EFX_PHY_LED_ON:
 352                 led_mode = MC_CMD_LED_ON;
 353                 break;
 354         default:
 355                 EFSYS_ASSERT(0);
 356                 led_mode = MC_CMD_LED_DEFAULT;
 357         }
 358 
 359         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, led_mode);
 360 #else
 361         MCDI_IN_SET_DWORD(req, SET_ID_LED_IN_STATE, MC_CMD_LED_DEFAULT);
 362 #endif  /* EFSYS_OPT_PHY_LED_CONTROL */
 363 
 364         efx_mcdi_execute(enp, &req);
 365 
 366         if (req.emr_rc != 0) {
 367                 rc = req.emr_rc;
 368                 goto fail2;
 369         }
 370 
 371         return (0);
 372 
 373 fail2:
 374         EFSYS_PROBE(fail2);
 375 fail1:
 376         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 377 
 378         return (rc);
 379 }
 380 
 381         __checkReturn   efx_rc_t
 382 siena_phy_verify(
 383         __in            efx_nic_t *enp)
 384 {
 385         efx_mcdi_req_t req;
 386         uint8_t payload[MAX(MC_CMD_GET_PHY_STATE_IN_LEN,
 387                             MC_CMD_GET_PHY_STATE_OUT_LEN)];
 388         uint32_t state;
 389         efx_rc_t rc;
 390 
 391         (void) memset(payload, 0, sizeof (payload));
 392         req.emr_cmd = MC_CMD_GET_PHY_STATE;
 393         req.emr_in_buf = payload;
 394         req.emr_in_length = MC_CMD_GET_PHY_STATE_IN_LEN;
 395         req.emr_out_buf = payload;
 396         req.emr_out_length = MC_CMD_GET_PHY_STATE_OUT_LEN;
 397 
 398         efx_mcdi_execute(enp, &req);
 399 
 400         if (req.emr_rc != 0) {
 401                 rc = req.emr_rc;
 402                 goto fail1;
 403         }
 404 
 405         if (req.emr_out_length_used < MC_CMD_GET_PHY_STATE_OUT_LEN) {
 406                 rc = EMSGSIZE;
 407                 goto fail2;
 408         }
 409 
 410         state = MCDI_OUT_DWORD(req, GET_PHY_STATE_OUT_STATE);
 411         if (state != MC_CMD_PHY_STATE_OK) {
 412                 if (state != MC_CMD_PHY_STATE_ZOMBIE)
 413                         EFSYS_PROBE1(mc_pcol_error, int, state);
 414                 rc = ENOTACTIVE;
 415                 goto fail3;
 416         }
 417 
 418         return (0);
 419 
 420 fail3:
 421         EFSYS_PROBE(fail3);
 422 fail2:
 423         EFSYS_PROBE(fail2);
 424 fail1:
 425         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 426 
 427         return (rc);
 428 }
 429 
 430         __checkReturn   efx_rc_t
 431 siena_phy_oui_get(
 432         __in            efx_nic_t *enp,
 433         __out           uint32_t *ouip)
 434 {
 435         _NOTE(ARGUNUSED(enp, ouip))
 436 
 437         return (ENOTSUP);
 438 }
 439 
 440 #if EFSYS_OPT_PHY_STATS
 441 
 442 #define SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,             \
 443                             _mc_record, _efx_record)                    \
 444         if ((_vmask) & (1ULL << (_mc_record))) {                      \
 445                 (_smask) |= (1ULL << (_efx_record));                      \
 446                 if ((_stat) != NULL && !EFSYS_MEM_IS_NULL(_esmp)) {     \
 447                         efx_dword_t dword;                              \
 448                         EFSYS_MEM_READD(_esmp, (_mc_record) * 4, &dword);\
 449                         (_stat)[_efx_record] =                          \
 450                                 EFX_DWORD_FIELD(dword, EFX_DWORD_0);    \
 451                 }                                                       \
 452         }
 453 
 454 #define SIENA_SIMPLE_STAT_SET2(_vmask, _esmp, _smask, _stat, _record)   \
 455         SIENA_SIMPLE_STAT_SET(_vmask, _esmp, _smask, _stat,             \
 456                             MC_CMD_ ## _record,                         \
 457                             EFX_PHY_STAT_ ## _record)
 458 
 459                                                 void
 460 siena_phy_decode_stats(
 461         __in                                    efx_nic_t *enp,
 462         __in                                    uint32_t vmask,
 463         __in_opt                                efsys_mem_t *esmp,
 464         __out_opt                               uint64_t *smaskp,
 465         __inout_ecount_opt(EFX_PHY_NSTATS)      uint32_t *stat)
 466 {
 467         uint64_t smask = 0;
 468 
 469         _NOTE(ARGUNUSED(enp))
 470 
 471         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, OUI);
 472         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_LINK_UP);
 473         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_RX_FAULT);
 474         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PMA_PMD_TX_FAULT);
 475 
 476         if (vmask & (1 << MC_CMD_PMA_PMD_SIGNAL)) {
 477                 smask |=   ((1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_A) |
 478                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_B) |
 479                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_C) |
 480                             (1ULL << EFX_PHY_STAT_PMA_PMD_SIGNAL_D));
 481                 if (stat != NULL && esmp != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
 482                         efx_dword_t dword;
 483                         uint32_t sig;
 484                         EFSYS_MEM_READD(esmp, 4 * MC_CMD_PMA_PMD_SIGNAL,
 485                                         &dword);
 486                         sig = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
 487                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_A] = (sig >> 1) & 1;
 488                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_B] = (sig >> 2) & 1;
 489                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_C] = (sig >> 3) & 1;
 490                         stat[EFX_PHY_STAT_PMA_PMD_SIGNAL_D] = (sig >> 4) & 1;
 491                 }
 492         }
 493 
 494         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_A,
 495                             EFX_PHY_STAT_SNR_A);
 496         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_B,
 497                             EFX_PHY_STAT_SNR_B);
 498         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_C,
 499                             EFX_PHY_STAT_SNR_C);
 500         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PMA_PMD_SNR_D,
 501                             EFX_PHY_STAT_SNR_D);
 502 
 503         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_LINK_UP);
 504         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_RX_FAULT);
 505         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_TX_FAULT);
 506         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BER);
 507         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, PCS_BLOCK_ERRORS);
 508 
 509         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_LINK_UP,
 510                             EFX_PHY_STAT_PHY_XS_LINK_UP);
 511         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_RX_FAULT,
 512                             EFX_PHY_STAT_PHY_XS_RX_FAULT);
 513         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_TX_FAULT,
 514                             EFX_PHY_STAT_PHY_XS_TX_FAULT);
 515         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_PHYXS_ALIGN,
 516                             EFX_PHY_STAT_PHY_XS_ALIGN);
 517 
 518         if (vmask & (1 << MC_CMD_PHYXS_SYNC)) {
 519                 smask |=   ((1 << EFX_PHY_STAT_PHY_XS_SYNC_A) |
 520                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_B) |
 521                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_C) |
 522                             (1 << EFX_PHY_STAT_PHY_XS_SYNC_D));
 523                 if (stat != NULL && !EFSYS_MEM_IS_NULL(esmp)) {
 524                         efx_dword_t dword;
 525                         uint32_t sync;
 526                         EFSYS_MEM_READD(esmp, 4 * MC_CMD_PHYXS_SYNC, &dword);
 527                         sync = EFX_DWORD_FIELD(dword, EFX_DWORD_0);
 528                         stat[EFX_PHY_STAT_PHY_XS_SYNC_A] = (sync >> 0) & 1;
 529                         stat[EFX_PHY_STAT_PHY_XS_SYNC_B] = (sync >> 1) & 1;
 530                         stat[EFX_PHY_STAT_PHY_XS_SYNC_C] = (sync >> 2) & 1;
 531                         stat[EFX_PHY_STAT_PHY_XS_SYNC_D] = (sync >> 3) & 1;
 532                 }
 533         }
 534 
 535         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_LINK_UP);
 536         SIENA_SIMPLE_STAT_SET2(vmask, esmp, smask, stat, AN_COMPLETE);
 537 
 538         SIENA_SIMPLE_STAT_SET(vmask, esmp, smask, stat, MC_CMD_CL22_LINK_UP,
 539                             EFX_PHY_STAT_CL22EXT_LINK_UP);
 540 
 541         if (smaskp != NULL)
 542                 *smaskp = smask;
 543 }
 544 
 545         __checkReturn                           efx_rc_t
 546 siena_phy_stats_update(
 547         __in                                    efx_nic_t *enp,
 548         __in                                    efsys_mem_t *esmp,
 549         __inout_ecount(EFX_PHY_NSTATS)          uint32_t *stat)
 550 {
 551         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 552         uint32_t vmask = encp->enc_mcdi_phy_stat_mask;
 553         uint64_t smask;
 554         efx_mcdi_req_t req;
 555         uint8_t payload[MAX(MC_CMD_PHY_STATS_IN_LEN,
 556                             MC_CMD_PHY_STATS_OUT_DMA_LEN)];
 557         efx_rc_t rc;
 558 
 559         (void) memset(payload, 0, sizeof (payload));
 560         req.emr_cmd = MC_CMD_PHY_STATS;
 561         req.emr_in_buf = payload;
 562         req.emr_in_length = MC_CMD_PHY_STATS_IN_LEN;
 563         req.emr_out_buf = payload;
 564         req.emr_out_length = MC_CMD_PHY_STATS_OUT_DMA_LEN;
 565 
 566         MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_LO,
 567                             EFSYS_MEM_ADDR(esmp) & 0xffffffff);
 568         MCDI_IN_SET_DWORD(req, PHY_STATS_IN_DMA_ADDR_HI,
 569                             EFSYS_MEM_ADDR(esmp) >> 32);
 570 
 571         efx_mcdi_execute(enp, &req);
 572 
 573         if (req.emr_rc != 0) {
 574                 rc = req.emr_rc;
 575                 goto fail1;
 576         }
 577         EFSYS_ASSERT3U(req.emr_out_length, ==, MC_CMD_PHY_STATS_OUT_DMA_LEN);
 578 
 579         siena_phy_decode_stats(enp, vmask, esmp, &smask, stat);
 580         EFSYS_ASSERT(smask == encp->enc_phy_stat_mask);
 581 
 582         return (0);
 583 
 584 fail1:
 585         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 586 
 587         return (0);
 588 }
 589 
 590 #endif  /* EFSYS_OPT_PHY_STATS */
 591 
 592 #if EFSYS_OPT_BIST
 593 
 594         __checkReturn           efx_rc_t
 595 siena_phy_bist_start(
 596         __in                    efx_nic_t *enp,
 597         __in                    efx_bist_type_t type)
 598 {
 599         efx_rc_t rc;
 600 
 601         if ((rc = efx_mcdi_bist_start(enp, type)) != 0)
 602                 goto fail1;
 603 
 604         return (0);
 605 
 606 fail1:
 607         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 608 
 609         return (rc);
 610 }
 611 
 612 static  __checkReturn           unsigned long
 613 siena_phy_sft9001_bist_status(
 614         __in                    uint16_t code)
 615 {
 616         switch (code) {
 617         case MC_CMD_POLL_BIST_SFT9001_PAIR_BUSY:
 618                 return (EFX_PHY_CABLE_STATUS_BUSY);
 619         case MC_CMD_POLL_BIST_SFT9001_INTER_PAIR_SHORT:
 620                 return (EFX_PHY_CABLE_STATUS_INTERPAIRSHORT);
 621         case MC_CMD_POLL_BIST_SFT9001_INTRA_PAIR_SHORT:
 622                 return (EFX_PHY_CABLE_STATUS_INTRAPAIRSHORT);
 623         case MC_CMD_POLL_BIST_SFT9001_PAIR_OPEN:
 624                 return (EFX_PHY_CABLE_STATUS_OPEN);
 625         case MC_CMD_POLL_BIST_SFT9001_PAIR_OK:
 626                 return (EFX_PHY_CABLE_STATUS_OK);
 627         default:
 628                 return (EFX_PHY_CABLE_STATUS_INVALID);
 629         }
 630 }
 631 
 632         __checkReturn           efx_rc_t
 633 siena_phy_bist_poll(
 634         __in                    efx_nic_t *enp,
 635         __in                    efx_bist_type_t type,
 636         __out                   efx_bist_result_t *resultp,
 637         __out_opt __drv_when(count > 0, __notnull)
 638         uint32_t *value_maskp,
 639         __out_ecount_opt(count) __drv_when(count > 0, __notnull)
 640         unsigned long *valuesp,
 641         __in                    size_t count)
 642 {
 643         efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 644         uint8_t payload[MAX(MC_CMD_POLL_BIST_IN_LEN,
 645                             MCDI_CTL_SDU_LEN_MAX)];
 646         uint32_t value_mask = 0;
 647         efx_mcdi_req_t req;
 648         uint32_t result;
 649         efx_rc_t rc;
 650 
 651         (void) memset(payload, 0, sizeof (payload));
 652         req.emr_cmd = MC_CMD_POLL_BIST;
 653         req.emr_in_buf = payload;
 654         req.emr_in_length = MC_CMD_POLL_BIST_IN_LEN;
 655         req.emr_out_buf = payload;
 656         req.emr_out_length = MCDI_CTL_SDU_LEN_MAX;
 657 
 658         efx_mcdi_execute(enp, &req);
 659 
 660         if (req.emr_rc != 0) {
 661                 rc = req.emr_rc;
 662                 goto fail1;
 663         }
 664 
 665         if (req.emr_out_length_used < MC_CMD_POLL_BIST_OUT_RESULT_OFST + 4) {
 666                 rc = EMSGSIZE;
 667                 goto fail2;
 668         }
 669 
 670         if (count > 0)
 671                 (void) memset(valuesp, '\0', count * sizeof (unsigned long));
 672 
 673         result = MCDI_OUT_DWORD(req, POLL_BIST_OUT_RESULT);
 674 
 675         /* Extract PHY specific results */
 676         if (result == MC_CMD_POLL_BIST_PASSED &&
 677             encp->enc_phy_type == EFX_PHY_SFT9001B &&
 678             req.emr_out_length_used >= MC_CMD_POLL_BIST_OUT_SFT9001_LEN &&
 679             (type == EFX_BIST_TYPE_PHY_CABLE_SHORT ||
 680             type == EFX_BIST_TYPE_PHY_CABLE_LONG)) {
 681                 uint16_t word;
 682 
 683                 if (count > EFX_BIST_PHY_CABLE_LENGTH_A) {
 684                         if (valuesp != NULL)
 685                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_A] =
 686                                     MCDI_OUT_DWORD(req,
 687                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_A);
 688                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_A);
 689                 }
 690 
 691                 if (count > EFX_BIST_PHY_CABLE_LENGTH_B) {
 692                         if (valuesp != NULL)
 693                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_B] =
 694                                     MCDI_OUT_DWORD(req,
 695                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_B);
 696                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_B);
 697                 }
 698 
 699                 if (count > EFX_BIST_PHY_CABLE_LENGTH_C) {
 700                         if (valuesp != NULL)
 701                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_C] =
 702                                     MCDI_OUT_DWORD(req,
 703                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_C);
 704                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_C);
 705                 }
 706 
 707                 if (count > EFX_BIST_PHY_CABLE_LENGTH_D) {
 708                         if (valuesp != NULL)
 709                                 valuesp[EFX_BIST_PHY_CABLE_LENGTH_D] =
 710                                     MCDI_OUT_DWORD(req,
 711                                     POLL_BIST_OUT_SFT9001_CABLE_LENGTH_D);
 712                         value_mask |= (1 << EFX_BIST_PHY_CABLE_LENGTH_D);
 713                 }
 714 
 715                 if (count > EFX_BIST_PHY_CABLE_STATUS_A) {
 716                         if (valuesp != NULL) {
 717                                 word = MCDI_OUT_WORD(req,
 718                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_A);
 719                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_A] =
 720                                     siena_phy_sft9001_bist_status(word);
 721                         }
 722                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_A);
 723                 }
 724 
 725                 if (count > EFX_BIST_PHY_CABLE_STATUS_B) {
 726                         if (valuesp != NULL) {
 727                                 word = MCDI_OUT_WORD(req,
 728                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_B);
 729                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_B] =
 730                                     siena_phy_sft9001_bist_status(word);
 731                         }
 732                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_B);
 733                 }
 734 
 735                 if (count > EFX_BIST_PHY_CABLE_STATUS_C) {
 736                         if (valuesp != NULL) {
 737                                 word = MCDI_OUT_WORD(req,
 738                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_C);
 739                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_C] =
 740                                     siena_phy_sft9001_bist_status(word);
 741                         }
 742                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_C);
 743                 }
 744 
 745                 if (count > EFX_BIST_PHY_CABLE_STATUS_D) {
 746                         if (valuesp != NULL) {
 747                                 word = MCDI_OUT_WORD(req,
 748                                     POLL_BIST_OUT_SFT9001_CABLE_STATUS_D);
 749                                 valuesp[EFX_BIST_PHY_CABLE_STATUS_D] =
 750                                     siena_phy_sft9001_bist_status(word);
 751                         }
 752                         value_mask |= (1 << EFX_BIST_PHY_CABLE_STATUS_D);
 753                 }
 754 
 755         } else if (result == MC_CMD_POLL_BIST_FAILED &&
 756                     encp->enc_phy_type == EFX_PHY_QLX111V &&
 757                     req.emr_out_length >= MC_CMD_POLL_BIST_OUT_MRSFP_LEN &&
 758                     count > EFX_BIST_FAULT_CODE) {
 759                 if (valuesp != NULL)
 760                         valuesp[EFX_BIST_FAULT_CODE] =
 761                             MCDI_OUT_DWORD(req, POLL_BIST_OUT_MRSFP_TEST);
 762                 value_mask |= 1 << EFX_BIST_FAULT_CODE;
 763         }
 764 
 765         if (value_maskp != NULL)
 766                 *value_maskp = value_mask;
 767 
 768         EFSYS_ASSERT(resultp != NULL);
 769         if (result == MC_CMD_POLL_BIST_RUNNING)
 770                 *resultp = EFX_BIST_RESULT_RUNNING;
 771         else if (result == MC_CMD_POLL_BIST_PASSED)
 772                 *resultp = EFX_BIST_RESULT_PASSED;
 773         else
 774                 *resultp = EFX_BIST_RESULT_FAILED;
 775 
 776         return (0);
 777 
 778 fail2:
 779         EFSYS_PROBE(fail2);
 780 fail1:
 781         EFSYS_PROBE1(fail1, efx_rc_t, rc);
 782 
 783         return (rc);
 784 }
 785 
 786                         void
 787 siena_phy_bist_stop(
 788         __in            efx_nic_t *enp,
 789         __in            efx_bist_type_t type)
 790 {
 791         /* There is no way to stop BIST on Siena */
 792         _NOTE(ARGUNUSED(enp, type))
 793 }
 794 
 795 #endif  /* EFSYS_OPT_BIST */
 796 
 797 #endif  /* EFSYS_OPT_SIENA */