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