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 */