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