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