1 /*
   2  * Copyright 2006-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 
  33 #if EFSYS_OPT_FALCON
  34 
  35 static  __checkReturn   int
  36 xphy_mmd_reset_wait(
  37         __in            efx_nic_t *enp,
  38         __in            uint8_t port,
  39         __in            uint8_t mmd)
  40 {
  41         unsigned int count;
  42         int rc;
  43 
  44         /* The Clause 22 extenion MMD does not implement IEEE registers */
  45         if (mmd == CL22EXT_MMD) {
  46                 rc = ENOTSUP;
  47                 goto fail1;
  48         }
  49 
  50         count = 0;
  51         do {
  52                 efx_word_t word;
  53 
  54                 EFSYS_PROBE1(wait, unsigned int, count);
  55 
  56                 /* Sleep for 100 ms */
  57                 EFSYS_SLEEP(100000);
  58 
  59                 /* Read control 1 register and check reset state */
  60                 if ((rc = falcon_mdio_read(enp, port, mmd,
  61                     MMD_CONTROL1_REG, &word)) != 0)
  62                         goto fail2;
  63 
  64                 if (EFX_WORD_FIELD(word, MMD_RESET) == 0)
  65                         goto done;
  66 
  67         } while (++count < 100);
  68 
  69         rc = ETIMEDOUT;
  70         goto fail3;
  71 
  72 done:
  73         return (0);
  74 
  75 fail3:
  76         EFSYS_PROBE(fail3);
  77 fail2:
  78         EFSYS_PROBE(fail2);
  79 fail1:
  80         EFSYS_PROBE1(fail1, int, rc);
  81 
  82         return (rc);
  83 }
  84 
  85         __checkReturn   int
  86 xphy_pkg_wait(
  87         __in            efx_nic_t *enp,
  88         __in            uint8_t port,
  89         __in            uint32_t mask)
  90 {
  91         uint8_t mmd;
  92         int rc;
  93 
  94         for (mmd = 0; mmd <= MAXMMD; mmd++) {
  95                 /* Only check MMDs in the mask */
  96                 if (((1 << mmd) & mask) == 0)
  97                         continue;
  98 
  99                 /*
 100                  * The Clause 22 extenion MMD does not implement IEEE
 101                  * registers.
 102                  */
 103                 if (mmd == CL22EXT_MMD)
 104                         continue;
 105 
 106                 /* Wait for the MMD to come out of reset */
 107                 if ((rc = xphy_mmd_reset_wait(enp, port, mmd)) != 0)
 108                         goto fail1;
 109         }
 110 
 111         return (0);
 112 
 113 fail1:
 114         EFSYS_PROBE1(fail1, int, rc);
 115 
 116         return (rc);
 117 }
 118 
 119         __checkReturn   int
 120 xphy_pkg_verify(
 121         __in            efx_nic_t *enp,
 122         __in            uint8_t port,
 123         __in            uint32_t mask)
 124 {
 125         uint8_t mmd;
 126         efx_word_t word;
 127         int rc;
 128 
 129         /* Find the first MMD */
 130         for (mmd = 0; mmd <= MAXMMD; mmd++) {
 131                 uint32_t devices;
 132 
 133                 if (((1 << mmd) & mask) == 0)
 134                         continue;
 135 
 136                 /*
 137                  * The Clause 22 extenion MMD does not implement IEEE
 138                  * registers.
 139                  */
 140                 if (mmd == CL22EXT_MMD)
 141                         continue;
 142 
 143                 if ((rc = falcon_mdio_read(enp, port, mmd,
 144                     MMD_DEVICES2_REG, &word)) != 0)
 145                         goto fail1;
 146 
 147                 devices = (uint32_t)EFX_WORD_FIELD(word, EFX_WORD_0) << 16;
 148 
 149                 if ((rc = falcon_mdio_read(enp, port, mmd,
 150                     MMD_DEVICES1_REG, &word)) != 0)
 151                         goto fail2;
 152 
 153                 devices |= (uint32_t)EFX_WORD_FIELD(word, EFX_WORD_0);
 154 
 155                 EFSYS_PROBE1(devices, uint32_t, devices);
 156 
 157                 /* Check that all the specified MMDs are present */
 158                 if ((devices & mask) != mask) {
 159                         rc = EFAULT;
 160                         goto fail3;
 161                 }
 162 
 163                 goto done;
 164         }
 165 
 166         rc = ENODEV;
 167         goto fail4;
 168 
 169 done:
 170         for (mmd = 0; mmd <= MAXMMD; mmd++) {
 171                 /* Only check MMDs in the mask */
 172                 if (((1 << mmd) & mask) == 0)
 173                         continue;
 174 
 175                 /*
 176                  * The Clause 22 extenion MMD does not implement IEEE
 177                  * registers.
 178                  */
 179                 if (mmd == CL22EXT_MMD)
 180                         continue;
 181 
 182                 /* Check the MMD is responding */
 183                 if ((rc = falcon_mdio_read(enp, port, mmd,
 184                     MMD_STATUS2_REG, &word)) != 0)
 185                         goto fail5;
 186 
 187                 if (EFX_WORD_FIELD(word, MMD_RESPONDING) !=
 188                     MMD_RESPONDING_DECODE)
 189                         goto fail6;
 190 
 191         }
 192 
 193         return (0);
 194 
 195 fail6:
 196         EFSYS_PROBE(fail6);
 197 fail5:
 198         EFSYS_PROBE(fail5);
 199 fail4:
 200         EFSYS_PROBE(fail4);
 201 fail3:
 202         EFSYS_PROBE(fail3);
 203 fail2:
 204         EFSYS_PROBE(fail2);
 205 fail1:
 206         EFSYS_PROBE1(fail1, int, rc);
 207 
 208         return (rc);
 209 }
 210 
 211         __checkReturn   int
 212 xphy_mmd_oui_get(
 213         __in            efx_nic_t *enp,
 214         __in            uint8_t port,
 215         __in            uint8_t mmd,
 216         __out           uint32_t *ouip)
 217 {
 218         efx_word_t word;
 219         int rc;
 220 
 221         /* The Clause 22 extenion MMD does not implement IEEE registers */
 222         if (mmd == CL22EXT_MMD) {
 223                 rc = ENOTSUP;
 224                 goto fail1;
 225         }
 226 
 227         if ((rc = falcon_mdio_read(enp, port, mmd, MMD_IDH_REG,
 228             &word)) != 0)
 229                 goto fail2;
 230 
 231         *ouip = (uint32_t)EFX_WORD_FIELD(word, MMD_IDH) << 16;
 232 
 233         if ((rc = falcon_mdio_read(enp, port, mmd, MMD_IDL_REG,
 234             &word)) != 0)
 235                 goto fail3;
 236 
 237         *ouip |= (uint32_t)EFX_WORD_FIELD(word, MMD_IDL) & 0x0000ffff;
 238 
 239         return (0);
 240 
 241 fail3:
 242         EFSYS_PROBE(fail3);
 243 fail2:
 244         EFSYS_PROBE(fail2);
 245 fail1:
 246         EFSYS_PROBE1(fail1, int, rc);
 247 
 248         return (rc);
 249 }
 250 
 251         __checkReturn   int
 252 xphy_mmd_check(
 253         __in            efx_nic_t *enp,
 254         __in            uint8_t port,
 255         __in            uint8_t mmd,
 256         __out           boolean_t *upp)
 257 {
 258         efx_word_t word;
 259         int rc;
 260 
 261         /* Reset the latched status and fault flags */
 262         if ((rc = falcon_mdio_read(enp, port, mmd, MMD_STATUS1_REG,
 263             &word)) != 0)
 264                 goto fail1;
 265 
 266         if (mmd == PMA_PMD_MMD || mmd == PCS_MMD || mmd == PHY_XS_MMD) {
 267                 if ((rc = falcon_mdio_read(enp, port, mmd,
 268                     MMD_STATUS2_REG, &word)) != 0)
 269                         goto fail2;
 270         }
 271 
 272         /* Check the current status and fault flags */
 273         if ((rc = falcon_mdio_read(enp, port, mmd, MMD_STATUS1_REG,
 274             &word)) != 0)
 275                 goto fail3;
 276 
 277         *upp = (EFX_WORD_FIELD(word, MMD_LINK_UP) != 0 &&
 278                 EFX_WORD_FIELD(word, MMD_FAULT) == 0);
 279 
 280         return (0);
 281 
 282 fail3:
 283         EFSYS_PROBE(fail3);
 284 fail2:
 285         EFSYS_PROBE(fail2);
 286 fail1:
 287         EFSYS_PROBE1(fail1, int, rc);
 288 
 289         return (rc);
 290 }
 291 
 292         __checkReturn   int
 293 xphy_mmd_fault(
 294         __in            efx_nic_t *enp,
 295         __in            uint8_t port,
 296         __out           boolean_t *upp)
 297 {
 298         efx_word_t word;
 299         int rc;
 300 
 301         if ((rc = falcon_mdio_read(enp, port, PHY_XS_MMD,
 302             MMD_STATUS2_REG, &word)) != 0)
 303                 goto fail1;
 304 
 305         *upp = (EFX_WORD_FIELD(word, MMD_RX_FAULT) == 0);
 306 
 307         return (0);
 308 
 309 fail1:
 310         EFSYS_PROBE1(fail1, int, rc);
 311 
 312         return (rc);
 313 }
 314 
 315         __checkReturn   int
 316 xphy_mmd_loopback_set(
 317         __in            efx_nic_t *enp,
 318         __in            uint8_t port,
 319         __in            uint8_t mmd,
 320         __in            boolean_t on)
 321 {
 322         efx_word_t word;
 323         int rc;
 324 
 325         /* The Clause 22 extenion MMD does not implement IEEE registers */
 326         if (mmd == CL22EXT_MMD) {
 327                 rc = ENOTSUP;
 328                 goto fail1;
 329         }
 330 
 331         if ((rc = falcon_mdio_read(enp, port, mmd, MMD_CONTROL1_REG,
 332             &word)) != 0)
 333                 goto fail2;
 334 
 335         if (mmd == PMA_PMD_MMD)
 336                 EFX_SET_WORD_FIELD(word, MMD_PMA_LOOPBACK, (on) ? 1 : 0);
 337         else
 338                 EFX_SET_WORD_FIELD(word, MMD_LOOPBACK, (on) ? 1 : 0);
 339 
 340         if ((rc = falcon_mdio_write(enp, port, mmd, MMD_CONTROL1_REG,
 341             &word)) != 0)
 342                 goto fail3;
 343 
 344         return (0);
 345 
 346 fail3:
 347         EFSYS_PROBE(fail3);
 348 fail2:
 349         EFSYS_PROBE(fail2);
 350 fail1:
 351         EFSYS_PROBE1(fail1, int, rc);
 352 
 353         return (rc);
 354 }
 355 
 356 #endif  /* EFSYS_OPT_FALCON */