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