1 /*
   2  * Copyright 2007-2013 Solarflare Communications Inc.  All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  * 1. Redistributions of source code must retain the above copyright
   8  *    notice, this list of conditions and the following disclaimer.
   9  * 2. Redistributions in binary form must reproduce the above copyright
  10  *    notice, this list of conditions and the following disclaimer in the
  11  *    documentation and/or other materials provided with the distribution.
  12  *
  13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS AND
  14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23  * SUCH DAMAGE.
  24  */
  25 
  26 #include "efsys.h"
  27 #include "efx.h"
  28 #include "efx_types.h"
  29 #include "efx_regs.h"
  30 #include "efx_impl.h"
  31 
  32 #if EFSYS_OPT_FALCON
  33 
  34 static  __checkReturn   int
  35 falcon_mdio_wait(
  36         __in            efx_nic_t *enp)
  37 {
  38         efx_oword_t oword;
  39         unsigned int count;
  40         int rc;
  41 
  42         count = 0;
  43         do {
  44                 EFSYS_PROBE1(wait, unsigned int, count);
  45 
  46                 EFX_BAR_READO(enp, FR_AB_MD_STAT_REG, &oword);
  47 
  48                 if (EFX_OWORD_FIELD(oword, FRF_AB_MD_BSY) == 0)
  49                         goto done;
  50 
  51                 /* Spin for 100 us */
  52                 EFSYS_SPIN(100);
  53 
  54         } while (++count < 100);
  55 
  56         rc = ETIMEDOUT;
  57         goto fail1;
  58 
  59 done:
  60         if (EFX_OWORD_FIELD(oword, FRF_AB_MD_LNFL) != 0) {
  61                 rc = EIO;
  62                 goto fail2;
  63         }
  64 
  65         if (EFX_OWORD_FIELD(oword, FRF_AB_MD_BSERR) != 0) {
  66                 rc = EIO;
  67                 goto fail3;
  68         }
  69 
  70         return (0);
  71 
  72 fail3:
  73         EFSYS_PROBE(fail3);
  74 fail2:
  75         EFSYS_PROBE(fail2);
  76 fail1:
  77         EFSYS_PROBE1(fail1, int, rc);
  78 
  79         return (rc);
  80 }
  81 
  82         __checkReturn   int
  83 falcon_mdio_write(
  84         __in            efx_nic_t *enp,
  85         __in            uint8_t port,
  86         __in            uint8_t mmd,
  87         __in            uint16_t reg,
  88         __in            efx_word_t *ewp)
  89 {
  90         int state;
  91         efx_oword_t oword;
  92         uint32_t prtad;
  93         uint32_t devad;
  94         uint32_t addr;
  95         uint16_t val;
  96         int rc;
  97 
  98         EFSYS_LOCK(enp->en_eslp, state);
  99 
 100         /* Check MDIO is not currently being accessed */
 101         if ((rc = falcon_mdio_wait(enp)) != 0)
 102                 goto fail1;
 103 
 104         prtad = port;
 105         devad = mmd;
 106 
 107         /* Write address */
 108         EFX_POPULATE_OWORD_2(oword, FRF_AB_MD_PRT_ADR, prtad,
 109             FRF_AB_MD_DEV_ADR, devad);
 110         EFX_BAR_WRITEO(enp, FR_AB_MD_ID_REG, &oword);
 111 
 112         addr = reg;
 113 
 114         EFX_POPULATE_OWORD_1(oword, FRF_AB_MD_PHY_ADR, addr);
 115         EFX_BAR_WRITEO(enp, FR_AB_MD_PHY_ADR_REG, &oword);
 116 
 117         /* Write data */
 118         val = EFX_WORD_FIELD(*ewp, EFX_WORD_0);
 119 
 120         EFSYS_PROBE4(mdio_write, uint8_t, port, uint8_t, mmd,
 121             uint16_t, reg, uint16_t, val);
 122 
 123         EFX_POPULATE_OWORD_1(oword, FRF_AB_MD_TXD, (uint32_t)val);
 124         EFX_BAR_WRITEO(enp, FR_AB_MD_TXD_REG, &oword);
 125 
 126         /* Select clause 45 write cycle */
 127         EFX_POPULATE_OWORD_2(oword, FRF_AB_MD_WRC, 1, FRF_AB_MD_GC, 0);
 128         EFX_BAR_WRITEO(enp, FR_AB_MD_CS_REG, &oword);
 129 
 130         /* Wait for the cycle to complete */
 131         if ((rc = falcon_mdio_wait(enp)) != 0)
 132                 goto fail2;
 133 
 134         EFSYS_UNLOCK(enp->en_eslp, state);
 135         return (0);
 136 
 137 fail2:
 138         EFSYS_PROBE(fail2);
 139 fail1:
 140         EFSYS_PROBE1(fail1, int, rc);
 141 
 142         EFSYS_UNLOCK(enp->en_eslp, state);
 143         return (rc);
 144 }
 145 
 146         __checkReturn   int
 147 falcon_mdio_read(
 148         __in            efx_nic_t *enp,
 149         __in            uint8_t port,
 150         __in            uint8_t mmd,
 151         __in            uint16_t reg,
 152         __out           efx_word_t *ewp)
 153 {
 154         int state;
 155         efx_oword_t oword;
 156         uint32_t prtad;
 157         uint32_t devad;
 158         uint32_t addr;
 159         uint16_t val;
 160         int rc;
 161 
 162         EFSYS_LOCK(enp->en_eslp, state);
 163 
 164         /* Check MDIO is not currently being accessed */
 165         if ((rc = falcon_mdio_wait(enp)) != 0)
 166                 goto fail1;
 167 
 168         prtad = port;
 169         devad = mmd;
 170 
 171         /* Write address */
 172         EFX_POPULATE_OWORD_2(oword, FRF_AB_MD_PRT_ADR, prtad,
 173             FRF_AB_MD_DEV_ADR, devad);
 174         EFX_BAR_WRITEO(enp, FR_AB_MD_ID_REG, &oword);
 175 
 176         addr = reg;
 177 
 178         EFX_POPULATE_OWORD_1(oword, FRF_AB_MD_PHY_ADR, addr);
 179         EFX_BAR_WRITEO(enp, FR_AB_MD_PHY_ADR_REG, &oword);
 180 
 181         /* Clear the data register */
 182         EFX_SET_OWORD(oword);
 183         EFX_BAR_WRITEO(enp, FR_AB_MD_RXD_REG, &oword);
 184 
 185         /* Select clause 45 read cycle */
 186         EFX_POPULATE_OWORD_2(oword, FRF_AB_MD_RDC, 1, FRF_AB_MD_GC, 0);
 187         EFX_BAR_WRITEO(enp, FR_AB_MD_CS_REG, &oword);
 188 
 189         /* Wait for the cycle to complete */
 190         if ((rc = falcon_mdio_wait(enp)) != 0)
 191                 goto fail2;
 192 
 193         /* Read data */
 194         EFX_BAR_READO(enp, FR_AB_MD_RXD_REG, &oword);
 195         val = (uint16_t)EFX_OWORD_FIELD(oword, FRF_AB_MD_RXD);
 196 
 197         EFSYS_PROBE4(mdio_read, uint8_t, port, uint8_t, mmd,
 198             uint16_t, reg, uint16_t, val);
 199 
 200         EFX_POPULATE_WORD_1(*ewp, EFX_WORD_0, val);
 201 
 202         EFSYS_UNLOCK(enp->en_eslp, state);
 203         return (0);
 204 
 205 fail2:
 206         EFSYS_PROBE(fail2);
 207 fail1:
 208         EFSYS_PROBE1(fail1, int, rc);
 209 
 210         EFSYS_UNLOCK(enp->en_eslp, state);
 211         return (rc);
 212 }
 213 
 214 #endif  /* EFSYS_OPT_FALCON */