diff options
author | Ben Hutchings <bhutchings@solarflare.com> | 2008-04-27 07:55:59 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-04-29 01:42:43 -0400 |
commit | 8ceee660aacb29721e26f08e336c58dc4847d1bd (patch) | |
tree | 158122642e6f21fe85d072c50d6185a0d0cf6834 /drivers/net/sfc/falcon_xmac.c | |
parent | 358c12953b88c5a06a57c33eb27c753b2e7934d1 (diff) |
New driver "sfc" for Solarstorm SFC4000 controller.
The driver supports the 10Xpress PHY and XFP modules on our reference
designs SFE4001 and SFE4002 and the SMC models SMC10GPCIe-XFP and
SMC10GPCIe-10BT.
Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/sfc/falcon_xmac.c')
-rw-r--r-- | drivers/net/sfc/falcon_xmac.c | 585 |
1 files changed, 585 insertions, 0 deletions
diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c new file mode 100644 index 000000000000..aa7521b24a5d --- /dev/null +++ b/drivers/net/sfc/falcon_xmac.c | |||
@@ -0,0 +1,585 @@ | |||
1 | /**************************************************************************** | ||
2 | * Driver for Solarflare Solarstorm network controllers and boards | ||
3 | * Copyright 2005-2006 Fen Systems Ltd. | ||
4 | * Copyright 2006-2008 Solarflare Communications Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms of the GNU General Public License version 2 as published | ||
8 | * by the Free Software Foundation, incorporated herein by reference. | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include "net_driver.h" | ||
13 | #include "efx.h" | ||
14 | #include "falcon.h" | ||
15 | #include "falcon_hwdefs.h" | ||
16 | #include "falcon_io.h" | ||
17 | #include "mac.h" | ||
18 | #include "gmii.h" | ||
19 | #include "mdio_10g.h" | ||
20 | #include "phy.h" | ||
21 | #include "boards.h" | ||
22 | #include "workarounds.h" | ||
23 | |||
24 | /************************************************************************** | ||
25 | * | ||
26 | * MAC register access | ||
27 | * | ||
28 | **************************************************************************/ | ||
29 | |||
30 | /* Offset of an XMAC register within Falcon */ | ||
31 | #define FALCON_XMAC_REG(mac_reg) \ | ||
32 | (FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE)) | ||
33 | |||
34 | void falcon_xmac_writel(struct efx_nic *efx, | ||
35 | efx_dword_t *value, unsigned int mac_reg) | ||
36 | { | ||
37 | efx_oword_t temp; | ||
38 | |||
39 | EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA)); | ||
40 | falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg)); | ||
41 | } | ||
42 | |||
43 | void falcon_xmac_readl(struct efx_nic *efx, | ||
44 | efx_dword_t *value, unsigned int mac_reg) | ||
45 | { | ||
46 | efx_oword_t temp; | ||
47 | |||
48 | falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg)); | ||
49 | EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA)); | ||
50 | } | ||
51 | |||
52 | /************************************************************************** | ||
53 | * | ||
54 | * MAC operations | ||
55 | * | ||
56 | *************************************************************************/ | ||
57 | static int falcon_reset_xmac(struct efx_nic *efx) | ||
58 | { | ||
59 | efx_dword_t reg; | ||
60 | int count; | ||
61 | |||
62 | EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1); | ||
63 | falcon_xmac_writel(efx, ®, XM_GLB_CFG_REG_MAC); | ||
64 | |||
65 | for (count = 0; count < 10000; count++) { /* wait upto 100ms */ | ||
66 | falcon_xmac_readl(efx, ®, XM_GLB_CFG_REG_MAC); | ||
67 | if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0) | ||
68 | return 0; | ||
69 | udelay(10); | ||
70 | } | ||
71 | |||
72 | EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); | ||
73 | return -ETIMEDOUT; | ||
74 | } | ||
75 | |||
76 | /* Configure the XAUI driver that is an output from Falcon */ | ||
77 | static void falcon_setup_xaui(struct efx_nic *efx) | ||
78 | { | ||
79 | efx_dword_t sdctl, txdrv; | ||
80 | |||
81 | /* Move the XAUI into low power, unless there is no PHY, in | ||
82 | * which case the XAUI will have to drive a cable. */ | ||
83 | if (efx->phy_type == PHY_TYPE_NONE) | ||
84 | return; | ||
85 | |||
86 | falcon_xmac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC); | ||
87 | EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT); | ||
88 | EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT); | ||
89 | EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT); | ||
90 | EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT); | ||
91 | EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT); | ||
92 | EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT); | ||
93 | EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT); | ||
94 | EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT); | ||
95 | falcon_xmac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC); | ||
96 | |||
97 | EFX_POPULATE_DWORD_8(txdrv, | ||
98 | XX_DEQD, XX_TXDRV_DEQ_DEFAULT, | ||
99 | XX_DEQC, XX_TXDRV_DEQ_DEFAULT, | ||
100 | XX_DEQB, XX_TXDRV_DEQ_DEFAULT, | ||
101 | XX_DEQA, XX_TXDRV_DEQ_DEFAULT, | ||
102 | XX_DTXD, XX_TXDRV_DTX_DEFAULT, | ||
103 | XX_DTXC, XX_TXDRV_DTX_DEFAULT, | ||
104 | XX_DTXB, XX_TXDRV_DTX_DEFAULT, | ||
105 | XX_DTXA, XX_TXDRV_DTX_DEFAULT); | ||
106 | falcon_xmac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC); | ||
107 | } | ||
108 | |||
109 | static void falcon_hold_xaui_in_rst(struct efx_nic *efx) | ||
110 | { | ||
111 | efx_dword_t reg; | ||
112 | |||
113 | EFX_ZERO_DWORD(reg); | ||
114 | EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1); | ||
115 | EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1); | ||
116 | EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1); | ||
117 | EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1); | ||
118 | EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1); | ||
119 | EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1); | ||
120 | EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1); | ||
121 | EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1); | ||
122 | EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1); | ||
123 | EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1); | ||
124 | EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1); | ||
125 | EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1); | ||
126 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
127 | udelay(10); | ||
128 | } | ||
129 | |||
130 | static int _falcon_reset_xaui_a(struct efx_nic *efx) | ||
131 | { | ||
132 | efx_dword_t reg; | ||
133 | |||
134 | falcon_hold_xaui_in_rst(efx); | ||
135 | falcon_xmac_readl(efx, ®, XX_PWR_RST_REG_MAC); | ||
136 | |||
137 | /* Follow the RAMBUS XAUI data reset sequencing | ||
138 | * Channels A and B first: power down, reset PLL, reset, clear | ||
139 | */ | ||
140 | EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0); | ||
141 | EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0); | ||
142 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
143 | udelay(10); | ||
144 | |||
145 | EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0); | ||
146 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
147 | udelay(10); | ||
148 | |||
149 | EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0); | ||
150 | EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0); | ||
151 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
152 | udelay(10); | ||
153 | |||
154 | /* Channels C and D: power down, reset PLL, reset, clear */ | ||
155 | EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0); | ||
156 | EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0); | ||
157 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
158 | udelay(10); | ||
159 | |||
160 | EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0); | ||
161 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
162 | udelay(10); | ||
163 | |||
164 | EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0); | ||
165 | EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0); | ||
166 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
167 | udelay(10); | ||
168 | |||
169 | /* Setup XAUI */ | ||
170 | falcon_setup_xaui(efx); | ||
171 | udelay(10); | ||
172 | |||
173 | /* Take XGXS out of reset */ | ||
174 | EFX_ZERO_DWORD(reg); | ||
175 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
176 | udelay(10); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int _falcon_reset_xaui_b(struct efx_nic *efx) | ||
182 | { | ||
183 | efx_dword_t reg; | ||
184 | int count; | ||
185 | |||
186 | EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1); | ||
187 | falcon_xmac_writel(efx, ®, XX_PWR_RST_REG_MAC); | ||
188 | |||
189 | /* Give some time for the link to establish */ | ||
190 | for (count = 0; count < 1000; count++) { /* wait upto 10ms */ | ||
191 | falcon_xmac_readl(efx, ®, XX_PWR_RST_REG_MAC); | ||
192 | if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) { | ||
193 | falcon_setup_xaui(efx); | ||
194 | return 0; | ||
195 | } | ||
196 | udelay(10); | ||
197 | } | ||
198 | EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n"); | ||
199 | return -ETIMEDOUT; | ||
200 | } | ||
201 | |||
202 | int falcon_reset_xaui(struct efx_nic *efx) | ||
203 | { | ||
204 | int rc; | ||
205 | |||
206 | if (EFX_WORKAROUND_9388(efx)) { | ||
207 | falcon_hold_xaui_in_rst(efx); | ||
208 | efx->phy_op->reset_xaui(efx); | ||
209 | rc = _falcon_reset_xaui_a(efx); | ||
210 | } else { | ||
211 | rc = _falcon_reset_xaui_b(efx); | ||
212 | } | ||
213 | return rc; | ||
214 | } | ||
215 | |||
216 | static int falcon_xgmii_status(struct efx_nic *efx) | ||
217 | { | ||
218 | efx_dword_t reg; | ||
219 | |||
220 | if (FALCON_REV(efx) < FALCON_REV_B0) | ||
221 | return 1; | ||
222 | |||
223 | /* The ISR latches, so clear it and re-read */ | ||
224 | falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0); | ||
225 | falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0); | ||
226 | |||
227 | if (EFX_DWORD_FIELD(reg, XM_LCLFLT) || | ||
228 | EFX_DWORD_FIELD(reg, XM_RMTFLT)) { | ||
229 | EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg)); | ||
230 | return 0; | ||
231 | } | ||
232 | |||
233 | return 1; | ||
234 | } | ||
235 | |||
236 | static void falcon_mask_status_intr(struct efx_nic *efx, int enable) | ||
237 | { | ||
238 | efx_dword_t reg; | ||
239 | |||
240 | if (FALCON_REV(efx) < FALCON_REV_B0) | ||
241 | return; | ||
242 | |||
243 | /* Flush the ISR */ | ||
244 | if (enable) | ||
245 | falcon_xmac_readl(efx, ®, XM_MGT_INT_REG_MAC_B0); | ||
246 | |||
247 | EFX_POPULATE_DWORD_2(reg, | ||
248 | XM_MSK_RMTFLT, !enable, | ||
249 | XM_MSK_LCLFLT, !enable); | ||
250 | falcon_xmac_writel(efx, ®, XM_MGT_INT_MSK_REG_MAC_B0); | ||
251 | } | ||
252 | |||
253 | int falcon_init_xmac(struct efx_nic *efx) | ||
254 | { | ||
255 | int rc; | ||
256 | |||
257 | /* Initialize the PHY first so the clock is around */ | ||
258 | rc = efx->phy_op->init(efx); | ||
259 | if (rc) | ||
260 | goto fail1; | ||
261 | |||
262 | rc = falcon_reset_xaui(efx); | ||
263 | if (rc) | ||
264 | goto fail2; | ||
265 | |||
266 | /* Wait again. Give the PHY and MAC time to come back */ | ||
267 | schedule_timeout_uninterruptible(HZ / 10); | ||
268 | |||
269 | rc = falcon_reset_xmac(efx); | ||
270 | if (rc) | ||
271 | goto fail2; | ||
272 | |||
273 | falcon_mask_status_intr(efx, 1); | ||
274 | return 0; | ||
275 | |||
276 | fail2: | ||
277 | efx->phy_op->fini(efx); | ||
278 | fail1: | ||
279 | return rc; | ||
280 | } | ||
281 | |||
282 | int falcon_xaui_link_ok(struct efx_nic *efx) | ||
283 | { | ||
284 | efx_dword_t reg; | ||
285 | int align_done, sync_status, link_ok = 0; | ||
286 | |||
287 | /* Read link status */ | ||
288 | falcon_xmac_readl(efx, ®, XX_CORE_STAT_REG_MAC); | ||
289 | |||
290 | align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE); | ||
291 | sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT); | ||
292 | if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED)) | ||
293 | link_ok = 1; | ||
294 | |||
295 | /* Clear link status ready for next read */ | ||
296 | EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET); | ||
297 | EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET); | ||
298 | EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); | ||
299 | falcon_xmac_writel(efx, ®, XX_CORE_STAT_REG_MAC); | ||
300 | |||
301 | /* If the link is up, then check the phy side of the xaui link | ||
302 | * (error conditions from the wire side propoagate back through | ||
303 | * the phy to the xaui side). */ | ||
304 | if (efx->link_up && link_ok) { | ||
305 | int has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS); | ||
306 | if (has_phyxs) | ||
307 | link_ok = mdio_clause45_phyxgxs_lane_sync(efx); | ||
308 | } | ||
309 | |||
310 | /* If the PHY and XAUI links are up, then check the mac's xgmii | ||
311 | * fault state */ | ||
312 | if (efx->link_up && link_ok) | ||
313 | link_ok = falcon_xgmii_status(efx); | ||
314 | |||
315 | return link_ok; | ||
316 | } | ||
317 | |||
318 | static void falcon_reconfigure_xmac_core(struct efx_nic *efx) | ||
319 | { | ||
320 | unsigned int max_frame_len; | ||
321 | efx_dword_t reg; | ||
322 | int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0; | ||
323 | |||
324 | /* Configure MAC - cut-thru mode is hard wired on */ | ||
325 | EFX_POPULATE_DWORD_3(reg, | ||
326 | XM_RX_JUMBO_MODE, 1, | ||
327 | XM_TX_STAT_EN, 1, | ||
328 | XM_RX_STAT_EN, 1); | ||
329 | falcon_xmac_writel(efx, ®, XM_GLB_CFG_REG_MAC); | ||
330 | |||
331 | /* Configure TX */ | ||
332 | EFX_POPULATE_DWORD_6(reg, | ||
333 | XM_TXEN, 1, | ||
334 | XM_TX_PRMBL, 1, | ||
335 | XM_AUTO_PAD, 1, | ||
336 | XM_TXCRC, 1, | ||
337 | XM_FCNTL, 1, | ||
338 | XM_IPG, 0x3); | ||
339 | falcon_xmac_writel(efx, ®, XM_TX_CFG_REG_MAC); | ||
340 | |||
341 | /* Configure RX */ | ||
342 | EFX_POPULATE_DWORD_5(reg, | ||
343 | XM_RXEN, 1, | ||
344 | XM_AUTO_DEPAD, 0, | ||
345 | XM_ACPT_ALL_MCAST, 1, | ||
346 | XM_ACPT_ALL_UCAST, efx->promiscuous, | ||
347 | XM_PASS_CRC_ERR, 1); | ||
348 | falcon_xmac_writel(efx, ®, XM_RX_CFG_REG_MAC); | ||
349 | |||
350 | /* Set frame length */ | ||
351 | max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); | ||
352 | EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len); | ||
353 | falcon_xmac_writel(efx, ®, XM_RX_PARAM_REG_MAC); | ||
354 | EFX_POPULATE_DWORD_2(reg, | ||
355 | XM_MAX_TX_FRM_SIZE, max_frame_len, | ||
356 | XM_TX_JUMBO_MODE, 1); | ||
357 | falcon_xmac_writel(efx, ®, XM_TX_PARAM_REG_MAC); | ||
358 | |||
359 | EFX_POPULATE_DWORD_2(reg, | ||
360 | XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */ | ||
361 | XM_DIS_FCNTL, rx_fc ? 0 : 1); | ||
362 | falcon_xmac_writel(efx, ®, XM_FC_REG_MAC); | ||
363 | |||
364 | /* Set MAC address */ | ||
365 | EFX_POPULATE_DWORD_4(reg, | ||
366 | XM_ADR_0, efx->net_dev->dev_addr[0], | ||
367 | XM_ADR_1, efx->net_dev->dev_addr[1], | ||
368 | XM_ADR_2, efx->net_dev->dev_addr[2], | ||
369 | XM_ADR_3, efx->net_dev->dev_addr[3]); | ||
370 | falcon_xmac_writel(efx, ®, XM_ADR_LO_REG_MAC); | ||
371 | EFX_POPULATE_DWORD_2(reg, | ||
372 | XM_ADR_4, efx->net_dev->dev_addr[4], | ||
373 | XM_ADR_5, efx->net_dev->dev_addr[5]); | ||
374 | falcon_xmac_writel(efx, ®, XM_ADR_HI_REG_MAC); | ||
375 | } | ||
376 | |||
377 | /* Try and bring the Falcon side of the Falcon-Phy XAUI link fails | ||
378 | * to come back up. Bash it until it comes back up */ | ||
379 | static int falcon_check_xaui_link_up(struct efx_nic *efx) | ||
380 | { | ||
381 | int max_tries, tries; | ||
382 | tries = EFX_WORKAROUND_5147(efx) ? 5 : 1; | ||
383 | max_tries = tries; | ||
384 | |||
385 | if (efx->phy_type == PHY_TYPE_NONE) | ||
386 | return 0; | ||
387 | |||
388 | while (tries) { | ||
389 | if (falcon_xaui_link_ok(efx)) | ||
390 | return 1; | ||
391 | |||
392 | EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n", | ||
393 | __func__, tries); | ||
394 | (void) falcon_reset_xaui(efx); | ||
395 | udelay(200); | ||
396 | tries--; | ||
397 | } | ||
398 | |||
399 | EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n", | ||
400 | max_tries); | ||
401 | return 0; | ||
402 | } | ||
403 | |||
404 | void falcon_reconfigure_xmac(struct efx_nic *efx) | ||
405 | { | ||
406 | int xaui_link_ok; | ||
407 | |||
408 | falcon_mask_status_intr(efx, 0); | ||
409 | |||
410 | falcon_deconfigure_mac_wrapper(efx); | ||
411 | efx->phy_op->reconfigure(efx); | ||
412 | falcon_reconfigure_xmac_core(efx); | ||
413 | falcon_reconfigure_mac_wrapper(efx); | ||
414 | |||
415 | /* Ensure XAUI link is up */ | ||
416 | xaui_link_ok = falcon_check_xaui_link_up(efx); | ||
417 | |||
418 | if (xaui_link_ok && efx->link_up) | ||
419 | falcon_mask_status_intr(efx, 1); | ||
420 | } | ||
421 | |||
422 | void falcon_fini_xmac(struct efx_nic *efx) | ||
423 | { | ||
424 | /* Isolate the MAC - PHY */ | ||
425 | falcon_deconfigure_mac_wrapper(efx); | ||
426 | |||
427 | /* Potentially power down the PHY */ | ||
428 | efx->phy_op->fini(efx); | ||
429 | } | ||
430 | |||
431 | void falcon_update_stats_xmac(struct efx_nic *efx) | ||
432 | { | ||
433 | struct efx_mac_stats *mac_stats = &efx->mac_stats; | ||
434 | int rc; | ||
435 | |||
436 | rc = falcon_dma_stats(efx, XgDmaDone_offset); | ||
437 | if (rc) | ||
438 | return; | ||
439 | |||
440 | /* Update MAC stats from DMAed values */ | ||
441 | FALCON_STAT(efx, XgRxOctets, rx_bytes); | ||
442 | FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes); | ||
443 | FALCON_STAT(efx, XgRxPkts, rx_packets); | ||
444 | FALCON_STAT(efx, XgRxPktsOK, rx_good); | ||
445 | FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast); | ||
446 | FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast); | ||
447 | FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast); | ||
448 | FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64); | ||
449 | FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo); | ||
450 | FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo); | ||
451 | FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64); | ||
452 | FALCON_STAT(efx, XgRxDropEvents, rx_overflow); | ||
453 | FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad); | ||
454 | FALCON_STAT(efx, XgRxAlignError, rx_align_error); | ||
455 | FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error); | ||
456 | FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error); | ||
457 | FALCON_STAT(efx, XgRxControlPkts, rx_control); | ||
458 | FALCON_STAT(efx, XgRxPausePkts, rx_pause); | ||
459 | FALCON_STAT(efx, XgRxPkts64Octets, rx_64); | ||
460 | FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127); | ||
461 | FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255); | ||
462 | FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511); | ||
463 | FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023); | ||
464 | FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx); | ||
465 | FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo); | ||
466 | FALCON_STAT(efx, XgRxLengthError, rx_length_error); | ||
467 | FALCON_STAT(efx, XgTxPkts, tx_packets); | ||
468 | FALCON_STAT(efx, XgTxOctets, tx_bytes); | ||
469 | FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast); | ||
470 | FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast); | ||
471 | FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast); | ||
472 | FALCON_STAT(efx, XgTxControlPkts, tx_control); | ||
473 | FALCON_STAT(efx, XgTxPausePkts, tx_pause); | ||
474 | FALCON_STAT(efx, XgTxPkts64Octets, tx_64); | ||
475 | FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127); | ||
476 | FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255); | ||
477 | FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511); | ||
478 | FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023); | ||
479 | FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx); | ||
480 | FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo); | ||
481 | FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64); | ||
482 | FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo); | ||
483 | FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp); | ||
484 | FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error); | ||
485 | FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error); | ||
486 | |||
487 | /* Update derived statistics */ | ||
488 | mac_stats->tx_good_bytes = | ||
489 | (mac_stats->tx_bytes - mac_stats->tx_bad_bytes); | ||
490 | mac_stats->rx_bad_bytes = | ||
491 | (mac_stats->rx_bytes - mac_stats->rx_good_bytes); | ||
492 | } | ||
493 | |||
494 | #define EFX_XAUI_RETRAIN_MAX 8 | ||
495 | |||
496 | int falcon_check_xmac(struct efx_nic *efx) | ||
497 | { | ||
498 | unsigned xaui_link_ok; | ||
499 | int rc; | ||
500 | |||
501 | falcon_mask_status_intr(efx, 0); | ||
502 | xaui_link_ok = falcon_xaui_link_ok(efx); | ||
503 | |||
504 | if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok) | ||
505 | (void) falcon_reset_xaui(efx); | ||
506 | |||
507 | /* Call the PHY check_hw routine */ | ||
508 | rc = efx->phy_op->check_hw(efx); | ||
509 | |||
510 | /* Unmask interrupt if everything was (and still is) ok */ | ||
511 | if (xaui_link_ok && efx->link_up) | ||
512 | falcon_mask_status_intr(efx, 1); | ||
513 | |||
514 | return rc; | ||
515 | } | ||
516 | |||
517 | /* Simulate a PHY event */ | ||
518 | void falcon_xmac_sim_phy_event(struct efx_nic *efx) | ||
519 | { | ||
520 | efx_qword_t phy_event; | ||
521 | |||
522 | EFX_POPULATE_QWORD_2(phy_event, | ||
523 | EV_CODE, GLOBAL_EV_DECODE, | ||
524 | XG_PHY_INTR, 1); | ||
525 | falcon_generate_event(&efx->channel[0], &phy_event); | ||
526 | } | ||
527 | |||
528 | int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) | ||
529 | { | ||
530 | mdio_clause45_get_settings(efx, ecmd); | ||
531 | ecmd->transceiver = XCVR_INTERNAL; | ||
532 | ecmd->phy_address = efx->mii.phy_id; | ||
533 | ecmd->autoneg = AUTONEG_DISABLE; | ||
534 | ecmd->duplex = DUPLEX_FULL; | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) | ||
539 | { | ||
540 | if (ecmd->transceiver != XCVR_INTERNAL) | ||
541 | return -EINVAL; | ||
542 | if (ecmd->autoneg != AUTONEG_DISABLE) | ||
543 | return -EINVAL; | ||
544 | if (ecmd->duplex != DUPLEX_FULL) | ||
545 | return -EINVAL; | ||
546 | |||
547 | return mdio_clause45_set_settings(efx, ecmd); | ||
548 | } | ||
549 | |||
550 | |||
551 | int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control) | ||
552 | { | ||
553 | int reset; | ||
554 | |||
555 | if (flow_control & EFX_FC_AUTO) { | ||
556 | EFX_LOG(efx, "10G does not support flow control " | ||
557 | "autonegotiation\n"); | ||
558 | return -EINVAL; | ||
559 | } | ||
560 | |||
561 | if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX)) | ||
562 | return -EINVAL; | ||
563 | |||
564 | /* TX flow control may automatically turn itself off if the | ||
565 | * link partner (intermittently) stops responding to pause | ||
566 | * frames. There isn't any indication that this has happened, | ||
567 | * so the best we do is leave it up to the user to spot this | ||
568 | * and fix it be cycling transmit flow control on this end. */ | ||
569 | reset = ((flow_control & EFX_FC_TX) && | ||
570 | !(efx->flow_control & EFX_FC_TX)); | ||
571 | if (EFX_WORKAROUND_11482(efx) && reset) { | ||
572 | if (FALCON_REV(efx) >= FALCON_REV_B0) { | ||
573 | /* Recover by resetting the EM block */ | ||
574 | if (efx->link_up) | ||
575 | falcon_drain_tx_fifo(efx); | ||
576 | } else { | ||
577 | /* Schedule a reset to recover */ | ||
578 | efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); | ||
579 | } | ||
580 | } | ||
581 | |||
582 | efx->flow_control = flow_control; | ||
583 | |||
584 | return 0; | ||
585 | } | ||