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