cxgb_xgmac.c revision 176472
1
2/**************************************************************************
3
4Copyright (c) 2007, Chelsio Inc.
5All rights reserved.
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are met:
9
10 1. Redistributions of source code must retain the above copyright notice,
11    this list of conditions and the following disclaimer.
12
13 2. Neither the name of the Chelsio Corporation nor the names of its
14    contributors may be used to endorse or promote products derived from
15    this software without specific prior written permission.
16
17THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27POSSIBILITY OF SUCH DAMAGE.
28
29***************************************************************************/
30
31#include <sys/cdefs.h>
32__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_xgmac.c 176472 2008-02-23 01:06:17Z kmacy $");
33
34#ifdef CONFIG_DEFINED
35#include <cxgb_include.h>
36#else
37#include <dev/cxgb/cxgb_include.h>
38#endif
39
40#undef msleep
41#define msleep t3_os_sleep
42
43/*
44 * # of exact address filters.  The first one is used for the station address,
45 * the rest are available for multicast addresses.
46 */
47#define EXACT_ADDR_FILTERS 8
48
49static inline int macidx(const struct cmac *mac)
50{
51	return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
52}
53
54static void xaui_serdes_reset(struct cmac *mac)
55{
56	static const unsigned int clear[] = {
57		F_PWRDN0 | F_PWRDN1,    F_RESETPLL01,    F_RESET0 | F_RESET1,
58	     	F_PWRDN2 | F_PWRDN3,    F_RESETPLL23,    F_RESET2 | F_RESET3
59	};
60
61	int i;
62	adapter_t *adap = mac->adapter;
63	u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
64
65	t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
66		     F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
67		     F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
68		     F_RESETPLL23 | F_RESETPLL01);
69	(void)t3_read_reg(adap, ctrl);
70	udelay(15);
71
72	for (i = 0; i < ARRAY_SIZE(clear); i++) {
73		t3_set_reg_field(adap, ctrl, clear[i], 0);
74		udelay(15);
75	}
76}
77
78/**
79 *	t3b_pcs_reset - reset the PCS on T3B+ adapters
80 *	@mac: the XGMAC handle
81 *
82 *	Reset the XGMAC PCS block on T3B+ adapters.
83 */
84void t3b_pcs_reset(struct cmac *mac)
85{
86	t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
87			 F_PCS_RESET_, 0);
88	udelay(20);
89	t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
90			 F_PCS_RESET_);
91}
92
93/**
94 *	t3_mac_reset - reset a MAC
95 *	@mac: the MAC to reset
96 *
97 *	Reset the given MAC.
98 */
99int t3_mac_reset(struct cmac *mac)
100{
101	static struct addr_val_pair mac_reset_avp[] = {
102		{ A_XGM_TX_CTRL, 0 },
103		{ A_XGM_RX_CTRL, 0 },
104		{ A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
105		                F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
106		{ A_XGM_RX_HASH_LOW, 0 },
107		{ A_XGM_RX_HASH_HIGH, 0 },
108		{ A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
109		{ A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
110		{ A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
111		{ A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
112		{ A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
113		{ A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
114		{ A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
115		{ A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
116		{ A_XGM_STAT_CTRL, F_CLRSTATS }
117	};
118	u32 val;
119	adapter_t *adap = mac->adapter;
120	unsigned int oft = mac->offset;
121
122	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
123	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
124
125	t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
126	t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
127			 F_RXSTRFRWRD | F_DISERRFRAMES,
128			 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
129	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
130
131	if (uses_xaui(adap)) {
132		if (adap->params.rev == 0) {
133			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
134					 F_RXENABLE | F_TXENABLE);
135			if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
136					    F_CMULOCK, 1, 5, 2)) {
137				CH_ERR(adap,
138				       "MAC %d XAUI SERDES CMU lock failed\n",
139				       macidx(mac));
140				return -1;
141			}
142			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
143					 F_SERDESRESET_);
144		} else
145			xaui_serdes_reset(mac);
146	}
147
148
149	if (mac->multiport) {
150		t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
151			     MAX_FRAME_SIZE - 4);
152		t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
153				 F_DISPREAMBLE);
154		t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
155				 F_ENNON802_3PREAMBLE);
156		t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
157				 V_TXFIFOTHRESH(M_TXFIFOTHRESH),
158				 V_TXFIFOTHRESH(64));
159		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
160		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
161	}
162	t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
163			 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
164			 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
165	val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
166	if (is_10G(adap) || mac->multiport)
167		val |= F_PCS_RESET_;
168	else if (uses_xaui(adap))
169		val |= F_PCS_RESET_ | F_XG2G_RESET_;
170	else
171		val |= F_RGMII_RESET_ | F_XG2G_RESET_;
172	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
173	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
174	if ((val & F_PCS_RESET_) && adap->params.rev) {
175		msleep(1);
176		t3b_pcs_reset(mac);
177	}
178
179	memset(&mac->stats, 0, sizeof(mac->stats));
180	return 0;
181}
182
183static int t3b2_mac_reset(struct cmac *mac)
184{
185	u32 val;
186	adapter_t *adap = mac->adapter;
187	unsigned int oft = mac->offset;
188
189
190	/* Stop egress traffic to xgm*/
191	if (!macidx(mac))
192		t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
193	else
194		t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
195
196	/* PCS in reset */
197	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
198	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
199
200	msleep(10);
201
202	/* Check for xgm Rx fifo empty */
203	if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
204			    0x80000000, 1, 5, 2)) {
205		CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
206		       macidx(mac));
207		return -1;
208	}
209
210	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
211	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
212
213	val = F_MAC_RESET_;
214	if (is_10G(adap))
215		val |= F_PCS_RESET_;
216	else if (uses_xaui(adap))
217		val |= F_PCS_RESET_ | F_XG2G_RESET_;
218	else
219		val |= F_RGMII_RESET_ | F_XG2G_RESET_;
220	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
221	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
222	if ((val & F_PCS_RESET_) && adap->params.rev) {
223		msleep(1);
224		t3b_pcs_reset(mac);
225	}
226	t3_write_reg(adap, A_XGM_RX_CFG + oft,
227		 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
228		                F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
229
230	/*Resume egress traffic to xgm*/
231	if (!macidx(mac))
232		t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
233	else
234		t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
235
236	return 0;
237}
238
239/*
240 * Set the exact match register 'idx' to recognize the given Ethernet address.
241 */
242static void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
243{
244	u32 addr_lo, addr_hi;
245	unsigned int oft = mac->offset + idx * 8;
246
247	addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
248	addr_hi = (addr[5] << 8) | addr[4];
249
250	t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
251	t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
252}
253
254/**
255 *	t3_mac_set_address - set one of the station's unicast MAC addresses
256 *	@mac: the MAC handle
257 *	@idx: index of the exact address match filter to use
258 *	@addr: the Ethernet address
259 *
260 *	Set one of the station's unicast MAC addresses.
261 */
262int t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
263{
264	if (mac->multiport)
265		idx = mac->ext_port + idx * mac->adapter->params.nports;
266	if (idx >= mac->nucast)
267		return -EINVAL;
268	set_addr_filter(mac, idx, addr);
269	if (mac->multiport && idx < mac->adapter->params.nports)
270		t3_vsc7323_set_addr(mac->adapter, addr, idx);
271	return 0;
272}
273
274/**
275 *	t3_mac_set_num_ucast - set the number of unicast addresses needed
276 *	@mac: the MAC handle
277 *	@n: number of unicast addresses needed
278 *
279 *	Specify the number of exact address filters that should be reserved for
280 *	unicast addresses.  Caller should reload the unicast and multicast
281 *	addresses after calling this.
282 */
283int t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
284{
285	if (n > EXACT_ADDR_FILTERS)
286		return -EINVAL;
287	mac->nucast = n;
288	return 0;
289}
290
291static void disable_exact_filters(struct cmac *mac)
292{
293	unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
294
295	for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
296		u32 v = t3_read_reg(mac->adapter, reg);
297		t3_write_reg(mac->adapter, reg, v);
298	}
299	t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
300}
301
302static void enable_exact_filters(struct cmac *mac)
303{
304	unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
305
306	for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
307		u32 v = t3_read_reg(mac->adapter, reg);
308		t3_write_reg(mac->adapter, reg, v);
309	}
310	t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
311}
312
313/* Calculate the RX hash filter index of an Ethernet address */
314static int hash_hw_addr(const u8 *addr)
315{
316	int hash = 0, octet, bit, i = 0, c;
317
318	for (octet = 0; octet < 6; ++octet)
319		for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
320			hash ^= (c & 1) << i;
321			if (++i == 6)
322				i = 0;
323		}
324	return hash;
325}
326
327/**
328 *	t3_mac_set_rx_mode - set the Rx mode and address filters
329 *	@mac: the MAC to configure
330 *	@rm: structure containing the Rx mode and MAC addresses needed
331 *
332 *	Configures the MAC Rx mode (promiscuity, etc) and exact and hash
333 *	address filters.
334 */
335int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
336{
337	u32 hash_lo, hash_hi;
338	adapter_t *adap = mac->adapter;
339	unsigned int oft = mac->offset;
340
341	if (promisc_rx_mode(rm))
342		mac->promisc_map |= 1 << mac->ext_port;
343	else
344		mac->promisc_map &= ~(1 << mac->ext_port);
345	t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
346			 mac->promisc_map ? F_COPYALLFRAMES : 0);
347
348	if (allmulti_rx_mode(rm) || mac->multiport)
349		hash_lo = hash_hi = 0xffffffff;
350	else {
351		u8 *addr;
352		int exact_addr_idx = mac->nucast;
353
354		hash_lo = hash_hi = 0;
355		while ((addr = t3_get_next_mcaddr(rm)))
356			if (exact_addr_idx < EXACT_ADDR_FILTERS)
357				set_addr_filter(mac, exact_addr_idx++, addr);
358			else {
359				int hash = hash_hw_addr(addr);
360
361				if (hash < 32)
362					hash_lo |= (1 << hash);
363				else
364					hash_hi |= (1 << (hash - 32));
365			}
366	}
367
368	t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
369	t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
370	return 0;
371}
372
373static int rx_fifo_hwm(int mtu)
374{
375	int hwm;
376
377	hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
378	return min(hwm, MAC_RXFIFO_SIZE - 8192);
379}
380
381/**
382 *	t3_mac_set_mtu - set the MAC MTU
383 *	@mac: the MAC to configure
384 *	@mtu: the MTU
385 *
386 *	Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
387 */
388int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
389{
390	int hwm, lwm, divisor;
391	int ipg;
392	unsigned int thres, v, reg;
393	adapter_t *adap = mac->adapter;
394
395	/*
396	 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
397	 * packet size register includes header, but not FCS.
398	 */
399	mtu += 14;
400	if (mac->multiport)
401		mtu += 8;                             /* for preamble */
402	if (mtu > MAX_FRAME_SIZE - 4)
403		return -EINVAL;
404	if (mac->multiport)
405		return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
406
407	if (adap->params.rev >= T3_REV_B2 &&
408	    (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
409		disable_exact_filters(mac);
410		v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
411		t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
412				 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
413
414		reg = adap->params.rev == T3_REV_B2 ?
415			A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
416
417		/* drain RX FIFO */
418		if (t3_wait_op_done(adap, reg + mac->offset,
419				    F_RXFIFO_EMPTY, 1, 20, 5)) {
420			t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
421			enable_exact_filters(mac);
422			return -EIO;
423		}
424		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
425				 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
426				 V_RXMAXPKTSIZE(mtu));
427		t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
428		enable_exact_filters(mac);
429	} else
430		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
431		                 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
432		                 V_RXMAXPKTSIZE(mtu));
433
434	/*
435	 * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
436	 * HWM only if flow-control is enabled.
437	 */
438	hwm = rx_fifo_hwm(mtu);
439	lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
440	v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
441	v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
442	v |= V_RXFIFOPAUSELWM(lwm / 8);
443	if (G_RXFIFOPAUSEHWM(v))
444		v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
445		    V_RXFIFOPAUSEHWM(hwm / 8);
446
447	t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
448
449	/* Adjust the TX FIFO threshold based on the MTU */
450	thres = (adap->params.vpd.cclk * 1000) / 15625;
451	thres = (thres * mtu) / 1000;
452	if (is_10G(adap))
453		thres /= 10;
454	thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
455	thres = max(thres, 8U);                          /* need at least 8 */
456	ipg = (adap->params.rev == T3_REV_C) ? 0 : 1;
457	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
458			 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
459			 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
460
461	/* Assuming a minimum drain rate of 2.5Gbps...
462	 */
463	if (adap->params.rev > 0) {
464		divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
465		t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
466		    (hwm - lwm) * 4 / divisor);
467	}
468	t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
469		     MAC_RXFIFO_SIZE * 4 * 8 / 512);
470	return 0;
471}
472
473/**
474 *	t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
475 *	@mac: the MAC to configure
476 *	@speed: the desired speed (10/100/1000/10000)
477 *	@duplex: the desired duplex
478 *	@fc: desired Tx/Rx PAUSE configuration
479 *
480 *	Set the MAC speed, duplex (actually only full-duplex is supported), and
481 *	flow control.  If a parameter value is negative the corresponding
482 *	MAC setting is left at its current value.
483 */
484int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
485{
486	u32 val;
487	adapter_t *adap = mac->adapter;
488	unsigned int oft = mac->offset;
489
490	if (duplex >= 0 && duplex != DUPLEX_FULL)
491		return -EINVAL;
492	if (mac->multiport) {
493		val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
494		val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
495		val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
496					A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
497		t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
498
499		t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
500			  		F_TXPAUSEEN);
501		return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
502	}
503	if (speed >= 0) {
504		if (speed == SPEED_10)
505			val = V_PORTSPEED(0);
506		else if (speed == SPEED_100)
507			val = V_PORTSPEED(1);
508		else if (speed == SPEED_1000)
509			val = V_PORTSPEED(2);
510		else if (speed == SPEED_10000)
511			val = V_PORTSPEED(3);
512		else
513			return -EINVAL;
514
515		t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
516				 V_PORTSPEED(M_PORTSPEED), val);
517	}
518
519	val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
520	val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
521	if (fc & PAUSE_TX)
522		val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(t3_read_reg(adap,
523					A_XGM_RX_MAX_PKT_SIZE + oft)) / 8);
524	t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
525
526	t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
527			(fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
528	return 0;
529}
530
531/**
532 *	t3_mac_enable - enable the MAC in the given directions
533 *	@mac: the MAC to configure
534 *	@which: bitmap indicating which directions to enable
535 *
536 *	Enables the MAC for operation in the given directions.
537 *	%MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
538 *	enables the Rx one.
539 */
540int t3_mac_enable(struct cmac *mac, int which)
541{
542	int idx = macidx(mac);
543	adapter_t *adap = mac->adapter;
544	unsigned int oft = mac->offset;
545	struct mac_stats *s = &mac->stats;
546
547	if (mac->multiport)
548		return t3_vsc7323_enable(adap, mac->ext_port, which);
549
550	if (which & MAC_DIRECTION_TX) {
551		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
552		t3_write_reg(adap, A_TP_PIO_DATA,
553			     adap->params.rev == T3_REV_C ?
554			     0xc4ffff01 : 0xc0ede401);
555		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
556		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
557				 adap->params.rev == T3_REV_C ?
558				 0 : 1 << idx);
559
560		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
561
562		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
563		mac->tx_mcnt = s->tx_frames;
564		mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
565							       A_TP_PIO_DATA)));
566		mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
567						A_XGM_TX_SPI4_SOP_EOP_CNT +
568						oft)));
569		mac->rx_mcnt = s->rx_frames;
570		mac->rx_pause = s->rx_pause;
571		mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
572						A_XGM_RX_SPI4_SOP_EOP_CNT +
573						oft)));
574		mac->rx_ocnt = s->rx_fifo_ovfl;
575		mac->txen = F_TXEN;
576		mac->toggle_cnt = 0;
577	}
578	if (which & MAC_DIRECTION_RX)
579		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
580	return 0;
581}
582
583/**
584 *	t3_mac_disable - disable the MAC in the given directions
585 *	@mac: the MAC to configure
586 *	@which: bitmap indicating which directions to disable
587 *
588 *	Disables the MAC in the given directions.
589 *	%MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
590 *	disables the Rx one.
591 */
592int t3_mac_disable(struct cmac *mac, int which)
593{
594	adapter_t *adap = mac->adapter;
595
596	if (mac->multiport)
597		return t3_vsc7323_disable(adap, mac->ext_port, which);
598
599	if (which & MAC_DIRECTION_TX) {
600		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
601		mac->txen = 0;
602	}
603	if (which & MAC_DIRECTION_RX) {
604		int val = F_MAC_RESET_;
605
606		t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
607				 F_PCS_RESET_, 0);
608		msleep(100);
609		t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
610		if (is_10G(adap))
611			val |= F_PCS_RESET_;
612		else if (uses_xaui(adap))
613			val |= F_PCS_RESET_ | F_XG2G_RESET_;
614		else
615			val |= F_RGMII_RESET_ | F_XG2G_RESET_;
616		t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
617	}
618	return 0;
619}
620
621int t3b2_mac_watchdog_task(struct cmac *mac)
622{
623	int status;
624	unsigned int tx_tcnt, tx_xcnt;
625	adapter_t *adap = mac->adapter;
626	struct mac_stats *s = &mac->stats;
627	unsigned int tx_mcnt = (unsigned int)s->tx_frames;
628	unsigned int rx_mcnt = (unsigned int)s->rx_frames;
629	unsigned int rx_xcnt;
630
631	if (mac->multiport) {
632	  tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
633	  rx_mcnt = t3_read_reg(adap, A_XGM_STAT_RX_FRAMES_LOW);
634	} else {
635	  tx_mcnt = (unsigned int)s->tx_frames;
636	  rx_mcnt = (unsigned int)s->rx_frames;
637	}
638	status = 0;
639	tx_xcnt = 1; /* By default tx_xcnt is making progress*/
640	tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
641	rx_xcnt = 1; /* By default rx_xcnt is making progress*/
642	if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
643		tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
644						A_XGM_TX_SPI4_SOP_EOP_CNT +
645					       	mac->offset)));
646		if (tx_xcnt == 0) {
647			t3_write_reg(adap, A_TP_PIO_ADDR,
648			     	A_TP_TX_DROP_CNT_CH0 + macidx(mac));
649			tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
650			      	A_TP_PIO_DATA)));
651		} else {
652			goto rxcheck;
653		}
654	} else {
655		mac->toggle_cnt = 0;
656		goto rxcheck;
657	}
658
659	if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
660		if (mac->toggle_cnt > 4) {
661			status = 2;
662			goto out;
663		} else {
664			status = 1;
665			goto out;
666		}
667	} else {
668		mac->toggle_cnt = 0;
669		goto rxcheck;
670	}
671
672rxcheck:
673	if (rx_mcnt != mac->rx_mcnt) {
674		rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
675						A_XGM_RX_SPI4_SOP_EOP_CNT +
676						mac->offset))) +
677						(s->rx_fifo_ovfl - mac->rx_ocnt);
678		mac->rx_ocnt = s->rx_fifo_ovfl;
679	} else
680		goto out;
681
682	if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 && mac->rx_xcnt == 0) {
683		if (!mac->multiport)
684		  status = 2;
685		goto out;
686	}
687
688out:
689	mac->tx_tcnt = tx_tcnt;
690	mac->tx_xcnt = tx_xcnt;
691	mac->tx_mcnt = s->tx_frames;
692	mac->rx_xcnt = rx_xcnt;
693	mac->rx_mcnt = s->rx_frames;
694	mac->rx_pause = s->rx_pause;
695	if (status == 1) {
696		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
697		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
698		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
699		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
700		mac->toggle_cnt++;
701	} else if (status == 2) {
702		t3b2_mac_reset(mac);
703		mac->toggle_cnt = 0;
704	}
705	return status;
706}
707
708/**
709 *	t3_mac_update_stats - accumulate MAC statistics
710 *	@mac: the MAC handle
711 *
712 *	This function is called periodically to accumulate the current values
713 *	of the RMON counters into the port statistics.  Since the packet
714 *	counters are only 32 bits they can overflow in ~286 secs at 10G, so the
715 *	function should be called more frequently than that.  The byte counters
716 *	are 45-bit wide, they would overflow in ~7.8 hours.
717 */
718const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
719{
720#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
721#define RMON_UPDATE(mac, name, reg) \
722	(mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
723#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
724	(mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
725			     ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
726
727	u32 v, lo;
728
729	if (mac->multiport)
730		return t3_vsc7323_update_stats(mac);
731
732	RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
733	RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
734	RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
735	RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
736	RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
737	RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
738	RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
739	RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
740	RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
741
742	RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
743
744	v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
745	if (mac->adapter->params.rev == T3_REV_B2)
746		v &= 0x7fffffff;
747	mac->stats.rx_too_long += v;
748
749	RMON_UPDATE(mac, rx_frames_64,        RX_64B_FRAMES);
750	RMON_UPDATE(mac, rx_frames_65_127,    RX_65_127B_FRAMES);
751	RMON_UPDATE(mac, rx_frames_128_255,   RX_128_255B_FRAMES);
752	RMON_UPDATE(mac, rx_frames_256_511,   RX_256_511B_FRAMES);
753	RMON_UPDATE(mac, rx_frames_512_1023,  RX_512_1023B_FRAMES);
754	RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
755	RMON_UPDATE(mac, rx_frames_1519_max,  RX_1519_MAXB_FRAMES);
756
757	RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
758	RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
759	RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
760	RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
761	RMON_UPDATE(mac, tx_pause, TX_PAUSE);
762	/* This counts error frames in general (bad FCS, underrun, etc). */
763	RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
764
765	RMON_UPDATE(mac, tx_frames_64,        TX_64B_FRAMES);
766	RMON_UPDATE(mac, tx_frames_65_127,    TX_65_127B_FRAMES);
767	RMON_UPDATE(mac, tx_frames_128_255,   TX_128_255B_FRAMES);
768	RMON_UPDATE(mac, tx_frames_256_511,   TX_256_511B_FRAMES);
769	RMON_UPDATE(mac, tx_frames_512_1023,  TX_512_1023B_FRAMES);
770	RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
771	RMON_UPDATE(mac, tx_frames_1519_max,  TX_1519_MAXB_FRAMES);
772
773	/* The next stat isn't clear-on-read. */
774	t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
775	v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
776	lo = (u32)mac->stats.rx_cong_drops;
777	mac->stats.rx_cong_drops += (u64)(v - lo);
778
779	return &mac->stats;
780}
781