cxgb_xgmac.c revision 199239
1167514Skmacy/**************************************************************************
2167514Skmacy
3189643SgnnCopyright (c) 2007-2009 Chelsio Inc.
4167514SkmacyAll rights reserved.
5167514Skmacy
6167514SkmacyRedistribution and use in source and binary forms, with or without
7167514Skmacymodification, are permitted provided that the following conditions are met:
8167514Skmacy
9167514Skmacy 1. Redistributions of source code must retain the above copyright notice,
10167514Skmacy    this list of conditions and the following disclaimer.
11167514Skmacy
12170076Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13167514Skmacy    contributors may be used to endorse or promote products derived from
14167514Skmacy    this software without specific prior written permission.
15167514Skmacy
16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26167514SkmacyPOSSIBILITY OF SUCH DAMAGE.
27167514Skmacy
28167514Skmacy***************************************************************************/
29167514Skmacy
30167514Skmacy#include <sys/cdefs.h>
31167514Skmacy__FBSDID("$FreeBSD: head/sys/dev/cxgb/common/cxgb_xgmac.c 199239 2009-11-13 00:34:28Z np $");
32167514Skmacy
33170076Skmacy#include <cxgb_include.h>
34167514Skmacy
35171471Skmacy#undef msleep
36171471Skmacy#define msleep t3_os_sleep
37171471Skmacy
38167514Skmacy
39167514Skmacystatic inline int macidx(const struct cmac *mac)
40167514Skmacy{
41167514Skmacy	return mac->offset / (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR);
42167514Skmacy}
43167514Skmacy
44197791Snp/*
45197791Snp * Returns a reasonable A_XGM_RESET_CTRL value for the mac specified.
46197791Snp */
47197791Snpstatic inline int xgm_reset_ctrl(const struct cmac *mac)
48197791Snp{
49197791Snp	adapter_t *adap = mac->adapter;
50197791Snp	int val = F_MAC_RESET_ | F_XGMAC_STOP_EN;
51197791Snp
52197791Snp	if (is_10G(adap)) {
53197791Snp		int cfg = t3_read_reg(adap, A_XGM_PORT_CFG + mac->offset);
54197791Snp
55197791Snp		val |= F_PCS_RESET_;
56197791Snp		if (G_PORTSPEED(cfg) != 3)	/* not running at 10G */
57197791Snp			val |= F_XG2G_RESET_;
58197791Snp	} else if (uses_xaui(adap))
59197791Snp		val |= F_PCS_RESET_ | F_XG2G_RESET_;
60197791Snp	else
61197791Snp		val |= F_RGMII_RESET_ | F_XG2G_RESET_;
62197791Snp
63197791Snp	return (val);
64197791Snp}
65197791Snp
66167514Skmacystatic void xaui_serdes_reset(struct cmac *mac)
67167514Skmacy{
68167514Skmacy	static const unsigned int clear[] = {
69167514Skmacy		F_PWRDN0 | F_PWRDN1,    F_RESETPLL01,    F_RESET0 | F_RESET1,
70167514Skmacy	     	F_PWRDN2 | F_PWRDN3,    F_RESETPLL23,    F_RESET2 | F_RESET3
71167514Skmacy	};
72167514Skmacy
73167514Skmacy	int i;
74167514Skmacy	adapter_t *adap = mac->adapter;
75167514Skmacy	u32 ctrl = A_XGM_SERDES_CTRL0 + mac->offset;
76167514Skmacy
77167514Skmacy	t3_write_reg(adap, ctrl, adap->params.vpd.xauicfg[macidx(mac)] |
78167514Skmacy		     F_RESET3 | F_RESET2 | F_RESET1 | F_RESET0 |
79167514Skmacy		     F_PWRDN3 | F_PWRDN2 | F_PWRDN1 | F_PWRDN0 |
80167514Skmacy		     F_RESETPLL23 | F_RESETPLL01);
81167514Skmacy	(void)t3_read_reg(adap, ctrl);
82167514Skmacy	udelay(15);
83167514Skmacy
84167514Skmacy	for (i = 0; i < ARRAY_SIZE(clear); i++) {
85167514Skmacy		t3_set_reg_field(adap, ctrl, clear[i], 0);
86167514Skmacy		udelay(15);
87167514Skmacy	}
88167514Skmacy}
89167514Skmacy
90176472Skmacy/**
91176472Skmacy *	t3b_pcs_reset - reset the PCS on T3B+ adapters
92176472Skmacy *	@mac: the XGMAC handle
93176472Skmacy *
94176472Skmacy *	Reset the XGMAC PCS block on T3B+ adapters.
95176472Skmacy */
96167514Skmacyvoid t3b_pcs_reset(struct cmac *mac)
97167514Skmacy{
98167514Skmacy	t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
99167514Skmacy			 F_PCS_RESET_, 0);
100167514Skmacy	udelay(20);
101167514Skmacy	t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset, 0,
102167514Skmacy			 F_PCS_RESET_);
103167514Skmacy}
104167514Skmacy
105176472Skmacy/**
106197791Snp *	t3_mac_init - initialize a MAC
107197791Snp *	@mac: the MAC to initialize
108176472Skmacy *
109197791Snp *	Initialize the given MAC.
110176472Skmacy */
111197791Snpint t3_mac_init(struct cmac *mac)
112167514Skmacy{
113167514Skmacy	static struct addr_val_pair mac_reset_avp[] = {
114167514Skmacy		{ A_XGM_TX_CTRL, 0 },
115167514Skmacy		{ A_XGM_RX_CTRL, 0 },
116167514Skmacy		{ A_XGM_RX_CFG, F_DISPAUSEFRAMES | F_EN1536BFRAMES |
117167514Skmacy		                F_RMFCS | F_ENJUMBO | F_ENHASHMCAST },
118167514Skmacy		{ A_XGM_RX_HASH_LOW, 0 },
119167514Skmacy		{ A_XGM_RX_HASH_HIGH, 0 },
120167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_1, 0 },
121167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_2, 0 },
122167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_3, 0 },
123167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_4, 0 },
124167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_5, 0 },
125167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_6, 0 },
126167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_7, 0 },
127167514Skmacy		{ A_XGM_RX_EXACT_MATCH_LOW_8, 0 },
128167514Skmacy		{ A_XGM_STAT_CTRL, F_CLRSTATS }
129167514Skmacy	};
130167514Skmacy	u32 val;
131167514Skmacy	adapter_t *adap = mac->adapter;
132167514Skmacy	unsigned int oft = mac->offset;
133167514Skmacy
134167514Skmacy	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
135167514Skmacy	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
136167514Skmacy
137167514Skmacy	t3_write_regs(adap, mac_reset_avp, ARRAY_SIZE(mac_reset_avp), oft);
138167514Skmacy	t3_set_reg_field(adap, A_XGM_RXFIFO_CFG + oft,
139167514Skmacy			 F_RXSTRFRWRD | F_DISERRFRAMES,
140167514Skmacy			 uses_xaui(adap) ? 0 : F_RXSTRFRWRD);
141176472Skmacy	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0, F_UNDERUNFIX);
142167514Skmacy
143167514Skmacy	if (uses_xaui(adap)) {
144167514Skmacy		if (adap->params.rev == 0) {
145167514Skmacy			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
146167514Skmacy					 F_RXENABLE | F_TXENABLE);
147167514Skmacy			if (t3_wait_op_done(adap, A_XGM_SERDES_STATUS1 + oft,
148167514Skmacy					    F_CMULOCK, 1, 5, 2)) {
149167514Skmacy				CH_ERR(adap,
150167514Skmacy				       "MAC %d XAUI SERDES CMU lock failed\n",
151167514Skmacy				       macidx(mac));
152167514Skmacy				return -1;
153167514Skmacy			}
154167514Skmacy			t3_set_reg_field(adap, A_XGM_SERDES_CTRL + oft, 0,
155167514Skmacy					 F_SERDESRESET_);
156167514Skmacy		} else
157167514Skmacy			xaui_serdes_reset(mac);
158167514Skmacy	}
159167514Skmacy
160170654Skmacy
161170654Skmacy	if (mac->multiport) {
162170654Skmacy		t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
163197791Snp			     V_RXMAXPKTSIZE(MAX_FRAME_SIZE - 4));
164170654Skmacy		t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft, 0,
165170654Skmacy				 F_DISPREAMBLE);
166170654Skmacy		t3_set_reg_field(adap, A_XGM_RX_CFG + oft, 0, F_COPYPREAMBLE |
167170654Skmacy				 F_ENNON802_3PREAMBLE);
168170654Skmacy		t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + oft,
169170654Skmacy				 V_TXFIFOTHRESH(M_TXFIFOTHRESH),
170170654Skmacy				 V_TXFIFOTHRESH(64));
171170654Skmacy		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
172170654Skmacy		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
173170654Skmacy	}
174180583Skmacy
175176472Skmacy	t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + oft,
176176472Skmacy			 V_RXMAXFRAMERSIZE(M_RXMAXFRAMERSIZE),
177176472Skmacy			 V_RXMAXFRAMERSIZE(MAX_FRAME_SIZE) | F_RXENFRAMER);
178180583Skmacy
179197791Snp	val = xgm_reset_ctrl(mac);
180167514Skmacy	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
181167514Skmacy	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
182167514Skmacy	if ((val & F_PCS_RESET_) && adap->params.rev) {
183171471Skmacy		msleep(1);
184167514Skmacy		t3b_pcs_reset(mac);
185167514Skmacy	}
186167514Skmacy
187167514Skmacy	memset(&mac->stats, 0, sizeof(mac->stats));
188167514Skmacy	return 0;
189167514Skmacy}
190167514Skmacy
191197791Snpstatic int t3_mac_reset(struct cmac *mac, int portspeed)
192167746Skmacy{
193197791Snp	u32 val, store_mps;
194167746Skmacy	adapter_t *adap = mac->adapter;
195167746Skmacy	unsigned int oft = mac->offset;
196181614Skmacy	int idx = macidx(mac);
197181614Skmacy	unsigned int store;
198167746Skmacy
199167746Skmacy	/* Stop egress traffic to xgm*/
200197791Snp	store_mps = t3_read_reg(adap, A_MPS_CFG);
201197791Snp	if (!idx)
202180583Skmacy		t3_set_reg_field(adap, A_MPS_CFG, F_PORT0ACTIVE, 0);
203167746Skmacy	else
204180583Skmacy		t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
205167746Skmacy
206189643Sgnn	/* This will reduce the number of TXTOGGLES */
207189643Sgnn	/* Clear: to stop the NIC traffic */
208189643Sgnn	t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0);
209189643Sgnn	/* Ensure TX drains */
210189643Sgnn	t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0);
211189643Sgnn
212167746Skmacy	/* PCS in reset */
213167746Skmacy	t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
214167746Skmacy	(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
215167746Skmacy
216181614Skmacy	/* Store A_TP_TX_DROP_CFG_CH0 */
217181614Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
218197791Snp	store = t3_read_reg(adap, A_TP_PIO_DATA);
219181614Skmacy
220171471Skmacy	msleep(10);
221167746Skmacy
222181614Skmacy	/* Change DROP_CFG to 0xc0000011 */
223181614Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
224181614Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
225181614Skmacy
226167746Skmacy	/* Check for xgm Rx fifo empty */
227181614Skmacy	/* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
228167746Skmacy	if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
229197791Snp			    0x80000000, 1, 1000, 2) && portspeed < 0) {
230197791Snp		CH_ERR(adap, "MAC %d Rx fifo drain failed\n", idx);
231167746Skmacy		return -1;
232167746Skmacy	}
233167746Skmacy
234197791Snp	if (portspeed >= 0) {
235197791Snp		u32 intr = t3_read_reg(adap, A_XGM_INT_ENABLE + oft);
236167746Skmacy
237197791Snp		/*
238197791Snp		 * safespeedchange: wipes out pretty much all XGMAC registers.
239197791Snp		 */
240197791Snp
241197791Snp		t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
242197791Snp		    V_PORTSPEED(M_PORTSPEED) | F_SAFESPEEDCHANGE,
243197791Snp		    portspeed | F_SAFESPEEDCHANGE);
244197791Snp		(void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
245197791Snp		t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
246197791Snp		    F_SAFESPEEDCHANGE, 0);
247197791Snp		(void) t3_read_reg(adap, A_XGM_PORT_CFG + oft);
248197791Snp		t3_mac_init(mac);
249197791Snp
250197791Snp		t3_write_reg(adap, A_XGM_INT_ENABLE + oft, intr);
251197791Snp	} else {
252197791Snp
253197791Snp		t3_write_reg(adap, A_XGM_RESET_CTRL + oft, 0); /*MAC in reset*/
254197791Snp		(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
255197791Snp
256197791Snp		val = xgm_reset_ctrl(mac);
257197791Snp		t3_write_reg(adap, A_XGM_RESET_CTRL + oft, val);
258197791Snp		(void) t3_read_reg(adap, A_XGM_RESET_CTRL + oft);  /* flush */
259197791Snp		if ((val & F_PCS_RESET_) && adap->params.rev) {
260197791Snp			msleep(1);
261197791Snp			t3b_pcs_reset(mac);
262197791Snp		}
263197791Snp		t3_write_reg(adap, A_XGM_RX_CFG + oft,
264197791Snp			 F_DISPAUSEFRAMES | F_EN1536BFRAMES |
265197791Snp					F_RMFCS | F_ENJUMBO | F_ENHASHMCAST );
266167746Skmacy	}
267167746Skmacy
268181614Skmacy	/* Restore the DROP_CFG */
269181614Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
270181614Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, store);
271181614Skmacy
272181614Skmacy	/* Resume egress traffic to xgm */
273197791Snp	t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
274197791Snp			 store_mps);
275167746Skmacy
276189643Sgnn	/*  Set: re-enable NIC traffic */
277197791Snp	t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, F_ENFORCEPKT);
278189643Sgnn
279167746Skmacy	return 0;
280167746Skmacy}
281167746Skmacy
282167514Skmacy/*
283167514Skmacy * Set the exact match register 'idx' to recognize the given Ethernet address.
284167514Skmacy */
285167514Skmacystatic void set_addr_filter(struct cmac *mac, int idx, const u8 *addr)
286167514Skmacy{
287167514Skmacy	u32 addr_lo, addr_hi;
288167514Skmacy	unsigned int oft = mac->offset + idx * 8;
289167514Skmacy
290167514Skmacy	addr_lo = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0];
291167514Skmacy	addr_hi = (addr[5] << 8) | addr[4];
292167514Skmacy
293167514Skmacy	t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1 + oft, addr_lo);
294167514Skmacy	t3_write_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_HIGH_1 + oft, addr_hi);
295167514Skmacy}
296167514Skmacy
297176472Skmacy/**
298176472Skmacy *	t3_mac_set_address - set one of the station's unicast MAC addresses
299176472Skmacy *	@mac: the MAC handle
300176472Skmacy *	@idx: index of the exact address match filter to use
301176472Skmacy *	@addr: the Ethernet address
302176472Skmacy *
303176472Skmacy *	Set one of the station's unicast MAC addresses.
304176472Skmacy */
305167514Skmacyint t3_mac_set_address(struct cmac *mac, unsigned int idx, u8 addr[6])
306167514Skmacy{
307170654Skmacy	if (mac->multiport)
308170654Skmacy		idx = mac->ext_port + idx * mac->adapter->params.nports;
309167514Skmacy	if (idx >= mac->nucast)
310167514Skmacy		return -EINVAL;
311167514Skmacy	set_addr_filter(mac, idx, addr);
312170654Skmacy	if (mac->multiport && idx < mac->adapter->params.nports)
313170654Skmacy		t3_vsc7323_set_addr(mac->adapter, addr, idx);
314167514Skmacy	return 0;
315167514Skmacy}
316167514Skmacy
317176472Skmacy/**
318176472Skmacy *	t3_mac_set_num_ucast - set the number of unicast addresses needed
319176472Skmacy *	@mac: the MAC handle
320176472Skmacy *	@n: number of unicast addresses needed
321176472Skmacy *
322176472Skmacy *	Specify the number of exact address filters that should be reserved for
323176472Skmacy *	unicast addresses.  Caller should reload the unicast and multicast
324176472Skmacy *	addresses after calling this.
325180583Skmacy *
326180583Skmacy *	Generally, this is 1 with the first one used for the station address,
327180583Skmacy *	and the rest are available for multicast addresses.
328167514Skmacy */
329170654Skmacyint t3_mac_set_num_ucast(struct cmac *mac, unsigned char n)
330167514Skmacy{
331167514Skmacy	if (n > EXACT_ADDR_FILTERS)
332167514Skmacy		return -EINVAL;
333167514Skmacy	mac->nucast = n;
334167514Skmacy	return 0;
335167514Skmacy}
336167514Skmacy
337189643Sgnnvoid t3_mac_disable_exact_filters(struct cmac *mac)
338170654Skmacy{
339170654Skmacy	unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
340170654Skmacy
341170654Skmacy	for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
342170654Skmacy		u32 v = t3_read_reg(mac->adapter, reg);
343170654Skmacy		t3_write_reg(mac->adapter, reg, v);
344170654Skmacy	}
345170654Skmacy	t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
346170654Skmacy}
347170654Skmacy
348189643Sgnnvoid t3_mac_enable_exact_filters(struct cmac *mac)
349170654Skmacy{
350170654Skmacy	unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
351170654Skmacy
352170654Skmacy	for (i = 0; i < EXACT_ADDR_FILTERS; i++, reg += 8) {
353170654Skmacy		u32 v = t3_read_reg(mac->adapter, reg);
354170654Skmacy		t3_write_reg(mac->adapter, reg, v);
355170654Skmacy	}
356170654Skmacy	t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1); /* flush */
357170654Skmacy}
358170654Skmacy
359167514Skmacy/* Calculate the RX hash filter index of an Ethernet address */
360167514Skmacystatic int hash_hw_addr(const u8 *addr)
361167514Skmacy{
362167514Skmacy	int hash = 0, octet, bit, i = 0, c;
363167514Skmacy
364167514Skmacy	for (octet = 0; octet < 6; ++octet)
365167514Skmacy		for (c = addr[octet], bit = 0; bit < 8; c >>= 1, ++bit) {
366167514Skmacy			hash ^= (c & 1) << i;
367167514Skmacy			if (++i == 6)
368167514Skmacy				i = 0;
369167514Skmacy		}
370167514Skmacy	return hash;
371167514Skmacy}
372167514Skmacy
373176472Skmacy/**
374176472Skmacy *	t3_mac_set_rx_mode - set the Rx mode and address filters
375176472Skmacy *	@mac: the MAC to configure
376176472Skmacy *	@rm: structure containing the Rx mode and MAC addresses needed
377176472Skmacy *
378176472Skmacy *	Configures the MAC Rx mode (promiscuity, etc) and exact and hash
379176472Skmacy *	address filters.
380176472Skmacy */
381167514Skmacyint t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
382167514Skmacy{
383170654Skmacy	u32 hash_lo, hash_hi;
384167514Skmacy	adapter_t *adap = mac->adapter;
385167514Skmacy	unsigned int oft = mac->offset;
386167514Skmacy
387167514Skmacy	if (promisc_rx_mode(rm))
388170654Skmacy		mac->promisc_map |= 1 << mac->ext_port;
389170654Skmacy	else
390170654Skmacy		mac->promisc_map &= ~(1 << mac->ext_port);
391170654Skmacy	t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
392170654Skmacy			 mac->promisc_map ? F_COPYALLFRAMES : 0);
393167514Skmacy
394170654Skmacy	if (allmulti_rx_mode(rm) || mac->multiport)
395167514Skmacy		hash_lo = hash_hi = 0xffffffff;
396167514Skmacy	else {
397167514Skmacy		u8 *addr;
398167514Skmacy		int exact_addr_idx = mac->nucast;
399167514Skmacy
400167514Skmacy		hash_lo = hash_hi = 0;
401167514Skmacy		while ((addr = t3_get_next_mcaddr(rm)))
402167514Skmacy			if (exact_addr_idx < EXACT_ADDR_FILTERS)
403167514Skmacy				set_addr_filter(mac, exact_addr_idx++, addr);
404167514Skmacy			else {
405167514Skmacy				int hash = hash_hw_addr(addr);
406167514Skmacy
407167514Skmacy				if (hash < 32)
408167514Skmacy					hash_lo |= (1 << hash);
409167514Skmacy				else
410167514Skmacy					hash_hi |= (1 << (hash - 32));
411167514Skmacy			}
412167514Skmacy	}
413167514Skmacy
414167514Skmacy	t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, hash_lo);
415167514Skmacy	t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, hash_hi);
416167514Skmacy	return 0;
417167514Skmacy}
418167514Skmacy
419170654Skmacystatic int rx_fifo_hwm(int mtu)
420167514Skmacy{
421170654Skmacy	int hwm;
422170654Skmacy
423170654Skmacy	hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
424170654Skmacy	return min(hwm, MAC_RXFIFO_SIZE - 8192);
425170654Skmacy}
426170654Skmacy
427176472Skmacy/**
428176472Skmacy *	t3_mac_set_mtu - set the MAC MTU
429176472Skmacy *	@mac: the MAC to configure
430176472Skmacy *	@mtu: the MTU
431176472Skmacy *
432176472Skmacy *	Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
433176472Skmacy */
434180583Skmacyint t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
435170654Skmacy{
436176472Skmacy	int hwm, lwm, divisor;
437176472Skmacy	int ipg;
438176472Skmacy	unsigned int thres, v, reg;
439167514Skmacy	adapter_t *adap = mac->adapter;
440197791Snp	unsigned port_type = adap->params.vpd.port_type[macidx(mac)];
441197791Snp	unsigned int orig_mtu=mtu;
442167514Skmacy
443167514Skmacy	/*
444167514Skmacy	 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
445167514Skmacy	 * packet size register includes header, but not FCS.
446167514Skmacy	 */
447167514Skmacy	mtu += 14;
448170654Skmacy	if (mac->multiport)
449170654Skmacy		mtu += 8;                             /* for preamble */
450167514Skmacy	if (mtu > MAX_FRAME_SIZE - 4)
451167514Skmacy		return -EINVAL;
452170654Skmacy	if (mac->multiport)
453170654Skmacy		return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
454167514Skmacy
455197791Snp	/* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */
456197791Snp	if (port_type == 2) {
457197791Snp		int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac));
458197791Snp
459197791Snp		if (err)
460197791Snp			return err;
461197791Snp	}
462197791Snp
463176472Skmacy	if (adap->params.rev >= T3_REV_B2 &&
464170654Skmacy	    (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
465189643Sgnn		t3_mac_disable_exact_filters(mac);
466170654Skmacy		v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
467170654Skmacy		t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
468170654Skmacy				 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
469170654Skmacy
470176472Skmacy		reg = adap->params.rev == T3_REV_B2 ?
471176472Skmacy			A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
472180583Skmacy
473176472Skmacy		/* drain RX FIFO */
474176472Skmacy		if (t3_wait_op_done(adap, reg + mac->offset,
475176472Skmacy				    F_RXFIFO_EMPTY, 1, 20, 5)) {
476170654Skmacy			t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
477189643Sgnn			t3_mac_enable_exact_filters(mac);
478170654Skmacy			return -EIO;
479170654Skmacy		}
480176472Skmacy		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
481176472Skmacy				 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
482176472Skmacy				 V_RXMAXPKTSIZE(mtu));
483170654Skmacy		t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
484189643Sgnn		t3_mac_enable_exact_filters(mac);
485170654Skmacy	} else
486176472Skmacy		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
487180583Skmacy				 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
488180583Skmacy				 V_RXMAXPKTSIZE(mtu));
489167514Skmacy	/*
490167514Skmacy	 * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
491167514Skmacy	 * HWM only if flow-control is enabled.
492167514Skmacy	 */
493170654Skmacy	hwm = rx_fifo_hwm(mtu);
494167746Skmacy	lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
495167514Skmacy	v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
496167514Skmacy	v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
497167514Skmacy	v |= V_RXFIFOPAUSELWM(lwm / 8);
498167514Skmacy	if (G_RXFIFOPAUSEHWM(v))
499167514Skmacy		v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
500167514Skmacy		    V_RXFIFOPAUSEHWM(hwm / 8);
501170654Skmacy
502167514Skmacy	t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
503167514Skmacy
504167514Skmacy	/* Adjust the TX FIFO threshold based on the MTU */
505167514Skmacy	thres = (adap->params.vpd.cclk * 1000) / 15625;
506167514Skmacy	thres = (thres * mtu) / 1000;
507167514Skmacy	if (is_10G(adap))
508167514Skmacy		thres /= 10;
509167514Skmacy	thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
510167514Skmacy	thres = max(thres, 8U);                          /* need at least 8 */
511199239Snp	ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0;
512167514Skmacy	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
513169978Skmacy			 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
514176472Skmacy			 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
515167746Skmacy
516167746Skmacy	/* Assuming a minimum drain rate of 2.5Gbps...
517167746Skmacy	 */
518176472Skmacy	if (adap->params.rev > 0) {
519176472Skmacy		divisor = (adap->params.rev == T3_REV_C) ? 64 : 8;
520180583Skmacy		t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
521180583Skmacy			     (hwm - lwm) * 4 / divisor);
522176472Skmacy	}
523180583Skmacy	t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
524167746Skmacy		     MAC_RXFIFO_SIZE * 4 * 8 / 512);
525167514Skmacy	return 0;
526167514Skmacy}
527167514Skmacy
528176472Skmacy/**
529176472Skmacy *	t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
530176472Skmacy *	@mac: the MAC to configure
531176472Skmacy *	@speed: the desired speed (10/100/1000/10000)
532176472Skmacy *	@duplex: the desired duplex
533176472Skmacy *	@fc: desired Tx/Rx PAUSE configuration
534176472Skmacy *
535176472Skmacy *	Set the MAC speed, duplex (actually only full-duplex is supported), and
536176472Skmacy *	flow control.  If a parameter value is negative the corresponding
537176472Skmacy *	MAC setting is left at its current value.
538176472Skmacy */
539167514Skmacyint t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
540167514Skmacy{
541167514Skmacy	u32 val;
542167514Skmacy	adapter_t *adap = mac->adapter;
543167514Skmacy	unsigned int oft = mac->offset;
544167514Skmacy
545167514Skmacy	if (duplex >= 0 && duplex != DUPLEX_FULL)
546167514Skmacy		return -EINVAL;
547180583Skmacy	if (mac->multiport) {
548197791Snp		u32 rx_max_pkt_size =
549197791Snp		    G_RXMAXPKTSIZE(t3_read_reg(adap,
550197791Snp					       A_XGM_RX_MAX_PKT_SIZE + oft));
551171471Skmacy		val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
552171471Skmacy		val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
553197791Snp		val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
554171471Skmacy		t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
555171471Skmacy
556171471Skmacy		t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
557171471Skmacy			  		F_TXPAUSEEN);
558170654Skmacy		return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
559171471Skmacy	}
560167514Skmacy	if (speed >= 0) {
561167514Skmacy		if (speed == SPEED_10)
562167514Skmacy			val = V_PORTSPEED(0);
563167514Skmacy		else if (speed == SPEED_100)
564167514Skmacy			val = V_PORTSPEED(1);
565167514Skmacy		else if (speed == SPEED_1000)
566167514Skmacy			val = V_PORTSPEED(2);
567167514Skmacy		else if (speed == SPEED_10000)
568167514Skmacy			val = V_PORTSPEED(3);
569167514Skmacy		else
570167514Skmacy			return -EINVAL;
571167514Skmacy
572197791Snp		if (!uses_xaui(adap)) /* T302 */
573197791Snp			t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
574197791Snp			    V_PORTSPEED(M_PORTSPEED), val);
575197791Snp		else {
576197791Snp			u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft);
577197791Snp
578197791Snp			if ((old & V_PORTSPEED(M_PORTSPEED)) != val) {
579197791Snp				t3_mac_reset(mac, val);
580197791Snp				mac->was_reset = 1;
581197791Snp			}
582197791Snp		}
583167514Skmacy	}
584170654Skmacy
585167514Skmacy	val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
586167514Skmacy	val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
587197791Snp	if (fc & PAUSE_TX) {
588197791Snp		u32 rx_max_pkt_size =
589197791Snp		    G_RXMAXPKTSIZE(t3_read_reg(adap,
590197791Snp					       A_XGM_RX_MAX_PKT_SIZE + oft));
591197791Snp		val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
592197791Snp	}
593167514Skmacy	t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
594170654Skmacy
595167514Skmacy	t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
596171471Skmacy			(fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
597167514Skmacy	return 0;
598167514Skmacy}
599167514Skmacy
600176472Skmacy/**
601176472Skmacy *	t3_mac_enable - enable the MAC in the given directions
602176472Skmacy *	@mac: the MAC to configure
603176472Skmacy *	@which: bitmap indicating which directions to enable
604176472Skmacy *
605176472Skmacy *	Enables the MAC for operation in the given directions.
606176472Skmacy *	%MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
607176472Skmacy *	enables the Rx one.
608176472Skmacy */
609167514Skmacyint t3_mac_enable(struct cmac *mac, int which)
610167514Skmacy{
611167514Skmacy	int idx = macidx(mac);
612167514Skmacy	adapter_t *adap = mac->adapter;
613167514Skmacy	unsigned int oft = mac->offset;
614169978Skmacy	struct mac_stats *s = &mac->stats;
615167514Skmacy
616170654Skmacy	if (mac->multiport)
617170654Skmacy		return t3_vsc7323_enable(adap, mac->ext_port, which);
618170654Skmacy
619167514Skmacy	if (which & MAC_DIRECTION_TX) {
620167514Skmacy		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
621176472Skmacy		t3_write_reg(adap, A_TP_PIO_DATA,
622176472Skmacy			     adap->params.rev == T3_REV_C ?
623176472Skmacy			     0xc4ffff01 : 0xc0ede401);
624167514Skmacy		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
625176472Skmacy		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
626176472Skmacy				 adap->params.rev == T3_REV_C ?
627176472Skmacy				 0 : 1 << idx);
628167746Skmacy
629171471Skmacy		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
630171471Skmacy
631167746Skmacy		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
632169978Skmacy		mac->tx_mcnt = s->tx_frames;
633169978Skmacy		mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
634169978Skmacy							       A_TP_PIO_DATA)));
635169978Skmacy		mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
636169978Skmacy						A_XGM_TX_SPI4_SOP_EOP_CNT +
637169978Skmacy						oft)));
638169978Skmacy		mac->rx_mcnt = s->rx_frames;
639172096Skmacy		mac->rx_pause = s->rx_pause;
640169978Skmacy		mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
641169978Skmacy						A_XGM_RX_SPI4_SOP_EOP_CNT +
642169978Skmacy						oft)));
643172096Skmacy		mac->rx_ocnt = s->rx_fifo_ovfl;
644167746Skmacy		mac->txen = F_TXEN;
645167746Skmacy		mac->toggle_cnt = 0;
646167514Skmacy	}
647180583Skmacy	if (which & MAC_DIRECTION_RX)
648167514Skmacy		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
649167514Skmacy	return 0;
650167514Skmacy}
651167514Skmacy
652176472Skmacy/**
653176472Skmacy *	t3_mac_disable - disable the MAC in the given directions
654176472Skmacy *	@mac: the MAC to configure
655176472Skmacy *	@which: bitmap indicating which directions to disable
656176472Skmacy *
657176472Skmacy *	Disables the MAC in the given directions.
658176472Skmacy *	%MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
659176472Skmacy *	disables the Rx one.
660176472Skmacy */
661167514Skmacyint t3_mac_disable(struct cmac *mac, int which)
662167514Skmacy{
663167514Skmacy	adapter_t *adap = mac->adapter;
664167514Skmacy
665170654Skmacy	if (mac->multiport)
666170654Skmacy		return t3_vsc7323_disable(adap, mac->ext_port, which);
667170654Skmacy
668167514Skmacy	if (which & MAC_DIRECTION_TX) {
669167514Skmacy		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
670167746Skmacy		mac->txen = 0;
671167514Skmacy	}
672169978Skmacy	if (which & MAC_DIRECTION_RX) {
673197791Snp		int val = xgm_reset_ctrl(mac);
674172096Skmacy
675169978Skmacy		t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
676169978Skmacy				 F_PCS_RESET_, 0);
677171471Skmacy		msleep(100);
678167514Skmacy		t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
679169978Skmacy		t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
680169978Skmacy	}
681167514Skmacy	return 0;
682167514Skmacy}
683167514Skmacy
684167746Skmacyint t3b2_mac_watchdog_task(struct cmac *mac)
685167746Skmacy{
686167746Skmacy	int status;
687169978Skmacy	unsigned int tx_tcnt, tx_xcnt;
688167746Skmacy	adapter_t *adap = mac->adapter;
689169978Skmacy	struct mac_stats *s = &mac->stats;
690189643Sgnn	u64 tx_mcnt = s->tx_frames;
691167746Skmacy
692189643Sgnn	if (mac->multiport)
693189643Sgnn		tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
694189643Sgnn
695169978Skmacy	status = 0;
696169978Skmacy	tx_xcnt = 1; /* By default tx_xcnt is making progress*/
697169978Skmacy	tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
698172096Skmacy	if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
699197791Snp		u32 cfg, active, enforcepkt;
700197791Snp
701169978Skmacy		tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
702189643Sgnn						      A_XGM_TX_SPI4_SOP_EOP_CNT +
703189643Sgnn						      mac->offset)));
704197791Snp		cfg = t3_read_reg(adap, A_MPS_CFG);
705197791Snp		active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE;
706197791Snp		enforcepkt = cfg & F_ENFORCEPKT;
707197791Snp		if (active && enforcepkt && (tx_xcnt == 0)) {
708169978Skmacy			t3_write_reg(adap, A_TP_PIO_ADDR,
709169978Skmacy			     	A_TP_TX_DROP_CNT_CH0 + macidx(mac));
710169978Skmacy			tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
711169978Skmacy			      	A_TP_PIO_DATA)));
712189643Sgnn		} else
713185564Sgnn			goto out;
714189643Sgnn
715169978Skmacy	} else {
716169978Skmacy		mac->toggle_cnt = 0;
717185564Sgnn		goto out;
718169978Skmacy	}
719169978Skmacy
720172096Skmacy	if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
721167746Skmacy		if (mac->toggle_cnt > 4) {
722167746Skmacy			status = 2;
723169978Skmacy			goto out;
724167746Skmacy		} else {
725167746Skmacy			status = 1;
726169978Skmacy			goto out;
727169978Skmacy		}
728167746Skmacy	} else {
729167746Skmacy		mac->toggle_cnt = 0;
730169978Skmacy		goto out;
731169978Skmacy	}
732180583Skmacy
733180583Skmacyout:
734169978Skmacy	mac->tx_tcnt = tx_tcnt;
735169978Skmacy	mac->tx_xcnt = tx_xcnt;
736169978Skmacy	mac->tx_mcnt = s->tx_frames;
737172096Skmacy	mac->rx_pause = s->rx_pause;
738169978Skmacy	if (status == 1) {
739169978Skmacy		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
740169978Skmacy		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
741169978Skmacy		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
742169978Skmacy		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
743169978Skmacy		mac->toggle_cnt++;
744169978Skmacy	} else if (status == 2) {
745197791Snp		t3_mac_reset(mac, -1);
746169978Skmacy		mac->toggle_cnt = 0;
747169978Skmacy	}
748167746Skmacy	return status;
749167746Skmacy}
750167746Skmacy
751176472Skmacy/**
752176472Skmacy *	t3_mac_update_stats - accumulate MAC statistics
753176472Skmacy *	@mac: the MAC handle
754176472Skmacy *
755176472Skmacy *	This function is called periodically to accumulate the current values
756176472Skmacy *	of the RMON counters into the port statistics.  Since the packet
757176472Skmacy *	counters are only 32 bits they can overflow in ~286 secs at 10G, so the
758176472Skmacy *	function should be called more frequently than that.  The byte counters
759176472Skmacy *	are 45-bit wide, they would overflow in ~7.8 hours.
760167514Skmacy */
761167514Skmacyconst struct mac_stats *t3_mac_update_stats(struct cmac *mac)
762167514Skmacy{
763167514Skmacy#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
764167514Skmacy#define RMON_UPDATE(mac, name, reg) \
765167514Skmacy	(mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
766167514Skmacy#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
767167514Skmacy	(mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
768167514Skmacy			     ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
769167514Skmacy
770167514Skmacy	u32 v, lo;
771167514Skmacy
772171471Skmacy	if (mac->multiport)
773171471Skmacy		return t3_vsc7323_update_stats(mac);
774171471Skmacy
775167514Skmacy	RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
776167514Skmacy	RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
777167514Skmacy	RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
778167514Skmacy	RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
779167514Skmacy	RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
780167514Skmacy	RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
781167514Skmacy	RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
782167514Skmacy	RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
783167514Skmacy	RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
784167514Skmacy
785167514Skmacy	RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
786167514Skmacy
787167746Skmacy	v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
788167746Skmacy	if (mac->adapter->params.rev == T3_REV_B2)
789167746Skmacy		v &= 0x7fffffff;
790167746Skmacy	mac->stats.rx_too_long += v;
791167746Skmacy
792167514Skmacy	RMON_UPDATE(mac, rx_frames_64,        RX_64B_FRAMES);
793167514Skmacy	RMON_UPDATE(mac, rx_frames_65_127,    RX_65_127B_FRAMES);
794167514Skmacy	RMON_UPDATE(mac, rx_frames_128_255,   RX_128_255B_FRAMES);
795167514Skmacy	RMON_UPDATE(mac, rx_frames_256_511,   RX_256_511B_FRAMES);
796167514Skmacy	RMON_UPDATE(mac, rx_frames_512_1023,  RX_512_1023B_FRAMES);
797167514Skmacy	RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
798167514Skmacy	RMON_UPDATE(mac, rx_frames_1519_max,  RX_1519_MAXB_FRAMES);
799167514Skmacy
800167514Skmacy	RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
801167514Skmacy	RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
802167514Skmacy	RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
803167514Skmacy	RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
804167514Skmacy	RMON_UPDATE(mac, tx_pause, TX_PAUSE);
805167514Skmacy	/* This counts error frames in general (bad FCS, underrun, etc). */
806167514Skmacy	RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
807167514Skmacy
808167514Skmacy	RMON_UPDATE(mac, tx_frames_64,        TX_64B_FRAMES);
809167514Skmacy	RMON_UPDATE(mac, tx_frames_65_127,    TX_65_127B_FRAMES);
810167514Skmacy	RMON_UPDATE(mac, tx_frames_128_255,   TX_128_255B_FRAMES);
811167514Skmacy	RMON_UPDATE(mac, tx_frames_256_511,   TX_256_511B_FRAMES);
812167514Skmacy	RMON_UPDATE(mac, tx_frames_512_1023,  TX_512_1023B_FRAMES);
813167514Skmacy	RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
814167514Skmacy	RMON_UPDATE(mac, tx_frames_1519_max,  TX_1519_MAXB_FRAMES);
815167514Skmacy
816167514Skmacy	/* The next stat isn't clear-on-read. */
817167514Skmacy	t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
818167514Skmacy	v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
819167514Skmacy	lo = (u32)mac->stats.rx_cong_drops;
820167514Skmacy	mac->stats.rx_cong_drops += (u64)(v - lo);
821167514Skmacy
822167514Skmacy	return &mac->stats;
823167514Skmacy}
824