falcon_xmac.c 11.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/****************************************************************************
 * 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"
#include "falcon_hwdefs.h"
#include "falcon_io.h"
#include "mac.h"
#include "mdio_10g.h"
#include "phy.h"
#include "boards.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)
{
32
	efx_oword_t sdctl, txdrv;
33 34 35 36 37 38

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

39 40 41 42 43 44 45 46 47 48 49 50
	falcon_read(efx, &sdctl, XX_SD_CTL_REG);
	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
	EFX_SET_OWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
	EFX_SET_OWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
	falcon_write(efx, &sdctl, XX_SD_CTL_REG);

	EFX_POPULATE_OWORD_8(txdrv,
51 52 53 54 55 56 57 58
			     XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
			     XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
			     XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
			     XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
			     XX_DTXD, XX_TXDRV_DTX_DEFAULT,
			     XX_DTXC, XX_TXDRV_DTX_DEFAULT,
			     XX_DTXB, XX_TXDRV_DTX_DEFAULT,
			     XX_DTXA, XX_TXDRV_DTX_DEFAULT);
59
	falcon_write(efx, &txdrv, XX_TXDRV_CTL_REG);
60 61
}

62
int falcon_reset_xaui(struct efx_nic *efx)
63
{
64
	efx_oword_t reg;
65 66 67
	int count;

	EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
68
	falcon_write(efx, &reg, XX_PWR_RST_REG);
69 70 71

	/* Give some time for the link to establish */
	for (count = 0; count < 1000; count++) { /* wait upto 10ms */
72 73
		falcon_read(efx, &reg, XX_PWR_RST_REG);
		if (EFX_OWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
74 75 76 77 78 79 80 81 82
			falcon_setup_xaui(efx);
			return 0;
		}
		udelay(10);
	}
	EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
	return -ETIMEDOUT;
}

83
static void falcon_mask_status_intr(struct efx_nic *efx, bool enable)
84
{
85
	efx_oword_t reg;
86

87 88
	if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx))
		return;
89

90 91 92
	/* We expect xgmii faults if the wireside link is up */
	if (!EFX_WORKAROUND_5147(efx) || !efx->link_up)
		return;
93

94 95 96
	/* We can only use this interrupt to signal the negative edge of
	 * xaui_align [we have to poll the positive edge]. */
	if (!efx->mac_up)
97 98 99 100
		return;

	/* Flush the ISR */
	if (enable)
101
		falcon_read(efx, &reg, XM_MGT_INT_REG_B0);
102

103
	EFX_POPULATE_OWORD_2(reg,
104 105
			     XM_MSK_RMTFLT, !enable,
			     XM_MSK_LCLFLT, !enable);
106
	falcon_write(efx, &reg, XM_MGT_INT_MSK_REG_B0);
107 108
}

109
/* Get status of XAUI link */
110
bool falcon_xaui_link_ok(struct efx_nic *efx)
111
{
112
	efx_oword_t reg;
113 114
	bool align_done, link_ok = false;
	int sync_status;
115

116
	if (LOOPBACK_INTERNAL(efx))
117
		return true;
118

119
	/* Read link status */
120
	falcon_read(efx, &reg, XX_CORE_STAT_REG);
121

122 123
	align_done = EFX_OWORD_FIELD(reg, XX_ALIGN_DONE);
	sync_status = EFX_OWORD_FIELD(reg, XX_SYNC_STAT);
124
	if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
125
		link_ok = true;
126 127

	/* Clear link status ready for next read */
128 129 130 131
	EFX_SET_OWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
	EFX_SET_OWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
	EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
	falcon_write(efx, &reg, XX_CORE_STAT_REG);
132

133 134
	/* If the link is up, then check the phy side of the xaui link */
	if (efx->link_up && link_ok)
135
		if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS))
136 137 138 139 140 141 142 143
			link_ok = mdio_clause45_phyxgxs_lane_sync(efx);

	return link_ok;
}

static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
{
	unsigned int max_frame_len;
144
	efx_oword_t reg;
145
	bool rx_fc = !!(efx->flow_control & EFX_FC_RX);
146 147 148 149 150 151

	/* Configure MAC  - cut-thru mode is hard wired on */
	EFX_POPULATE_DWORD_3(reg,
			     XM_RX_JUMBO_MODE, 1,
			     XM_TX_STAT_EN, 1,
			     XM_RX_STAT_EN, 1);
152
	falcon_write(efx, &reg, XM_GLB_CFG_REG);
153 154 155 156 157 158 159 160 161

	/* Configure TX */
	EFX_POPULATE_DWORD_6(reg,
			     XM_TXEN, 1,
			     XM_TX_PRMBL, 1,
			     XM_AUTO_PAD, 1,
			     XM_TXCRC, 1,
			     XM_FCNTL, 1,
			     XM_IPG, 0x3);
162
	falcon_write(efx, &reg, XM_TX_CFG_REG);
163 164 165 166 167 168 169 170

	/* Configure RX */
	EFX_POPULATE_DWORD_5(reg,
			     XM_RXEN, 1,
			     XM_AUTO_DEPAD, 0,
			     XM_ACPT_ALL_MCAST, 1,
			     XM_ACPT_ALL_UCAST, efx->promiscuous,
			     XM_PASS_CRC_ERR, 1);
171
	falcon_write(efx, &reg, XM_RX_CFG_REG);
172 173 174 175

	/* Set frame length */
	max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
	EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
176
	falcon_write(efx, &reg, XM_RX_PARAM_REG);
177 178 179
	EFX_POPULATE_DWORD_2(reg,
			     XM_MAX_TX_FRM_SIZE, max_frame_len,
			     XM_TX_JUMBO_MODE, 1);
180
	falcon_write(efx, &reg, XM_TX_PARAM_REG);
181 182 183

	EFX_POPULATE_DWORD_2(reg,
			     XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
184
			     XM_DIS_FCNTL, !rx_fc);
185
	falcon_write(efx, &reg, XM_FC_REG);
186 187 188 189 190 191 192

	/* Set MAC address */
	EFX_POPULATE_DWORD_4(reg,
			     XM_ADR_0, efx->net_dev->dev_addr[0],
			     XM_ADR_1, efx->net_dev->dev_addr[1],
			     XM_ADR_2, efx->net_dev->dev_addr[2],
			     XM_ADR_3, efx->net_dev->dev_addr[3]);
193
	falcon_write(efx, &reg, XM_ADR_LO_REG);
194 195 196
	EFX_POPULATE_DWORD_2(reg,
			     XM_ADR_4, efx->net_dev->dev_addr[4],
			     XM_ADR_5, efx->net_dev->dev_addr[5]);
197
	falcon_write(efx, &reg, XM_ADR_HI_REG);
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 214 215
		falcon_read(efx, &reg, XX_CORE_STAT_REG);
		old_xgxs_loopback = EFX_OWORD_FIELD(reg, XX_XGXS_LB_EN);
		old_xgmii_loopback = EFX_OWORD_FIELD(reg, XX_XGMII_LB_EN);
216

217 218
		falcon_read(efx, &reg, XX_SD_CTL_REG);
		old_xaui_loopback = EFX_OWORD_FIELD(reg, XX_LPBKA);
219 220 221 222 223

		/* 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 已提交
224 225 226

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

229 230
	falcon_read(efx, &reg, XX_CORE_STAT_REG);
	EFX_SET_OWORD_FIELD(reg, XX_FORCE_SIG,
231 232
			    (xgxs_loopback || xaui_loopback) ?
			    XX_FORCE_SIG_DECODE_FORCED : 0);
233 234 235 236 237 238 239 240 241 242
	EFX_SET_OWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
	EFX_SET_OWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
	falcon_write(efx, &reg, XX_CORE_STAT_REG);

	falcon_read(efx, &reg, XX_SD_CTL_REG);
	EFX_SET_OWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
	EFX_SET_OWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
	EFX_SET_OWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
	EFX_SET_OWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
	falcon_write(efx, &reg, XX_SD_CTL_REG);
243 244 245
}


246 247
/* Try and bring the Falcon side of the Falcon-Phy XAUI link fails
 * to come back up. Bash it until it comes back up */
248
static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries)
249
{
250
	efx->mac_up = falcon_xaui_link_ok(efx);
251

252
	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
253
	    efx_phy_mode_disabled(efx->phy_mode))
254 255
		/* XAUI link is expected to be down */
		return;
256

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

262 263 264
		efx->mac_up = falcon_xaui_link_ok(efx);
		--tries;
	}
265 266
}

267
static void falcon_reconfigure_xmac(struct efx_nic *efx)
268
{
269
	falcon_mask_status_intr(efx, false);
270

271
	falcon_reconfigure_xgxs_core(efx);
272
	falcon_reconfigure_xmac_core(efx);
273

274 275
	falcon_reconfigure_mac_wrapper(efx);

276 277
	falcon_check_xaui_link_up(efx, 5);
	falcon_mask_status_intr(efx, true);
278 279
}

280
static void falcon_update_stats_xmac(struct efx_nic *efx)
281 282 283 284 285 286 287 288 289 290 291 292 293 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
{
	struct efx_mac_stats *mac_stats = &efx->mac_stats;
	int rc;

	rc = falcon_dma_stats(efx, XgDmaDone_offset);
	if (rc)
		return;

	/* 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 已提交
338 339
		(mac_stats->tx_bytes - mac_stats->tx_bad_bytes -
		 mac_stats->tx_control * 64);
340
	mac_stats->rx_bad_bytes =
B
Ben Hutchings 已提交
341 342
		(mac_stats->rx_bytes - mac_stats->rx_good_bytes -
		 mac_stats->rx_control * 64);
343 344
}

345
static int falcon_check_xmac(struct efx_nic *efx)
346
{
347
	bool xaui_link_ok;
348 349
	int rc;

350
	if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
351
	    efx_phy_mode_disabled(efx->phy_mode))
352 353
		return 0;

354
	falcon_mask_status_intr(efx, false);
355 356 357
	xaui_link_ok = falcon_xaui_link_ok(efx);

	if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok)
B
Ben Hutchings 已提交
358
		falcon_reset_xaui(efx);
359 360 361 362 363 364

	/* Call the PHY check_hw routine */
	rc = efx->phy_op->check_hw(efx);

	/* Unmask interrupt if everything was (and still is) ok */
	if (xaui_link_ok && efx->link_up)
365
		falcon_mask_status_intr(efx, true);
366 367 368 369

	return rc;
}

370 371 372 373 374
struct efx_mac_operations falcon_xmac_operations = {
	.reconfigure	= falcon_reconfigure_xmac,
	.update_stats	= falcon_update_stats_xmac,
	.check_hw	= falcon_check_xmac,
};