falcon_xmac.c 12.0 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14
/****************************************************************************
 * Driver for Solarflare Solarstorm network controllers and boards
 * Copyright 2005-2006 Fen Systems Ltd.
 * Copyright 2006-2008 Solarflare Communications Inc.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation, incorporated herein by reference.
 */

#include <linux/delay.h>
#include "net_driver.h"
#include "efx.h"
#include "falcon.h"
15
#include "regs.h"
16
#include "io.h"
17 18 19 20 21 22 23 24 25 26 27 28 29 30
#include "mac.h"
#include "mdio_10g.h"
#include "phy.h"
#include "workarounds.h"

/**************************************************************************
 *
 * MAC operations
 *
 *************************************************************************/

/* Configure the XAUI driver that is an output from Falcon */
static void falcon_setup_xaui(struct efx_nic *efx)
{
31
	efx_oword_t sdctl, txdrv;
32 33 34 35 36 37

	/* Move the XAUI into low power, unless there is no PHY, in
	 * which case the XAUI will have to drive a cable. */
	if (efx->phy_type == PHY_TYPE_NONE)
		return;

38
	efx_reado(efx, &sdctl, FR_AB_XX_SD_CTL);
39 40 41 42 43 44 45 46
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVD, FFE_AB_XX_SD_CTL_DRV_DEF);
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVC, FFE_AB_XX_SD_CTL_DRV_DEF);
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVB, FFE_AB_XX_SD_CTL_DRV_DEF);
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_HIDRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
	EFX_SET_OWORD_FIELD(sdctl, FRF_AB_XX_LODRVA, FFE_AB_XX_SD_CTL_DRV_DEF);
47
	efx_writeo(efx, &sdctl, FR_AB_XX_SD_CTL);
48 49

	EFX_POPULATE_OWORD_8(txdrv,
50 51 52 53 54 55 56 57
			     FRF_AB_XX_DEQD, FFE_AB_XX_TXDRV_DEQ_DEF,
			     FRF_AB_XX_DEQC, FFE_AB_XX_TXDRV_DEQ_DEF,
			     FRF_AB_XX_DEQB, FFE_AB_XX_TXDRV_DEQ_DEF,
			     FRF_AB_XX_DEQA, FFE_AB_XX_TXDRV_DEQ_DEF,
			     FRF_AB_XX_DTXD, FFE_AB_XX_TXDRV_DTX_DEF,
			     FRF_AB_XX_DTXC, FFE_AB_XX_TXDRV_DTX_DEF,
			     FRF_AB_XX_DTXB, FFE_AB_XX_TXDRV_DTX_DEF,
			     FRF_AB_XX_DTXA, FFE_AB_XX_TXDRV_DTX_DEF);
58
	efx_writeo(efx, &txdrv, FR_AB_XX_TXDRV_CTL);
59 60
}

61
int falcon_reset_xaui(struct efx_nic *efx)
62
{
63
	struct falcon_nic_data *nic_data = efx->nic_data;
64
	efx_oword_t reg;
65 66
	int count;

67 68 69
	/* Don't fetch MAC statistics over an XMAC reset */
	WARN_ON(nic_data->stats_disable_count == 0);

70
	/* Start reset sequence */
71
	EFX_POPULATE_OWORD_1(reg, FRF_AB_XX_RST_XX_EN, 1);
72
	efx_writeo(efx, &reg, FR_AB_XX_PWR_RST);
73

74 75
	/* Wait up to 10 ms for completion, then reinitialise */
	for (count = 0; count < 1000; count++) {
76
		efx_reado(efx, &reg, FR_AB_XX_PWR_RST);
77 78
		if (EFX_OWORD_FIELD(reg, FRF_AB_XX_RST_XX_EN) == 0 &&
		    EFX_OWORD_FIELD(reg, FRF_AB_XX_SD_RST_ACT) == 0) {
79 80 81 82 83 84 85 86 87
			falcon_setup_xaui(efx);
			return 0;
		}
		udelay(10);
	}
	EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
	return -ETIMEDOUT;
}

88
static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
89
{
90
	efx_oword_t reg;
91

92
	if ((efx_nic_rev(efx) != EFX_REV_FALCON_B0) || LOOPBACK_INTERNAL(efx))
93
		return;
94

95
	/* We expect xgmii faults if the wireside link is up */
96
	if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up)
97
		return;
98

99 100
	/* We can only use this interrupt to signal the negative edge of
	 * xaui_align [we have to poll the positive edge]. */
B
Ben Hutchings 已提交
101
	if (efx->xmac_poll_required)
102 103 104 105
		return;

	/* Flush the ISR */
	if (enable)
106
		efx_reado(efx, &reg, FR_AB_XM_MGT_INT_MSK);
107

108
	EFX_POPULATE_OWORD_2(reg,
109 110
			     FRF_AB_XM_MSK_RMTFLT, !enable,
			     FRF_AB_XM_MSK_LCLFLT, !enable);
111
	efx_writeo(efx, &reg, FR_AB_XM_MGT_INT_MASK);
112 113
}

114
/* Get status of XAUI link */
B
Ben Hutchings 已提交
115
static bool falcon_xaui_link_ok(struct efx_nic *efx)
116
{
117
	efx_oword_t reg;
118 119
	bool align_done, link_ok = false;
	int sync_status;
120

121
	if (LOOPBACK_INTERNAL(efx))
122
		return true;
123

124
	/* Read link status */
125
	efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
126

127 128 129
	align_done = EFX_OWORD_FIELD(reg, FRF_AB_XX_ALIGN_DONE);
	sync_status = EFX_OWORD_FIELD(reg, FRF_AB_XX_SYNC_STAT);
	if (align_done && (sync_status == FFE_AB_XX_STAT_ALL_LANES))
130
		link_ok = true;
131 132

	/* Clear link status ready for next read */
133 134 135
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_COMMA_DET, FFE_AB_XX_STAT_ALL_LANES);
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_CHAR_ERR, FFE_AB_XX_STAT_ALL_LANES);
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_DISPERR, FFE_AB_XX_STAT_ALL_LANES);
136
	efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
137

138
	/* If the link is up, then check the phy side of the xaui link */
139
	if (efx->link_state.up && link_ok)
140
		if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
141
			link_ok = efx_mdio_phyxgxs_lane_sync(efx);
142 143 144 145

	return link_ok;
}

B
Ben Hutchings 已提交
146
void falcon_reconfigure_xmac_core(struct efx_nic *efx)
147 148
{
	unsigned int max_frame_len;
149
	efx_oword_t reg;
150
	bool rx_fc = !!(efx->link_state.fc & EFX_FC_RX);
151
	bool tx_fc = !!(efx->link_state.fc & EFX_FC_TX);
152 153

	/* Configure MAC  - cut-thru mode is hard wired on */
154
	EFX_POPULATE_OWORD_3(reg,
155 156 157
			     FRF_AB_XM_RX_JUMBO_MODE, 1,
			     FRF_AB_XM_TX_STAT_EN, 1,
			     FRF_AB_XM_RX_STAT_EN, 1);
158
	efx_writeo(efx, &reg, FR_AB_XM_GLB_CFG);
159 160

	/* Configure TX */
161
	EFX_POPULATE_OWORD_6(reg,
162 163 164 165
			     FRF_AB_XM_TXEN, 1,
			     FRF_AB_XM_TX_PRMBL, 1,
			     FRF_AB_XM_AUTO_PAD, 1,
			     FRF_AB_XM_TXCRC, 1,
166
			     FRF_AB_XM_FCNTL, tx_fc,
167
			     FRF_AB_XM_IPG, 0x3);
168
	efx_writeo(efx, &reg, FR_AB_XM_TX_CFG);
169 170

	/* Configure RX */
171
	EFX_POPULATE_OWORD_5(reg,
172 173 174 175 176
			     FRF_AB_XM_RXEN, 1,
			     FRF_AB_XM_AUTO_DEPAD, 0,
			     FRF_AB_XM_ACPT_ALL_MCAST, 1,
			     FRF_AB_XM_ACPT_ALL_UCAST, efx->promiscuous,
			     FRF_AB_XM_PASS_CRC_ERR, 1);
177
	efx_writeo(efx, &reg, FR_AB_XM_RX_CFG);
178 179 180

	/* Set frame length */
	max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
181
	EFX_POPULATE_OWORD_1(reg, FRF_AB_XM_MAX_RX_FRM_SIZE, max_frame_len);
182
	efx_writeo(efx, &reg, FR_AB_XM_RX_PARAM);
183
	EFX_POPULATE_OWORD_2(reg,
184 185
			     FRF_AB_XM_MAX_TX_FRM_SIZE, max_frame_len,
			     FRF_AB_XM_TX_JUMBO_MODE, 1);
186
	efx_writeo(efx, &reg, FR_AB_XM_TX_PARAM);
187

188
	EFX_POPULATE_OWORD_2(reg,
189 190
			     FRF_AB_XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
			     FRF_AB_XM_DIS_FCNTL, !rx_fc);
191
	efx_writeo(efx, &reg, FR_AB_XM_FC);
192 193

	/* Set MAC address */
194
	memcpy(&reg, &efx->net_dev->dev_addr[0], 4);
195
	efx_writeo(efx, &reg, FR_AB_XM_ADR_LO);
196
	memcpy(&reg, &efx->net_dev->dev_addr[4], 2);
197
	efx_writeo(efx, &reg, FR_AB_XM_ADR_HI);
198 199
}

200 201
static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
{
202
	efx_oword_t reg;
203 204 205
	bool xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS);
	bool xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI);
	bool xgmii_loopback = (efx->loopback_mode == LOOPBACK_XGMII);
206 207 208 209

	/* XGXS block is flaky and will need to be reset if moving
	 * into our out of XGMII, XGXS or XAUI loopbacks. */
	if (EFX_WORKAROUND_5147(efx)) {
210 211
		bool old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
		bool reset_xgxs;
212

213
		efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
214 215 216
		old_xgxs_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN);
		old_xgmii_loopback =
			EFX_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN);
217

218
		efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
219
		old_xaui_loopback = EFX_OWORD_FIELD(reg, FRF_AB_XX_LPBKA);
220 221 222 223 224

		/* The PHY driver may have turned XAUI off */
		reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
			      (xaui_loopback != old_xaui_loopback) ||
			      (xgmii_loopback != old_xgmii_loopback));
B
Ben Hutchings 已提交
225 226 227

		if (reset_xgxs)
			falcon_reset_xaui(efx);
228 229
	}

230
	efx_reado(efx, &reg, FR_AB_XX_CORE_STAT);
231
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_FORCE_SIG,
232
			    (xgxs_loopback || xaui_loopback) ?
233 234 235
			    FFE_AB_XX_FORCE_SIG_ALL_LANES : 0);
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGXS_LB_EN, xgxs_loopback);
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_XGMII_LB_EN, xgmii_loopback);
236
	efx_writeo(efx, &reg, FR_AB_XX_CORE_STAT);
237

238
	efx_reado(efx, &reg, FR_AB_XX_SD_CTL);
239 240 241 242
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKD, xaui_loopback);
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKC, xaui_loopback);
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKB, xaui_loopback);
	EFX_SET_OWORD_FIELD(reg, FRF_AB_XX_LPBKA, xaui_loopback);
243
	efx_writeo(efx, &reg, FR_AB_XX_SD_CTL);
244 245 246
}


B
Ben Hutchings 已提交
247 248
/* Try to bring up the Falcon side of the Falcon-Phy XAUI link */
static bool falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
249
{
B
Ben Hutchings 已提交
250
	bool mac_up = falcon_xaui_link_ok(efx);
251

252
	if (LOOPBACK_MASK(efx) & LOOPBACKS_EXTERNAL(efx) & LOOPBACKS_WS ||
253
	    efx_phy_mode_disabled(efx->phy_mode))
254
		/* XAUI link is expected to be down */
B
Ben Hutchings 已提交
255
		return mac_up;
256

257 258
	falcon_stop_nic_stats(efx);

B
Ben Hutchings 已提交
259
	while (!mac_up && tries) {
260
		EFX_LOG(efx, "bashing xaui\n");
B
Ben Hutchings 已提交
261
		falcon_reset_xaui(efx);
262 263
		udelay(200);

B
Ben Hutchings 已提交
264
		mac_up = falcon_xaui_link_ok(efx);
265 266
		--tries;
	}
267 268

	falcon_start_nic_stats(efx);
B
Ben Hutchings 已提交
269 270 271 272 273 274 275

	return mac_up;
}

static bool falcon_xmac_check_fault(struct efx_nic *efx)
{
	return !falcon_check_xaui_link_up(efx, 5);
276 277
}

B
Ben Hutchings 已提交
278
static int falcon_reconfigure_xmac(struct efx_nic *efx)
279
{
280
	falcon_mask_status_intr(efx, false);
281

282
	falcon_reconfigure_xgxs_core(efx);
283
	falcon_reconfigure_xmac_core(efx);
284

285 286
	falcon_reconfigure_mac_wrapper(efx);

B
Ben Hutchings 已提交
287
	efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 5);
288
	falcon_mask_status_intr(efx, true);
B
Ben Hutchings 已提交
289 290

	return 0;
291 292
}

293
static void falcon_update_stats_xmac(struct efx_nic *efx)
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
{
	struct efx_mac_stats *mac_stats = &efx->mac_stats;

	/* Update MAC stats from DMAed values */
	FALCON_STAT(efx, XgRxOctets, rx_bytes);
	FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes);
	FALCON_STAT(efx, XgRxPkts, rx_packets);
	FALCON_STAT(efx, XgRxPktsOK, rx_good);
	FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast);
	FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast);
	FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast);
	FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64);
	FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo);
	FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo);
	FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64);
	FALCON_STAT(efx, XgRxDropEvents, rx_overflow);
	FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad);
	FALCON_STAT(efx, XgRxAlignError, rx_align_error);
	FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error);
	FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error);
	FALCON_STAT(efx, XgRxControlPkts, rx_control);
	FALCON_STAT(efx, XgRxPausePkts, rx_pause);
	FALCON_STAT(efx, XgRxPkts64Octets, rx_64);
	FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127);
	FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255);
	FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511);
	FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023);
	FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx);
	FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo);
	FALCON_STAT(efx, XgRxLengthError, rx_length_error);
	FALCON_STAT(efx, XgTxPkts, tx_packets);
	FALCON_STAT(efx, XgTxOctets, tx_bytes);
	FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast);
	FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast);
	FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast);
	FALCON_STAT(efx, XgTxControlPkts, tx_control);
	FALCON_STAT(efx, XgTxPausePkts, tx_pause);
	FALCON_STAT(efx, XgTxPkts64Octets, tx_64);
	FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127);
	FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255);
	FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511);
	FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023);
	FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx);
	FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo);
	FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64);
	FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo);
	FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp);
	FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error);
	FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);

	/* Update derived statistics */
	mac_stats->tx_good_bytes =
B
Ben Hutchings 已提交
346 347
		(mac_stats->tx_bytes - mac_stats->tx_bad_bytes -
		 mac_stats->tx_control * 64);
348
	mac_stats->rx_bad_bytes =
B
Ben Hutchings 已提交
349 350
		(mac_stats->rx_bytes - mac_stats->rx_good_bytes -
		 mac_stats->rx_control * 64);
351 352
}

B
Ben Hutchings 已提交
353
void falcon_poll_xmac(struct efx_nic *efx)
354
{
B
Ben Hutchings 已提交
355 356
	if (!EFX_WORKAROUND_5147(efx) || !efx->link_state.up ||
	    !efx->xmac_poll_required)
357
		return;
358

359
	falcon_mask_status_intr(efx, false);
B
Ben Hutchings 已提交
360
	efx->xmac_poll_required = !falcon_check_xaui_link_up(efx, 1);
361
	falcon_mask_status_intr(efx, true);
362 363
}

364 365 366
struct efx_mac_operations falcon_xmac_operations = {
	.reconfigure	= falcon_reconfigure_xmac,
	.update_stats	= falcon_update_stats_xmac,
B
Ben Hutchings 已提交
367
	.check_fault	= falcon_xmac_check_fault,
368
};