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