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