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