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 */
411struct t3_mcaddr_ctx {
412	struct cmac *mac;
413	u32 hash_lo, hash_hi;
414};
415
416static u_int
417t3_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
418{
419	struct t3_mcaddr_ctx *ctx = arg;
420	int hash;
421
422	if (ctx->mac->nucast + cnt < EXACT_ADDR_FILTERS)
423		set_addr_filter(ctx->mac, ctx->mac->nucast + cnt, LLADDR(sdl));
424	else {
425		hash = hash_hw_addr(LLADDR(sdl));
426		if (hash < 32)
427			ctx->hash_lo |= (1 << hash);
428		else
429			ctx->hash_hi |= (1 << (hash - 32));
430	}
431	return (1);
432}
433
434int t3_mac_set_rx_mode(struct cmac *mac, struct t3_rx_mode *rm)
435{
436	struct t3_mcaddr_ctx ctx;
437	adapter_t *adap = mac->adapter;
438	unsigned int oft = mac->offset;
439
440	if (promisc_rx_mode(rm))
441		mac->promisc_map |= 1 << mac->ext_port;
442	else
443		mac->promisc_map &= ~(1 << mac->ext_port);
444	t3_set_reg_field(adap, A_XGM_RX_CFG + oft, F_COPYALLFRAMES,
445			 mac->promisc_map ? F_COPYALLFRAMES : 0);
446
447	if (allmulti_rx_mode(rm) || mac->multiport)
448		ctx.hash_lo = ctx.hash_hi = 0xffffffff;
449	else {
450		ctx.mac = mac;
451		ctx.hash_lo = ctx.hash_hi = 0;
452		if_foreach_llmaddr(rm->port->ifp, t3_hash_maddr, &ctx);
453	}
454
455	t3_write_reg(adap, A_XGM_RX_HASH_LOW + oft, ctx.hash_lo);
456	t3_write_reg(adap, A_XGM_RX_HASH_HIGH + oft, ctx.hash_hi);
457	return 0;
458}
459
460static int rx_fifo_hwm(int mtu)
461{
462	int hwm;
463
464	hwm = max(MAC_RXFIFO_SIZE - 3 * mtu, (MAC_RXFIFO_SIZE * 38) / 100);
465	return min(hwm, MAC_RXFIFO_SIZE - 8192);
466}
467
468/**
469 *	t3_mac_set_mtu - set the MAC MTU
470 *	@mac: the MAC to configure
471 *	@mtu: the MTU
472 *
473 *	Sets the MAC MTU and adjusts the FIFO PAUSE watermarks accordingly.
474 */
475int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
476{
477	int hwm, lwm;
478	int ipg;
479	unsigned int thres, v, reg;
480	adapter_t *adap = mac->adapter;
481	unsigned port_type = adap->params.vpd.port_type[macidx(mac)];
482	unsigned int orig_mtu=mtu;
483
484	/*
485	 * MAX_FRAME_SIZE inludes header + FCS, mtu doesn't.  The HW max
486	 * packet size register includes header, but not FCS.
487	 */
488	mtu += 14;
489	if (mac->multiport)
490		mtu += 8;                             /* for preamble */
491	if (mtu > MAX_FRAME_SIZE - 4)
492		return -EINVAL;
493	if (mac->multiport)
494		return t3_vsc7323_set_mtu(adap, mtu - 4, mac->ext_port);
495
496	/* Modify the TX and RX fifo depth only if the card has a vsc8211 phy */
497	if (port_type == 2) {
498		int err = t3_vsc8211_fifo_depth(adap,orig_mtu,macidx(mac));
499
500		if (err)
501			return err;
502	}
503
504	if (adap->params.rev >= T3_REV_B2 &&
505	    (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
506		t3_mac_disable_exact_filters(mac);
507		v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
508		t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
509				 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
510
511		reg = adap->params.rev == T3_REV_B2 ?
512			A_XGM_RX_MAX_PKT_SIZE_ERR_CNT : A_XGM_RXFIFO_CFG;
513
514		/* drain RX FIFO */
515		if (t3_wait_op_done(adap, reg + mac->offset,
516				    F_RXFIFO_EMPTY, 1, 20, 5)) {
517			t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
518			t3_mac_enable_exact_filters(mac);
519			return -EIO;
520		}
521		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
522				 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
523				 V_RXMAXPKTSIZE(mtu));
524		t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
525		t3_mac_enable_exact_filters(mac);
526	} else
527		t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
528				 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
529				 V_RXMAXPKTSIZE(mtu));
530	/*
531	 * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
532	 * HWM only if flow-control is enabled.
533	 */
534	hwm = rx_fifo_hwm(mtu);
535	lwm = min(3 * (int) mtu, MAC_RXFIFO_SIZE /4);
536	v = t3_read_reg(adap, A_XGM_RXFIFO_CFG + mac->offset);
537	v &= ~V_RXFIFOPAUSELWM(M_RXFIFOPAUSELWM);
538	v |= V_RXFIFOPAUSELWM(lwm / 8);
539	if (G_RXFIFOPAUSEHWM(v))
540		v = (v & ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM)) |
541		    V_RXFIFOPAUSEHWM(hwm / 8);
542
543	t3_write_reg(adap, A_XGM_RXFIFO_CFG + mac->offset, v);
544
545	/* Adjust the TX FIFO threshold based on the MTU */
546	thres = (adap->params.vpd.cclk * 1000) / 15625;
547	thres = (thres * mtu) / 1000;
548	if (is_10G(adap))
549		thres /= 10;
550	thres = mtu > thres ? (mtu - thres + 7) / 8 : 0;
551	thres = max(thres, 8U);                          /* need at least 8 */
552	ipg = (port_type == 9 || adap->params.rev != T3_REV_C) ? 1 : 0;
553	t3_set_reg_field(adap, A_XGM_TXFIFO_CFG + mac->offset,
554			 V_TXFIFOTHRESH(M_TXFIFOTHRESH) | V_TXIPG(M_TXIPG),
555			 V_TXFIFOTHRESH(thres) | V_TXIPG(ipg));
556	return 0;
557}
558
559/**
560 *	t3_mac_set_speed_duplex_fc - set MAC speed, duplex and flow control
561 *	@mac: the MAC to configure
562 *	@speed: the desired speed (10/100/1000/10000)
563 *	@duplex: the desired duplex
564 *	@fc: desired Tx/Rx PAUSE configuration
565 *
566 *	Set the MAC speed, duplex (actually only full-duplex is supported), and
567 *	flow control.  If a parameter value is negative the corresponding
568 *	MAC setting is left at its current value.
569 */
570int t3_mac_set_speed_duplex_fc(struct cmac *mac, int speed, int duplex, int fc)
571{
572	u32 val;
573	adapter_t *adap = mac->adapter;
574	unsigned int oft = mac->offset;
575	unsigned int pause_bits;
576
577	if (duplex >= 0 && duplex != DUPLEX_FULL)
578		return -EINVAL;
579
580	pause_bits = MAC_RXFIFO_SIZE * 4 * 8;
581	t3_write_reg(adap, A_XGM_TX_PAUSE_QUANTA + mac->offset,
582		     pause_bits / 512);
583	t3_write_reg(adap, A_XGM_PAUSE_TIMER + mac->offset,
584		     (pause_bits >> (adap->params.rev == T3_REV_C ? 10 : 7)));
585
586	if (mac->multiport) {
587		u32 rx_max_pkt_size =
588		    G_RXMAXPKTSIZE(t3_read_reg(adap,
589					       A_XGM_RX_MAX_PKT_SIZE + oft));
590		val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
591		val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
592		val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
593		t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
594		t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
595			  		F_TXPAUSEEN);
596
597		return t3_vsc7323_set_speed_fc(adap, speed, fc, mac->ext_port);
598	}
599	if (speed >= 0) {
600		if (speed == SPEED_10)
601			val = V_PORTSPEED(0);
602		else if (speed == SPEED_100)
603			val = V_PORTSPEED(1);
604		else if (speed == SPEED_1000)
605			val = V_PORTSPEED(2);
606		else if (speed == SPEED_10000)
607			val = V_PORTSPEED(3);
608		else
609			return -EINVAL;
610
611		if (!uses_xaui(adap)) /* T302 */
612			t3_set_reg_field(adap, A_XGM_PORT_CFG + oft,
613			    V_PORTSPEED(M_PORTSPEED), val);
614		else {
615			u32 old = t3_read_reg(adap, A_XGM_PORT_CFG + oft);
616
617			if ((old & V_PORTSPEED(M_PORTSPEED)) != val) {
618				t3_mac_reset(mac, val);
619				mac->was_reset = 1;
620			}
621		}
622	}
623
624	val = t3_read_reg(adap, A_XGM_RXFIFO_CFG + oft);
625	val &= ~V_RXFIFOPAUSEHWM(M_RXFIFOPAUSEHWM);
626	if (fc & PAUSE_TX) {
627		u32 rx_max_pkt_size =
628		    G_RXMAXPKTSIZE(t3_read_reg(adap,
629					       A_XGM_RX_MAX_PKT_SIZE + oft));
630		val |= V_RXFIFOPAUSEHWM(rx_fifo_hwm(rx_max_pkt_size) / 8);
631	}
632	t3_write_reg(adap, A_XGM_RXFIFO_CFG + oft, val);
633
634	t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN,
635			(fc & PAUSE_RX) ? F_TXPAUSEEN : 0);
636	return 0;
637}
638
639/**
640 *	t3_mac_enable - enable the MAC in the given directions
641 *	@mac: the MAC to configure
642 *	@which: bitmap indicating which directions to enable
643 *
644 *	Enables the MAC for operation in the given directions.
645 *	%MAC_DIRECTION_TX enables the Tx direction, and %MAC_DIRECTION_RX
646 *	enables the Rx one.
647 */
648int t3_mac_enable(struct cmac *mac, int which)
649{
650	int idx = macidx(mac);
651	adapter_t *adap = mac->adapter;
652	unsigned int oft = mac->offset;
653	struct mac_stats *s = &mac->stats;
654
655	if (mac->multiport)
656		return t3_vsc7323_enable(adap, mac->ext_port, which);
657
658	if (which & MAC_DIRECTION_TX) {
659		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
660		t3_write_reg(adap, A_TP_PIO_DATA,
661			     adap->params.rev == T3_REV_C ?
662			     0xc4ffff01 : 0xc0ede401);
663		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
664		t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
665				 adap->params.rev == T3_REV_C ?
666				 0 : 1 << idx);
667
668		t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
669
670		t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CNT_CH0 + idx);
671		mac->tx_mcnt = s->tx_frames;
672		mac->tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
673							       A_TP_PIO_DATA)));
674		mac->tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
675						A_XGM_TX_SPI4_SOP_EOP_CNT +
676						oft)));
677		mac->rx_mcnt = s->rx_frames;
678		mac->rx_pause = s->rx_pause;
679		mac->rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
680						A_XGM_RX_SPI4_SOP_EOP_CNT +
681						oft)));
682		mac->rx_ocnt = s->rx_fifo_ovfl;
683		mac->txen = F_TXEN;
684		mac->toggle_cnt = 0;
685	}
686	if (which & MAC_DIRECTION_RX)
687		t3_write_reg(adap, A_XGM_RX_CTRL + oft, F_RXEN);
688	return 0;
689}
690
691/**
692 *	t3_mac_disable - disable the MAC in the given directions
693 *	@mac: the MAC to configure
694 *	@which: bitmap indicating which directions to disable
695 *
696 *	Disables the MAC in the given directions.
697 *	%MAC_DIRECTION_TX disables the Tx direction, and %MAC_DIRECTION_RX
698 *	disables the Rx one.
699 */
700int t3_mac_disable(struct cmac *mac, int which)
701{
702	adapter_t *adap = mac->adapter;
703
704	if (mac->multiport)
705		return t3_vsc7323_disable(adap, mac->ext_port, which);
706
707	if (which & MAC_DIRECTION_TX) {
708		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
709		mac->txen = 0;
710	}
711	if (which & MAC_DIRECTION_RX) {
712		int val = xgm_reset_ctrl(mac);
713
714		t3_set_reg_field(mac->adapter, A_XGM_RESET_CTRL + mac->offset,
715				 F_PCS_RESET_, 0);
716		msleep(100);
717		t3_write_reg(adap, A_XGM_RX_CTRL + mac->offset, 0);
718		t3_write_reg(mac->adapter, A_XGM_RESET_CTRL + mac->offset, val);
719	}
720	return 0;
721}
722
723int t3b2_mac_watchdog_task(struct cmac *mac)
724{
725	int status;
726	unsigned int tx_tcnt, tx_xcnt;
727	adapter_t *adap = mac->adapter;
728	struct mac_stats *s = &mac->stats;
729	u64 tx_mcnt = s->tx_frames;
730
731	if (mac->multiport)
732		tx_mcnt = t3_read_reg(adap, A_XGM_STAT_TX_FRAME_LOW);
733
734	status = 0;
735	tx_xcnt = 1; /* By default tx_xcnt is making progress*/
736	tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt*/
737	if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
738		u32 cfg, active, enforcepkt;
739
740		tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
741						      A_XGM_TX_SPI4_SOP_EOP_CNT +
742						      mac->offset)));
743		cfg = t3_read_reg(adap, A_MPS_CFG);
744		active = macidx(mac) ? cfg & F_PORT1ACTIVE : cfg & F_PORT0ACTIVE;
745		enforcepkt = cfg & F_ENFORCEPKT;
746		if (active && enforcepkt && (tx_xcnt == 0)) {
747			t3_write_reg(adap, A_TP_PIO_ADDR,
748			     	A_TP_TX_DROP_CNT_CH0 + macidx(mac));
749			tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
750			      	A_TP_PIO_DATA)));
751		} else
752			goto out;
753
754	} else {
755		mac->toggle_cnt = 0;
756		goto out;
757	}
758
759	if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
760		if (mac->toggle_cnt > 4) {
761			status = 2;
762			goto out;
763		} else {
764			status = 1;
765			goto out;
766		}
767	} else {
768		mac->toggle_cnt = 0;
769		goto out;
770	}
771
772out:
773	mac->tx_tcnt = tx_tcnt;
774	mac->tx_xcnt = tx_xcnt;
775	mac->tx_mcnt = s->tx_frames;
776	mac->rx_pause = s->rx_pause;
777	if (status == 1) {
778		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
779		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
780		t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, mac->txen);
781		t3_read_reg(adap, A_XGM_TX_CTRL + mac->offset);  /* flush */
782		mac->toggle_cnt++;
783	} else if (status == 2) {
784		t3_mac_reset(mac, -1);
785		mac->toggle_cnt = 0;
786	}
787	return status;
788}
789
790/**
791 *	t3_mac_update_stats - accumulate MAC statistics
792 *	@mac: the MAC handle
793 *
794 *	This function is called periodically to accumulate the current values
795 *	of the RMON counters into the port statistics.  Since the packet
796 *	counters are only 32 bits they can overflow in ~286 secs at 10G, so the
797 *	function should be called more frequently than that.  The byte counters
798 *	are 45-bit wide, they would overflow in ~7.8 hours.
799 */
800const struct mac_stats *t3_mac_update_stats(struct cmac *mac)
801{
802#define RMON_READ(mac, addr) t3_read_reg(mac->adapter, addr + mac->offset)
803#define RMON_UPDATE(mac, name, reg) \
804	(mac)->stats.name += (u64)RMON_READ(mac, A_XGM_STAT_##reg)
805#define RMON_UPDATE64(mac, name, reg_lo, reg_hi) \
806	(mac)->stats.name += RMON_READ(mac, A_XGM_STAT_##reg_lo) + \
807			     ((u64)RMON_READ(mac, A_XGM_STAT_##reg_hi) << 32)
808
809	u32 v, lo;
810
811	if (mac->multiport)
812		return t3_vsc7323_update_stats(mac);
813
814	RMON_UPDATE64(mac, rx_octets, RX_BYTES_LOW, RX_BYTES_HIGH);
815	RMON_UPDATE64(mac, rx_frames, RX_FRAMES_LOW, RX_FRAMES_HIGH);
816	RMON_UPDATE(mac, rx_mcast_frames, RX_MCAST_FRAMES);
817	RMON_UPDATE(mac, rx_bcast_frames, RX_BCAST_FRAMES);
818	RMON_UPDATE(mac, rx_fcs_errs, RX_CRC_ERR_FRAMES);
819	RMON_UPDATE(mac, rx_pause, RX_PAUSE_FRAMES);
820	RMON_UPDATE(mac, rx_jabber, RX_JABBER_FRAMES);
821	RMON_UPDATE(mac, rx_short, RX_SHORT_FRAMES);
822	RMON_UPDATE(mac, rx_symbol_errs, RX_SYM_CODE_ERR_FRAMES);
823
824	RMON_UPDATE(mac, rx_too_long, RX_OVERSIZE_FRAMES);
825
826	v = RMON_READ(mac, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT);
827	if (mac->adapter->params.rev == T3_REV_B2)
828		v &= 0x7fffffff;
829	mac->stats.rx_too_long += v;
830
831	RMON_UPDATE(mac, rx_frames_64,        RX_64B_FRAMES);
832	RMON_UPDATE(mac, rx_frames_65_127,    RX_65_127B_FRAMES);
833	RMON_UPDATE(mac, rx_frames_128_255,   RX_128_255B_FRAMES);
834	RMON_UPDATE(mac, rx_frames_256_511,   RX_256_511B_FRAMES);
835	RMON_UPDATE(mac, rx_frames_512_1023,  RX_512_1023B_FRAMES);
836	RMON_UPDATE(mac, rx_frames_1024_1518, RX_1024_1518B_FRAMES);
837	RMON_UPDATE(mac, rx_frames_1519_max,  RX_1519_MAXB_FRAMES);
838
839	RMON_UPDATE64(mac, tx_octets, TX_BYTE_LOW, TX_BYTE_HIGH);
840	RMON_UPDATE64(mac, tx_frames, TX_FRAME_LOW, TX_FRAME_HIGH);
841	RMON_UPDATE(mac, tx_mcast_frames, TX_MCAST);
842	RMON_UPDATE(mac, tx_bcast_frames, TX_BCAST);
843	RMON_UPDATE(mac, tx_pause, TX_PAUSE);
844	/* This counts error frames in general (bad FCS, underrun, etc). */
845	RMON_UPDATE(mac, tx_underrun, TX_ERR_FRAMES);
846
847	RMON_UPDATE(mac, tx_frames_64,        TX_64B_FRAMES);
848	RMON_UPDATE(mac, tx_frames_65_127,    TX_65_127B_FRAMES);
849	RMON_UPDATE(mac, tx_frames_128_255,   TX_128_255B_FRAMES);
850	RMON_UPDATE(mac, tx_frames_256_511,   TX_256_511B_FRAMES);
851	RMON_UPDATE(mac, tx_frames_512_1023,  TX_512_1023B_FRAMES);
852	RMON_UPDATE(mac, tx_frames_1024_1518, TX_1024_1518B_FRAMES);
853	RMON_UPDATE(mac, tx_frames_1519_max,  TX_1519_MAXB_FRAMES);
854
855	/* The next stat isn't clear-on-read. */
856	t3_write_reg(mac->adapter, A_TP_MIB_INDEX, mac->offset ? 51 : 50);
857	v = t3_read_reg(mac->adapter, A_TP_MIB_RDATA);
858	lo = (u32)mac->stats.rx_cong_drops;
859	mac->stats.rx_cong_drops += (u64)(v - lo);
860
861	return &mac->stats;
862}
863