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