sfc: Gather link state fields in struct efx_nic into new struct efx_link_state
[linux-2.6-block.git] / drivers / net / sfc / falcon_xmac.c
CommitLineData
8ceee660
BH
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"
3e6c4538 15#include "regs.h"
12d00cad 16#include "io.h"
8ceee660 17#include "mac.h"
8ceee660
BH
18#include "mdio_10g.h"
19#include "phy.h"
8ceee660
BH
20#include "workarounds.h"
21
8ceee660
BH
22/**************************************************************************
23 *
24 * MAC operations
25 *
26 *************************************************************************/
8ceee660
BH
27
28/* Configure the XAUI driver that is an output from Falcon */
29static void falcon_setup_xaui(struct efx_nic *efx)
30{
c1e5fcc9 31 efx_oword_t sdctl, txdrv;
8ceee660
BH
32
33 /* Move the XAUI into low power, unless there is no PHY, in
34 * which case the XAUI will have to drive a cable. */
35 if (efx->phy_type == PHY_TYPE_NONE)
36 return;
37
12d00cad 38 efx_reado(efx, &sdctl, FR_AB_XX_SD_CTL);
3e6c4538
BH
39 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
40 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
41 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
42 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
43 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
44 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
45 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
46 EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
12d00cad 47 efx_writeo(efx, &sdctl, FR_AB_XX_SD_CTL);
c1e5fcc9
BH
48
49 EFX_POPULATE_OWORD_8(txdrv,
3e6c4538
BH
50 FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF,
51 FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF,
52 FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF,
53 FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF,
54 FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF,
55 FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF,
56 FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF,
57 FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF);
12d00cad 58 efx_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL);
8ceee660
BH
59}
60
ef08af03 61int falcon_reset_xaui(struct efx_nic *efx)
8ceee660 62{
c1e5fcc9 63 efx_oword_t reg;
8ceee660
BH
64 int count;
65
d4ec09ac 66 /* Start reset sequence */
3e6c4538 67 EFX_POPULATE_DWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
12d00cad 68 efx_writeo(efx, &reg, FR_AB_XX_PWR_RST);
8ceee660 69
d4ec09ac
BH
70 /* Wait up to 10 ms for completion, then reinitialise */
71 for (count = 0; count < 1000; count++) {
12d00cad 72 efx_reado(efx, &reg, FR_AB_XX_PWR_RST);
3e6c4538
BH
73 if (EFX_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 &&
74 EFX_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) {
8ceee660
BH
75 falcon_setup_xaui(efx);
76 return 0;
77 }
78 udelay(10);
79 }
80 EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
81 return -ETIMEDOUT;
82}
83
177dfcd8 84static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
8ceee660 85{
c1e5fcc9 86 efx_oword_t reg;
8ceee660 87
177dfcd8
BH
88 if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
89 return;
8ceee660 90
177dfcd8 91 /* We expect xgmii faults if the wireside link is up */
eb50c0d6 92 if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up)
177dfcd8 93 return;
8ceee660 94
177dfcd8
BH
95 /* We can only use this interrupt to signal the negative edge of
96 * xaui_align [we have to poll the positive edge]. */
97 if (!efx->mac_up)
8ceee660
BH
98 return;
99
100 /* Flush the ISR */
101 if (enable)
12d00cad 102 efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
8ceee660 103
c1e5fcc9 104 EFX_POPULATE_OWORD_2(reg,
3e6c4538
BH
105 FRF_AB_XM_MSK_RMTFLT, !enable,
106 FRF_AB_XM_MSK_LCLFLT, !enable);
12d00cad 107 efx_writeo(efx, &reg, FR_AB_XM_MGT_INT_MASK);
8ceee660
BH
108}
109
177dfcd8 110/* Get status of XAUI link */
dc8cfa55 111bool falcon_xaui_link_ok(struct efx_nic *efx)
8ceee660 112{
c1e5fcc9 113 efx_oword_t reg;
dc8cfa55
BH
114 bool align_done, link_ok = false;
115 int sync_status;
8ceee660 116
3273c2e8 117 if (LOOPBACK_INTERNAL(efx))
dc8cfa55 118 return true;
3273c2e8 119
8ceee660 120 /* Read link status */
12d00cad 121 efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
8ceee660 122
3e6c4538
BH
123 align_done = EFX_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE);
124 sync_status = EFX_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT);
125 if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES))
dc8cfa55 126 link_ok = true;
8ceee660
BH
127
128 /* Clear link status ready for next read */
3e6c4538
BH
129 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES);
130 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES);
131 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES);
12d00cad 132 efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
8ceee660 133
177dfcd8 134 /* If the link is up, then check the phy side of the xaui link */
eb50c0d6 135 if (efx->link_state.up && link_ok)
dc8cfa55 136 if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
68e7f45e 137 link_ok = efx_mdio_phyxgxs_lane_sync(efx);
8ceee660
BH
138
139 return link_ok;
140}
141
142static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
143{
144 unsigned int max_frame_len;
c1e5fcc9 145 efx_oword_t reg;
eb50c0d6 146 bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX);
8ceee660
BH
147
148 /* Configure MAC - cut-thru mode is hard wired on */
149 EFX_POPULATE_DWORD_3(reg,
3e6c4538
BH
150 FRF_AB_XM_RX_JUMBO_MODE, 1,
151 FRF_AB_XM_TX_STAT_EN, 1,
152 FRF_AB_XM_RX_STAT_EN, 1);
12d00cad 153 efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
8ceee660
BH
154
155 /* Configure TX */
156 EFX_POPULATE_DWORD_6(reg,
3e6c4538
BH
157 FRF_AB_XM_TXEN, 1,
158 FRF_AB_XM_TX_PRMBL, 1,
159 FRF_AB_XM_AUTO_PAD, 1,
160 FRF_AB_XM_TXCRC, 1,
161 FRF_AB_XM_FCNTL, 1,
162 FRF_AB_XM_IPG, 0x3);
12d00cad 163 efx_writeo(efx, &reg, FR_AB_XM_TX_CFG);
8ceee660
BH
164
165 /* Configure RX */
166 EFX_POPULATE_DWORD_5(reg,
3e6c4538
BH
167 FRF_AB_XM_RXEN, 1,
168 FRF_AB_XM_AUTO_DEPAD, 0,
169 FRF_AB_XM_ACPT_ALL_MCAST, 1,
170 FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous,
171 FRF_AB_XM_PASS_CRC_ERR, 1);
12d00cad 172 efx_writeo(efx, &reg, FR_AB_XM_RX_CFG);
8ceee660
BH
173
174 /* Set frame length */
175 max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
3e6c4538 176 EFX_POPULATE_DWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len);
12d00cad 177 efx_writeo(efx, &reg, FR_AB_XM_RX_PARAM);
8ceee660 178 EFX_POPULATE_DWORD_2(reg,
3e6c4538
BH
179 FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len,
180 FRF_AB_XM_TX_JUMBO_MODE, 1);
12d00cad 181 efx_writeo(efx, &reg, FR_AB_XM_TX_PARAM);
8ceee660
BH
182
183 EFX_POPULATE_DWORD_2(reg,
3e6c4538
BH
184 FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
185 FRF_AB_XM_DIS_FCNTL, !rx_fc);
12d00cad 186 efx_writeo(efx, &reg, FR_AB_XM_FC);
8ceee660
BH
187
188 /* Set MAC address */
3e6c4538 189 memcpy(&reg, &efx->net_dev->dev_addr[0], 4);
12d00cad 190 efx_writeo(efx, &reg, FR_AB_XM_ADR_LO);
3e6c4538 191 memcpy(&reg, &efx->net_dev->dev_addr[4], 2);
12d00cad 192 efx_writeo(efx, &reg, FR_AB_XM_ADR_HI);
8ceee660
BH
193}
194
3273c2e8
BH
195static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
196{
c1e5fcc9 197 efx_oword_t reg;
dc8cfa55
BH
198 bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS);
199 bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI);
200 bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII);
3273c2e8
BH
201
202 /* XGXS block is flaky and will need to be reset if moving
203 * into our out of XGMII, XGXS or XAUI loopbacks. */
204 if (EFX_WORKAROUND_5147(efx)) {
dc8cfa55
BH
205 bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
206 bool reset_xgxs;
3273c2e8 207
12d00cad 208 efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
3e6c4538
BH
209 old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN);
210 old_xgmii_loopback =
211 EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN);
3273c2e8 212
12d00cad 213 efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
3e6c4538 214 old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA);
3273c2e8
BH
215
216 /* The PHY driver may have turned XAUI off */
217 reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
218 (xaui_loopback != old_xaui_loopback) ||
219 (xgmii_loopback != old_xgmii_loopback));
8c8661e4
BH
220
221 if (reset_xgxs)
222 falcon_reset_xaui(efx);
3273c2e8
BH
223 }
224
12d00cad 225 efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
3e6c4538 226 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG,
3273c2e8 227 (xgxs_loopback || xaui_loopback) ?
3e6c4538
BH
228 FFE_AB_XX_FORCE_SIG_ALL_LANES : 0);
229 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback);
230 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback);
12d00cad 231 efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
3e6c4538 232
12d00cad 233 efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
3e6c4538
BH
234 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback);
235 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback);
236 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback);
237 EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback);
12d00cad 238 efx_writeo(efx, &reg, FR_AB_XX_SD_CTL);
3273c2e8
BH
239}
240
241
8ceee660
BH
242/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
243 * to come back up. Bash it until it comes back up */
177dfcd8 244static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
8ceee660 245{
177dfcd8 246 efx->mac_up = falcon_xaui_link_ok(efx);
8ceee660 247
3273c2e8 248 if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
f8b87c17 249 efx_phy_mode_disabled(efx->phy_mode))
177dfcd8
BH
250 /* XAUI link is expected to be down */
251 return;
8ceee660 252
177dfcd8
BH
253 while (!efx->mac_up && tries) {
254 EFX_LOG(efx, "bashing xaui\n");
91ad757c 255 falcon_reset_xaui(efx);
8ceee660 256 udelay(200);
8ceee660 257
177dfcd8
BH
258 efx->mac_up = falcon_xaui_link_ok(efx);
259 --tries;
260 }
8ceee660
BH
261}
262
177dfcd8 263static void falcon_reconfigure_xmac(struct efx_nic *efx)
8ceee660 264{
dc8cfa55 265 falcon_mask_status_intr(efx, false);
8ceee660 266
3273c2e8 267 falcon_reconfigure_xgxs_core(efx);
8ceee660 268 falcon_reconfigure_xmac_core(efx);
3273c2e8 269
8ceee660
BH
270 falcon_reconfigure_mac_wrapper(efx);
271
177dfcd8
BH
272 falcon_check_xaui_link_up(efx, 5);
273 falcon_mask_status_intr(efx, true);
8ceee660
BH
274}
275
177dfcd8 276static void falcon_update_stats_xmac(struct efx_nic *efx)
8ceee660
BH
277{
278 struct efx_mac_stats *mac_stats = &efx->mac_stats;
279 int rc;
280
281 rc = falcon_dma_stats(efx, XgDmaDone_offset);
282 if (rc)
283 return;
284
285 /* Update MAC stats from DMAed values */
286 FALCON_STAT(efx, XgRxOctets, rx_bytes);
287 FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes);
288 FALCON_STAT(efx, XgRxPkts, rx_packets);
289 FALCON_STAT(efx, XgRxPktsOK, rx_good);
290 FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast);
291 FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast);
292 FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast);
293 FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64);
294 FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo);
295 FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo);
296 FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64);
297 FALCON_STAT(efx, XgRxDropEvents, rx_overflow);
298 FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad);
299 FALCON_STAT(efx, XgRxAlignError, rx_align_error);
300 FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error);
301 FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error);
302 FALCON_STAT(efx, XgRxControlPkts, rx_control);
303 FALCON_STAT(efx, XgRxPausePkts, rx_pause);
304 FALCON_STAT(efx, XgRxPkts64Octets, rx_64);
305 FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127);
306 FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255);
307 FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511);
308 FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023);
309 FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx);
310 FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo);
311 FALCON_STAT(efx, XgRxLengthError, rx_length_error);
312 FALCON_STAT(efx, XgTxPkts, tx_packets);
313 FALCON_STAT(efx, XgTxOctets, tx_bytes);
314 FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast);
315 FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast);
316 FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast);
317 FALCON_STAT(efx, XgTxControlPkts, tx_control);
318 FALCON_STAT(efx, XgTxPausePkts, tx_pause);
319 FALCON_STAT(efx, XgTxPkts64Octets, tx_64);
320 FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127);
321 FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255);
322 FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511);
323 FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023);
324 FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx);
325 FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo);
326 FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64);
327 FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo);
328 FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp);
329 FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error);
330 FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);
331
332 /* Update derived statistics */
333 mac_stats->tx_good_bytes =
c264361d
BH
334 (mac_stats->tx_bytes - mac_stats->tx_bad_bytes -
335 mac_stats->tx_control * 64);
8ceee660 336 mac_stats->rx_bad_bytes =
c264361d
BH
337 (mac_stats->rx_bytes - mac_stats->rx_good_bytes -
338 mac_stats->rx_control * 64);
8ceee660
BH
339}
340
766ca0fa 341static void falcon_xmac_irq(struct efx_nic *efx)
8ceee660 342{
766ca0fa
BH
343 /* The XGMII link has a transient fault, which indicates either:
344 * - there's a transient xgmii fault
345 * - falcon's end of the xaui link may need a kick
346 * - the wire-side link may have gone down, but the lasi/poll()
347 * hasn't noticed yet.
348 *
349 * We only want to even bother polling XAUI if we're confident it's
350 * not (1) or (3). In both cases, the only reliable way to spot this
351 * is to wait a bit. We do this here by forcing the mac link state
352 * to down, and waiting for the mac poll to come round and check
353 */
354 efx->mac_up = false;
355}
8ceee660 356
766ca0fa
BH
357static void falcon_poll_xmac(struct efx_nic *efx)
358{
eb50c0d6 359 if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up || efx->mac_up)
766ca0fa 360 return;
3273c2e8 361
dc8cfa55 362 falcon_mask_status_intr(efx, false);
766ca0fa
BH
363 falcon_check_xaui_link_up(efx, 1);
364 falcon_mask_status_intr(efx, true);
8ceee660
BH
365}
366
177dfcd8
BH
367struct efx_mac_operations falcon_xmac_operations = {
368 .reconfigure = falcon_reconfigure_xmac,
369 .update_stats = falcon_update_stats_xmac,
766ca0fa
BH
370 .irq = falcon_xmac_irq,
371 .poll = falcon_poll_xmac,
177dfcd8 372};