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 #if EFSYS_OPT_MAC_FALCON_GMAC
  35 #include "falcon_gmac.h"
  36 #endif
  37 
  38 #if EFSYS_OPT_MAC_FALCON_XMAC
  39 #include "falcon_xmac.h"
  40 #endif
  41 
  42         __checkReturn   int
  43 falcon_mac_poll(
  44         __in            efx_nic_t *enp,
  45         __out           efx_link_mode_t *link_modep)
  46 {
  47         efx_port_t *epp = &(enp->en_port);
  48         efx_phy_ops_t *epop = epp->ep_epop;
  49         efx_link_mode_t link_mode;
  50         unsigned int fcntl;
  51         uint32_t lp_cap_mask;
  52         boolean_t mac_up = B_TRUE;
  53         boolean_t reconfigure_mac = B_FALSE;
  54         int rc;
  55 
  56         /* Poll PHY for link state changes */
  57         rc = epop->epo_downlink_check(enp, &link_mode, &fcntl, &lp_cap_mask);
  58         if (rc != 0) {
  59                 fcntl = epp->ep_fcntl;
  60                 lp_cap_mask = epp->ep_lp_cap_mask;
  61                 link_mode = EFX_LINK_UNKNOWN;
  62         }
  63 
  64 #if EFSYS_OPT_LOOPBACK
  65         /* Ignore the phy link state in MAC level loopback */
  66         switch (epp->ep_loopback_type) {
  67         case EFX_LOOPBACK_GMAC:
  68                 link_mode = EFX_LINK_1000FDX;
  69                 break;
  70 
  71         case EFX_LOOPBACK_XGMII:
  72         case EFX_LOOPBACK_XGXS:
  73         case EFX_LOOPBACK_XAUI:
  74                 link_mode = EFX_LINK_10000FDX;
  75                 break;
  76 
  77         default:
  78                 break;
  79         }
  80 
  81         if (epp->ep_loopback_type != EFX_LOOPBACK_OFF) {
  82                 /*
  83                  * We've already configured the correct MAC for the correct
  84                  * speed, so all we need to do is wait for the phy loopback
  85                  * to come up. Keep ep_link_mode et al. at the values forced
  86                  * by falcon_mac_loopback_set(), but return the current value
  87                  * of link up vs link down.
  88                  */
  89                 goto poll_mac;
  90         }
  91 #endif
  92 
  93         /* Hook in the correct MAC and reconfigure for the new link speed. */
  94         epp->ep_lp_cap_mask = lp_cap_mask;
  95 
  96         if (link_mode != epp->ep_link_mode) {
  97                 epp->ep_link_mode = link_mode;
  98 
  99                 if ((rc = efx_mac_select(enp)) != 0)
 100                         goto fail1;
 101 
 102                 reconfigure_mac = B_TRUE;
 103         }
 104 
 105         if (fcntl != epp->ep_fcntl) {
 106                 epp->ep_fcntl = fcntl;
 107                 reconfigure_mac = B_TRUE;
 108         }
 109 
 110         if (reconfigure_mac)
 111                 epp->ep_emop->emo_reconfigure(enp);
 112 
 113 #if EFSYS_OPT_LOOPBACK
 114 poll_mac:
 115 #endif
 116         /* The XMAC requires additional polling */
 117         if (epp->ep_mac_type == EFX_MAC_FALCON_XMAC)
 118                 falcon_xmac_poll(enp, &mac_up);
 119         else
 120                 mac_up = B_TRUE;
 121 
 122         epp->ep_mac_up = mac_up;
 123         *link_modep = link_mode;
 124 
 125         return (0);
 126 
 127 fail1:
 128         EFSYS_PROBE1(fail1, int, rc);
 129 
 130         return (rc);
 131 }
 132 
 133         __checkReturn   int
 134 falcon_mac_up(
 135         __in            efx_nic_t *enp,
 136         __out           boolean_t *mac_upp)
 137 {
 138         efx_port_t *epp = &(enp->en_port);
 139 
 140         /* falcon_mac_poll() *must* be run on Falcon */
 141         *mac_upp = epp->ep_mac_up;
 142 
 143         return (0);
 144 }
 145 
 146                         void
 147 falcon_mac_wrapper_enable(
 148         __in            efx_nic_t *enp)
 149 {
 150         efx_port_t *epp = &(enp->en_port);
 151         efx_oword_t oword;
 152         uint32_t speed;
 153         boolean_t drain = epp->ep_mac_drain;
 154 
 155         switch (epp->ep_link_mode) {
 156         case EFX_LINK_100FDX:
 157         case EFX_LINK_100HDX:
 158                 speed = FRF_AB_MAC_SPEED_100M;
 159                 break;
 160 
 161         case EFX_LINK_1000FDX:
 162         case EFX_LINK_1000HDX:
 163                 speed = FRF_AB_MAC_SPEED_1G;
 164                 break;
 165 
 166         case EFX_LINK_10000FDX:
 167                 speed = FRF_AB_MAC_SPEED_10G;
 168                 break;
 169 
 170         default:
 171 #if EFSYS_OPT_LOOPBACK
 172                 EFSYS_ASSERT3U(epp->ep_loopback_type, ==, EFX_LOOPBACK_OFF);
 173 #endif  /* EFSYS_OPT_LOOPBACK */
 174                 drain = B_TRUE;
 175                 speed = FRF_AB_MAC_SPEED_10M;
 176         };
 177 
 178         /* Bring the mac wrapper out of reset and configure it */
 179         switch (epp->ep_mac_type) {
 180         case EFX_MAC_FALCON_GMAC:
 181                 EFX_POPULATE_OWORD_6(oword,
 182                     FRF_AB_MAC_XOFF_VAL, 0xffff,
 183                     FRF_AB_MAC_XG_DISTXCRC, 0,
 184                     FRF_AB_MAC_BCAD_ACPT, (epp->ep_brdcst) ? 1 : 0,
 185                     FRF_AB_MAC_UC_PROM, (epp->ep_unicst) ? 1 : 0,
 186                     FRF_AB_MAC_LINK_STATUS, 1,
 187                     FRF_AB_MAC_SPEED, speed);
 188                 break;
 189 
 190         case EFX_MAC_FALCON_XMAC:
 191                 EFX_POPULATE_OWORD_6(oword,
 192                     FRF_AB_MAC_XOFF_VAL, 0xffff,
 193                     FRF_AB_MAC_XG_DISTXCRC, 0,
 194                     FRF_AB_MAC_BCAD_ACPT, 1,
 195                     FRF_AB_MAC_UC_PROM, 0,
 196                     FRF_AB_MAC_LINK_STATUS, 1,
 197                     FRF_AB_MAC_SPEED, speed);
 198                 break;
 199 
 200         default:
 201                 EFSYS_ASSERT(B_FALSE);
 202                 break;
 203         }
 204 
 205         /* Open TX_DRAIN if the link is up */
 206         if (enp->en_family == EFX_FAMILY_FALCON)
 207                 EFX_SET_OWORD_FIELD(oword, FRF_BB_TXFIFO_DRAIN_EN,
 208                                     drain ? 1 : 0);
 209         EFX_BAR_WRITEO(enp, FR_AB_MAC_CTRL_REG, &oword);
 210 
 211         /* Push multicast hash. Set the broadcast bit (0xff) appropriately */
 212         EFX_BAR_WRITEO(enp, FR_AB_MAC_MC_HASH0_REG,
 213             &(epp->ep_multicst_hash[0]));
 214         memcpy(&oword, &(epp->ep_multicst_hash[1]), sizeof (oword));
 215         if (epp->ep_brdcst)
 216                 EFX_SET_OWORD_BIT(oword, 0x7f);
 217         EFX_BAR_WRITEO(enp, FR_AB_MAC_MC_HASH1_REG, &oword);
 218 
 219         /* Configure RX <-> mac_wrapper link */
 220         EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
 221         EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_XON_TX_TH, 25);
 222         EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_XOFF_TX_TH, 20);
 223         /* Send XON and XOFF at ~3 * max MTU away from empty/full */
 224         EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_XON_MAC_TH, 27648 >> 8);
 225         EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_XOFF_MAC_TH, 54272 >> 8);
 226         EFX_SET_OWORD_FIELD(oword, FRF_AZ_RX_XOFF_MAC_EN,
 227             (epp->ep_fcntl & EFX_FCNTL_GENERATE) ? 1 : 0);
 228 
 229         if (enp->en_family == EFX_FAMILY_FALCON)
 230                 EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, drain ? 0 : 1);
 231 
 232         EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
 233 }
 234 
 235         __checkReturn   int
 236 falcon_mac_wrapper_disable(
 237         __in            efx_nic_t *enp)
 238 {
 239         efx_oword_t oword;
 240         int rc;
 241 
 242         EFX_BAR_READO(enp, FR_AZ_RX_CFG_REG, &oword);
 243         EFX_SET_OWORD_FIELD(oword, FRF_BZ_RX_INGR_EN, 0);
 244         EFX_BAR_WRITEO(enp, FR_AZ_RX_CFG_REG, &oword);
 245 
 246         /* There is no point in draining more than once */
 247         EFX_BAR_READO(enp, FR_AB_MAC_CTRL_REG, &oword);
 248         if (EFX_OWORD_FIELD(oword, FRF_BB_TXFIFO_DRAIN_EN))
 249                 return (0);
 250 
 251         if ((rc = falcon_nic_mac_reset(enp)) != 0)
 252                 goto fail1;
 253 
 254         return (0);
 255 
 256 fail1:
 257         EFSYS_PROBE1(fail1, int, rc);
 258 
 259         return (rc);
 260 }
 261 
 262 #if EFSYS_OPT_LOOPBACK
 263 
 264         __checkReturn   int
 265 falcon_mac_loopback_set(
 266         __in            efx_nic_t *enp,
 267         __in            efx_link_mode_t link_mode,
 268         __in            efx_loopback_type_t loopback_type)
 269 {
 270         efx_port_t *epp = &(enp->en_port);
 271         efx_phy_ops_t *epop = epp->ep_epop;
 272         const efx_nic_cfg_t *encp = &(enp->en_nic_cfg);
 273         efx_loopback_type_t old_loopback_type;
 274         efx_link_mode_t old_loopback_link_mode;
 275         uint32_t phy_loopback_mask;
 276         boolean_t phy_loopback_changed;
 277         int rc;
 278 
 279         EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON);
 280 
 281         old_loopback_type = epp->ep_loopback_type;
 282         old_loopback_link_mode = epp->ep_loopback_link_mode;
 283 
 284         phy_loopback_mask = EFX_LOOPBACK_MASK &
 285                 ~(EFX_LOOPBACK_MAC_MASK | (1 << EFX_LOOPBACK_OFF));
 286         phy_loopback_changed = (phy_loopback_mask &
 287                 ((1 << loopback_type) ^ (1 << epp->ep_loopback_type))) != 0;
 288         epp->ep_loopback_type = loopback_type;
 289         epp->ep_loopback_link_mode = link_mode;
 290 
 291         if (loopback_type == EFX_LOOPBACK_OFF)
 292                 link_mode = EFX_LINK_DOWN;
 293         else if (link_mode == EFX_LINK_UNKNOWN) {
 294                 for (link_mode = EFX_LINK_NMODES - 1;
 295                     link_mode > EFX_LINK_UNKNOWN; --link_mode) {
 296                 if ((1 << loopback_type) &
 297                     encp->enc_loopback_types[link_mode])
 298                         break;
 299                 }
 300         }
 301 
 302         EFSYS_ASSERT(((1 << loopback_type) & ~FALCON_GMAC_LOOPBACK_MASK) ||
 303                         link_mode == EFX_LINK_1000FDX);
 304         EFSYS_ASSERT(((1 << loopback_type) & ~FALCON_XMAC_LOOPBACK_MASK) ||
 305                         link_mode == EFX_LINK_10000FDX);
 306 
 307         /*
 308          * In loopback, a PHY typically requires the correct MAC and link
 309          * to be initialized before they will report link up. Determine
 310          * the expected link speed and select the correct MAC. Ensure that
 311          * ep_link_mode != LINK_DOWN in loopback so that TXDRAIN isn't enabled,
 312          * because we'll never again run efx_mac_select() to subsequently
 313          * reset the EM block.
 314          */
 315         epp->ep_link_mode = link_mode;
 316         if ((rc = efx_mac_select(enp)) != 0)
 317                 goto fail1;
 318 
 319         /*
 320          * Don't reset and reconfigure the PHY unless it's
 321          * configuration has actually changed
 322          */
 323         if (phy_loopback_changed) {
 324                 if ((rc = epop->epo_reset(enp)) != 0)
 325                         goto fail2;
 326 
 327                 EFSYS_ASSERT(enp->en_reset_flags & EFX_RESET_PHY);
 328                 enp->en_reset_flags &= ~EFX_RESET_PHY;
 329 
 330                 if ((rc = epop->epo_reconfigure(enp)) != 0)
 331                         goto fail3;
 332         }
 333 
 334         epp->ep_emop->emo_reconfigure(enp);
 335 
 336         /* Ensure that the MAC is subsequently polled */
 337         epp->ep_mac_poll_needed = B_TRUE;
 338         epp->ep_mac_up = B_FALSE;
 339 
 340         return (0);
 341 
 342 fail3:
 343         EFSYS_PROBE(fail3);
 344 fail2:
 345         EFSYS_PROBE(fail2);
 346 fail1:
 347         EFSYS_PROBE1(fail1, int, rc);
 348 
 349         epp->ep_loopback_type = old_loopback_type;
 350         epp->ep_loopback_link_mode = old_loopback_link_mode;
 351         epp->ep_link_mode = EFX_LINK_DOWN;
 352 
 353         return (rc);
 354 }
 355 
 356 #endif  /* EFSYS_OPT_LOOPBACK */
 357 
 358 #if EFSYS_OPT_MAC_STATS
 359 
 360         __checkReturn                   int
 361 falcon_mac_stats_upload(
 362         __in                            efx_nic_t *enp,
 363         __in                            efsys_mem_t *esmp)
 364 {
 365         efx_oword_t oword;
 366 
 367         EFSYS_ASSERT3U(enp->en_family, ==, EFX_FAMILY_FALCON);
 368 
 369         EFX_POPULATE_OWORD_3(oword,
 370             FRF_AB_MAC_STAT_DMA_ADR_DW0, EFSYS_MEM_ADDR(esmp) & 0xffffffff,
 371             FRF_AB_MAC_STAT_DMA_ADR_DW1, EFSYS_MEM_ADDR(esmp) >> 32,
 372             FRF_AB_MAC_STAT_DMA_CMD, 1);
 373 
 374         EFX_BAR_WRITEO(enp, FR_AB_MAC_STAT_DMA_REG, &oword);
 375 
 376         return (0);
 377 }
 378 
 379 #endif  /* EFSYS_OPT_MAC_STATS */
 380 
 381 #endif  /* EFSYS_OPT_FALCON */