1f7917c00SJeff Kirsher /*
2f7917c00SJeff Kirsher  * Copyright (c) 2003-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 #include "sge_defs.h"
35f7917c00SJeff Kirsher #include "firmware_exports.h"
36f7917c00SJeff Kirsher 
37f7917c00SJeff Kirsher static void t3_port_intr_clear(struct adapter *adapter, int idx);
38f7917c00SJeff Kirsher 
39f7917c00SJeff Kirsher /**
40f7917c00SJeff Kirsher  *	t3_wait_op_done_val - wait until an operation is completed
41f7917c00SJeff Kirsher  *	@adapter: the adapter performing the operation
42f7917c00SJeff Kirsher  *	@reg: the register to check for completion
43f7917c00SJeff Kirsher  *	@mask: a single-bit field within @reg that indicates completion
44f7917c00SJeff Kirsher  *	@polarity: the value of the field when the operation is completed
45f7917c00SJeff Kirsher  *	@attempts: number of check iterations
46f7917c00SJeff Kirsher  *	@delay: delay in usecs between iterations
47f7917c00SJeff Kirsher  *	@valp: where to store the value of the register at completion time
48f7917c00SJeff Kirsher  *
49f7917c00SJeff Kirsher  *	Wait until an operation is completed by checking a bit in a register
50f7917c00SJeff Kirsher  *	up to @attempts times.  If @valp is not NULL the value of the register
51f7917c00SJeff Kirsher  *	at the time it indicated completion is stored there.  Returns 0 if the
52f7917c00SJeff Kirsher  *	operation completes and -EAGAIN otherwise.
53f7917c00SJeff Kirsher  */
54f7917c00SJeff Kirsher 
55f7917c00SJeff Kirsher int t3_wait_op_done_val(struct adapter *adapter, int reg, u32 mask,
56f7917c00SJeff Kirsher 			int polarity, int attempts, int delay, u32 *valp)
57f7917c00SJeff Kirsher {
58f7917c00SJeff Kirsher 	while (1) {
59f7917c00SJeff Kirsher 		u32 val = t3_read_reg(adapter, reg);
60f7917c00SJeff Kirsher 
61f7917c00SJeff Kirsher 		if (!!(val & mask) == polarity) {
62f7917c00SJeff Kirsher 			if (valp)
63f7917c00SJeff Kirsher 				*valp = val;
64f7917c00SJeff Kirsher 			return 0;
65f7917c00SJeff Kirsher 		}
66f7917c00SJeff Kirsher 		if (--attempts == 0)
67f7917c00SJeff Kirsher 			return -EAGAIN;
68f7917c00SJeff Kirsher 		if (delay)
69f7917c00SJeff Kirsher 			udelay(delay);
70f7917c00SJeff Kirsher 	}
71f7917c00SJeff Kirsher }
72f7917c00SJeff Kirsher 
73f7917c00SJeff Kirsher /**
74f7917c00SJeff Kirsher  *	t3_write_regs - write a bunch of registers
75f7917c00SJeff Kirsher  *	@adapter: the adapter to program
76f7917c00SJeff Kirsher  *	@p: an array of register address/register value pairs
77f7917c00SJeff Kirsher  *	@n: the number of address/value pairs
78f7917c00SJeff Kirsher  *	@offset: register address offset
79f7917c00SJeff Kirsher  *
80f7917c00SJeff Kirsher  *	Takes an array of register address/register value pairs and writes each
81f7917c00SJeff Kirsher  *	value to the corresponding register.  Register addresses are adjusted
82f7917c00SJeff Kirsher  *	by the supplied offset.
83f7917c00SJeff Kirsher  */
84f7917c00SJeff Kirsher void t3_write_regs(struct adapter *adapter, const struct addr_val_pair *p,
85f7917c00SJeff Kirsher 		   int n, unsigned int offset)
86f7917c00SJeff Kirsher {
87f7917c00SJeff Kirsher 	while (n--) {
88f7917c00SJeff Kirsher 		t3_write_reg(adapter, p->reg_addr + offset, p->val);
89f7917c00SJeff Kirsher 		p++;
90f7917c00SJeff Kirsher 	}
91f7917c00SJeff Kirsher }
92f7917c00SJeff Kirsher 
93f7917c00SJeff Kirsher /**
94f7917c00SJeff Kirsher  *	t3_set_reg_field - set a register field to a value
95f7917c00SJeff Kirsher  *	@adapter: the adapter to program
96f7917c00SJeff Kirsher  *	@addr: the register address
97f7917c00SJeff Kirsher  *	@mask: specifies the portion of the register to modify
98f7917c00SJeff Kirsher  *	@val: the new value for the register field
99f7917c00SJeff Kirsher  *
100f7917c00SJeff Kirsher  *	Sets a register field specified by the supplied mask to the
101f7917c00SJeff Kirsher  *	given value.
102f7917c00SJeff Kirsher  */
103f7917c00SJeff Kirsher void t3_set_reg_field(struct adapter *adapter, unsigned int addr, u32 mask,
104f7917c00SJeff Kirsher 		      u32 val)
105f7917c00SJeff Kirsher {
106f7917c00SJeff Kirsher 	u32 v = t3_read_reg(adapter, addr) & ~mask;
107f7917c00SJeff Kirsher 
108f7917c00SJeff Kirsher 	t3_write_reg(adapter, addr, v | val);
109f7917c00SJeff Kirsher 	t3_read_reg(adapter, addr);	/* flush */
110f7917c00SJeff Kirsher }
111f7917c00SJeff Kirsher 
112f7917c00SJeff Kirsher /**
113f7917c00SJeff Kirsher  *	t3_read_indirect - read indirectly addressed registers
114f7917c00SJeff Kirsher  *	@adap: the adapter
115f7917c00SJeff Kirsher  *	@addr_reg: register holding the indirect address
116f7917c00SJeff Kirsher  *	@data_reg: register holding the value of the indirect register
117f7917c00SJeff Kirsher  *	@vals: where the read register values are stored
118f7917c00SJeff Kirsher  *	@start_idx: index of first indirect register to read
119f7917c00SJeff Kirsher  *	@nregs: how many indirect registers to read
120f7917c00SJeff Kirsher  *
121f7917c00SJeff Kirsher  *	Reads registers that are accessed indirectly through an address/data
122f7917c00SJeff Kirsher  *	register pair.
123f7917c00SJeff Kirsher  */
124f7917c00SJeff Kirsher static void t3_read_indirect(struct adapter *adap, unsigned int addr_reg,
125f7917c00SJeff Kirsher 			     unsigned int data_reg, u32 *vals,
126f7917c00SJeff Kirsher 			     unsigned int nregs, unsigned int start_idx)
127f7917c00SJeff Kirsher {
128f7917c00SJeff Kirsher 	while (nregs--) {
129f7917c00SJeff Kirsher 		t3_write_reg(adap, addr_reg, start_idx);
130f7917c00SJeff Kirsher 		*vals++ = t3_read_reg(adap, data_reg);
131f7917c00SJeff Kirsher 		start_idx++;
132f7917c00SJeff Kirsher 	}
133f7917c00SJeff Kirsher }
134f7917c00SJeff Kirsher 
135f7917c00SJeff Kirsher /**
136f7917c00SJeff Kirsher  *	t3_mc7_bd_read - read from MC7 through backdoor accesses
137f7917c00SJeff Kirsher  *	@mc7: identifies MC7 to read from
138f7917c00SJeff Kirsher  *	@start: index of first 64-bit word to read
139f7917c00SJeff Kirsher  *	@n: number of 64-bit words to read
140f7917c00SJeff Kirsher  *	@buf: where to store the read result
141f7917c00SJeff Kirsher  *
142f7917c00SJeff Kirsher  *	Read n 64-bit words from MC7 starting at word start, using backdoor
143f7917c00SJeff Kirsher  *	accesses.
144f7917c00SJeff Kirsher  */
145f7917c00SJeff Kirsher int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
146f7917c00SJeff Kirsher 		   u64 *buf)
147f7917c00SJeff Kirsher {
148f7917c00SJeff Kirsher 	static const int shift[] = { 0, 0, 16, 24 };
149f7917c00SJeff Kirsher 	static const int step[] = { 0, 32, 16, 8 };
150f7917c00SJeff Kirsher 
151f7917c00SJeff Kirsher 	unsigned int size64 = mc7->size / 8;	/* # of 64-bit words */
152f7917c00SJeff Kirsher 	struct adapter *adap = mc7->adapter;
153f7917c00SJeff Kirsher 
154f7917c00SJeff Kirsher 	if (start >= size64 || start + n > size64)
155f7917c00SJeff Kirsher 		return -EINVAL;
156f7917c00SJeff Kirsher 
157f7917c00SJeff Kirsher 	start *= (8 << mc7->width);
158f7917c00SJeff Kirsher 	while (n--) {
159f7917c00SJeff Kirsher 		int i;
160f7917c00SJeff Kirsher 		u64 val64 = 0;
161f7917c00SJeff Kirsher 
162f7917c00SJeff Kirsher 		for (i = (1 << mc7->width) - 1; i >= 0; --i) {
163f7917c00SJeff Kirsher 			int attempts = 10;
164f7917c00SJeff Kirsher 			u32 val;
165f7917c00SJeff Kirsher 
166f7917c00SJeff Kirsher 			t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR, start);
167f7917c00SJeff Kirsher 			t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
168f7917c00SJeff Kirsher 			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
169f7917c00SJeff Kirsher 			while ((val & F_BUSY) && attempts--)
170f7917c00SJeff Kirsher 				val = t3_read_reg(adap,
171f7917c00SJeff Kirsher 						  mc7->offset + A_MC7_BD_OP);
172f7917c00SJeff Kirsher 			if (val & F_BUSY)
173f7917c00SJeff Kirsher 				return -EIO;
174f7917c00SJeff Kirsher 
175f7917c00SJeff Kirsher 			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
176f7917c00SJeff Kirsher 			if (mc7->width == 0) {
177f7917c00SJeff Kirsher 				val64 = t3_read_reg(adap,
178f7917c00SJeff Kirsher 						    mc7->offset +
179f7917c00SJeff Kirsher 						    A_MC7_BD_DATA0);
180f7917c00SJeff Kirsher 				val64 |= (u64) val << 32;
181f7917c00SJeff Kirsher 			} else {
182f7917c00SJeff Kirsher 				if (mc7->width > 1)
183f7917c00SJeff Kirsher 					val >>= shift[mc7->width];
184f7917c00SJeff Kirsher 				val64 |= (u64) val << (step[mc7->width] * i);
185f7917c00SJeff Kirsher 			}
186f7917c00SJeff Kirsher 			start += 8;
187f7917c00SJeff Kirsher 		}
188f7917c00SJeff Kirsher 		*buf++ = val64;
189f7917c00SJeff Kirsher 	}
190f7917c00SJeff Kirsher 	return 0;
191f7917c00SJeff Kirsher }
192f7917c00SJeff Kirsher 
193f7917c00SJeff Kirsher /*
194f7917c00SJeff Kirsher  * Initialize MI1.
195f7917c00SJeff Kirsher  */
196f7917c00SJeff Kirsher static void mi1_init(struct adapter *adap, const struct adapter_info *ai)
197f7917c00SJeff Kirsher {
198f7917c00SJeff Kirsher 	u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
199f7917c00SJeff Kirsher 	u32 val = F_PREEN | V_CLKDIV(clkdiv);
200f7917c00SJeff Kirsher 
201f7917c00SJeff Kirsher 	t3_write_reg(adap, A_MI1_CFG, val);
202f7917c00SJeff Kirsher }
203f7917c00SJeff Kirsher 
204f7917c00SJeff Kirsher #define MDIO_ATTEMPTS 20
205f7917c00SJeff Kirsher 
206f7917c00SJeff Kirsher /*
207f7917c00SJeff Kirsher  * MI1 read/write operations for clause 22 PHYs.
208f7917c00SJeff Kirsher  */
209f7917c00SJeff Kirsher static int t3_mi1_read(struct net_device *dev, int phy_addr, int mmd_addr,
210f7917c00SJeff Kirsher 		       u16 reg_addr)
211f7917c00SJeff Kirsher {
212f7917c00SJeff Kirsher 	struct port_info *pi = netdev_priv(dev);
213f7917c00SJeff Kirsher 	struct adapter *adapter = pi->adapter;
214f7917c00SJeff Kirsher 	int ret;
215f7917c00SJeff Kirsher 	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
216f7917c00SJeff Kirsher 
217f7917c00SJeff Kirsher 	mutex_lock(&adapter->mdio_lock);
218f7917c00SJeff Kirsher 	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
219f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_ADDR, addr);
220f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
221f7917c00SJeff Kirsher 	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
222f7917c00SJeff Kirsher 	if (!ret)
223f7917c00SJeff Kirsher 		ret = t3_read_reg(adapter, A_MI1_DATA);
224f7917c00SJeff Kirsher 	mutex_unlock(&adapter->mdio_lock);
225f7917c00SJeff Kirsher 	return ret;
226f7917c00SJeff Kirsher }
227f7917c00SJeff Kirsher 
228f7917c00SJeff Kirsher static int t3_mi1_write(struct net_device *dev, int phy_addr, int mmd_addr,
229f7917c00SJeff Kirsher 			u16 reg_addr, u16 val)
230f7917c00SJeff Kirsher {
231f7917c00SJeff Kirsher 	struct port_info *pi = netdev_priv(dev);
232f7917c00SJeff Kirsher 	struct adapter *adapter = pi->adapter;
233f7917c00SJeff Kirsher 	int ret;
234f7917c00SJeff Kirsher 	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
235f7917c00SJeff Kirsher 
236f7917c00SJeff Kirsher 	mutex_lock(&adapter->mdio_lock);
237f7917c00SJeff Kirsher 	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
238f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_ADDR, addr);
239f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_DATA, val);
240f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
241f7917c00SJeff Kirsher 	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
242f7917c00SJeff Kirsher 	mutex_unlock(&adapter->mdio_lock);
243f7917c00SJeff Kirsher 	return ret;
244f7917c00SJeff Kirsher }
245f7917c00SJeff Kirsher 
246f7917c00SJeff Kirsher static const struct mdio_ops mi1_mdio_ops = {
247f7917c00SJeff Kirsher 	.read = t3_mi1_read,
248f7917c00SJeff Kirsher 	.write = t3_mi1_write,
249f7917c00SJeff Kirsher 	.mode_support = MDIO_SUPPORTS_C22
250f7917c00SJeff Kirsher };
251f7917c00SJeff Kirsher 
252f7917c00SJeff Kirsher /*
253f7917c00SJeff Kirsher  * Performs the address cycle for clause 45 PHYs.
254f7917c00SJeff Kirsher  * Must be called with the MDIO_LOCK held.
255f7917c00SJeff Kirsher  */
256f7917c00SJeff Kirsher static int mi1_wr_addr(struct adapter *adapter, int phy_addr, int mmd_addr,
257f7917c00SJeff Kirsher 		       int reg_addr)
258f7917c00SJeff Kirsher {
259f7917c00SJeff Kirsher 	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
260f7917c00SJeff Kirsher 
261f7917c00SJeff Kirsher 	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0);
262f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_ADDR, addr);
263f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
264f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
265f7917c00SJeff Kirsher 	return t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
266f7917c00SJeff Kirsher 			       MDIO_ATTEMPTS, 10);
267f7917c00SJeff Kirsher }
268f7917c00SJeff Kirsher 
269f7917c00SJeff Kirsher /*
270f7917c00SJeff Kirsher  * MI1 read/write operations for indirect-addressed PHYs.
271f7917c00SJeff Kirsher  */
272f7917c00SJeff Kirsher static int mi1_ext_read(struct net_device *dev, int phy_addr, int mmd_addr,
273f7917c00SJeff Kirsher 			u16 reg_addr)
274f7917c00SJeff Kirsher {
275f7917c00SJeff Kirsher 	struct port_info *pi = netdev_priv(dev);
276f7917c00SJeff Kirsher 	struct adapter *adapter = pi->adapter;
277f7917c00SJeff Kirsher 	int ret;
278f7917c00SJeff Kirsher 
279f7917c00SJeff Kirsher 	mutex_lock(&adapter->mdio_lock);
280f7917c00SJeff Kirsher 	ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
281f7917c00SJeff Kirsher 	if (!ret) {
282f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
283f7917c00SJeff Kirsher 		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
284f7917c00SJeff Kirsher 				      MDIO_ATTEMPTS, 10);
285f7917c00SJeff Kirsher 		if (!ret)
286f7917c00SJeff Kirsher 			ret = t3_read_reg(adapter, A_MI1_DATA);
287f7917c00SJeff Kirsher 	}
288f7917c00SJeff Kirsher 	mutex_unlock(&adapter->mdio_lock);
289f7917c00SJeff Kirsher 	return ret;
290f7917c00SJeff Kirsher }
291f7917c00SJeff Kirsher 
292f7917c00SJeff Kirsher static int mi1_ext_write(struct net_device *dev, int phy_addr, int mmd_addr,
293f7917c00SJeff Kirsher 			 u16 reg_addr, u16 val)
294f7917c00SJeff Kirsher {
295f7917c00SJeff Kirsher 	struct port_info *pi = netdev_priv(dev);
296f7917c00SJeff Kirsher 	struct adapter *adapter = pi->adapter;
297f7917c00SJeff Kirsher 	int ret;
298f7917c00SJeff Kirsher 
299f7917c00SJeff Kirsher 	mutex_lock(&adapter->mdio_lock);
300f7917c00SJeff Kirsher 	ret = mi1_wr_addr(adapter, phy_addr, mmd_addr, reg_addr);
301f7917c00SJeff Kirsher 	if (!ret) {
302f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_MI1_DATA, val);
303f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
304f7917c00SJeff Kirsher 		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
305f7917c00SJeff Kirsher 				      MDIO_ATTEMPTS, 10);
306f7917c00SJeff Kirsher 	}
307f7917c00SJeff Kirsher 	mutex_unlock(&adapter->mdio_lock);
308f7917c00SJeff Kirsher 	return ret;
309f7917c00SJeff Kirsher }
310f7917c00SJeff Kirsher 
311f7917c00SJeff Kirsher static const struct mdio_ops mi1_mdio_ext_ops = {
312f7917c00SJeff Kirsher 	.read = mi1_ext_read,
313f7917c00SJeff Kirsher 	.write = mi1_ext_write,
314f7917c00SJeff Kirsher 	.mode_support = MDIO_SUPPORTS_C45 | MDIO_EMULATE_C22
315f7917c00SJeff Kirsher };
316f7917c00SJeff Kirsher 
317f7917c00SJeff Kirsher /**
318f7917c00SJeff Kirsher  *	t3_mdio_change_bits - modify the value of a PHY register
319f7917c00SJeff Kirsher  *	@phy: the PHY to operate on
320f7917c00SJeff Kirsher  *	@mmd: the device address
321f7917c00SJeff Kirsher  *	@reg: the register address
322f7917c00SJeff Kirsher  *	@clear: what part of the register value to mask off
323f7917c00SJeff Kirsher  *	@set: what part of the register value to set
324f7917c00SJeff Kirsher  *
325f7917c00SJeff Kirsher  *	Changes the value of a PHY register by applying a mask to its current
326f7917c00SJeff Kirsher  *	value and ORing the result with a new value.
327f7917c00SJeff Kirsher  */
328f7917c00SJeff Kirsher int t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
329f7917c00SJeff Kirsher 			unsigned int set)
330f7917c00SJeff Kirsher {
331f7917c00SJeff Kirsher 	int ret;
332f7917c00SJeff Kirsher 	unsigned int val;
333f7917c00SJeff Kirsher 
334f7917c00SJeff Kirsher 	ret = t3_mdio_read(phy, mmd, reg, &val);
335f7917c00SJeff Kirsher 	if (!ret) {
336f7917c00SJeff Kirsher 		val &= ~clear;
337f7917c00SJeff Kirsher 		ret = t3_mdio_write(phy, mmd, reg, val | set);
338f7917c00SJeff Kirsher 	}
339f7917c00SJeff Kirsher 	return ret;
340f7917c00SJeff Kirsher }
341f7917c00SJeff Kirsher 
342f7917c00SJeff Kirsher /**
343f7917c00SJeff Kirsher  *	t3_phy_reset - reset a PHY block
344f7917c00SJeff Kirsher  *	@phy: the PHY to operate on
345f7917c00SJeff Kirsher  *	@mmd: the device address of the PHY block to reset
346f7917c00SJeff Kirsher  *	@wait: how long to wait for the reset to complete in 1ms increments
347f7917c00SJeff Kirsher  *
348f7917c00SJeff Kirsher  *	Resets a PHY block and optionally waits for the reset to complete.
349f7917c00SJeff Kirsher  *	@mmd should be 0 for 10/100/1000 PHYs and the device address to reset
350f7917c00SJeff Kirsher  *	for 10G PHYs.
351f7917c00SJeff Kirsher  */
352f7917c00SJeff Kirsher int t3_phy_reset(struct cphy *phy, int mmd, int wait)
353f7917c00SJeff Kirsher {
354f7917c00SJeff Kirsher 	int err;
355f7917c00SJeff Kirsher 	unsigned int ctl;
356f7917c00SJeff Kirsher 
357f7917c00SJeff Kirsher 	err = t3_mdio_change_bits(phy, mmd, MDIO_CTRL1, MDIO_CTRL1_LPOWER,
358f7917c00SJeff Kirsher 				  MDIO_CTRL1_RESET);
359f7917c00SJeff Kirsher 	if (err || !wait)
360f7917c00SJeff Kirsher 		return err;
361f7917c00SJeff Kirsher 
362f7917c00SJeff Kirsher 	do {
363f7917c00SJeff Kirsher 		err = t3_mdio_read(phy, mmd, MDIO_CTRL1, &ctl);
364f7917c00SJeff Kirsher 		if (err)
365f7917c00SJeff Kirsher 			return err;
366f7917c00SJeff Kirsher 		ctl &= MDIO_CTRL1_RESET;
367f7917c00SJeff Kirsher 		if (ctl)
368f7917c00SJeff Kirsher 			msleep(1);
369f7917c00SJeff Kirsher 	} while (ctl && --wait);
370f7917c00SJeff Kirsher 
371f7917c00SJeff Kirsher 	return ctl ? -1 : 0;
372f7917c00SJeff Kirsher }
373f7917c00SJeff Kirsher 
374f7917c00SJeff Kirsher /**
375f7917c00SJeff Kirsher  *	t3_phy_advertise - set the PHY advertisement registers for autoneg
376f7917c00SJeff Kirsher  *	@phy: the PHY to operate on
377f7917c00SJeff Kirsher  *	@advert: bitmap of capabilities the PHY should advertise
378f7917c00SJeff Kirsher  *
379f7917c00SJeff Kirsher  *	Sets a 10/100/1000 PHY's advertisement registers to advertise the
380f7917c00SJeff Kirsher  *	requested capabilities.
381f7917c00SJeff Kirsher  */
382f7917c00SJeff Kirsher int t3_phy_advertise(struct cphy *phy, unsigned int advert)
383f7917c00SJeff Kirsher {
384f7917c00SJeff Kirsher 	int err;
385f7917c00SJeff Kirsher 	unsigned int val = 0;
386f7917c00SJeff Kirsher 
387f7917c00SJeff Kirsher 	err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_CTRL1000, &val);
388f7917c00SJeff Kirsher 	if (err)
389f7917c00SJeff Kirsher 		return err;
390f7917c00SJeff Kirsher 
391f7917c00SJeff Kirsher 	val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
392f7917c00SJeff Kirsher 	if (advert & ADVERTISED_1000baseT_Half)
393f7917c00SJeff Kirsher 		val |= ADVERTISE_1000HALF;
394f7917c00SJeff Kirsher 	if (advert & ADVERTISED_1000baseT_Full)
395f7917c00SJeff Kirsher 		val |= ADVERTISE_1000FULL;
396f7917c00SJeff Kirsher 
397f7917c00SJeff Kirsher 	err = t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_CTRL1000, val);
398f7917c00SJeff Kirsher 	if (err)
399f7917c00SJeff Kirsher 		return err;
400f7917c00SJeff Kirsher 
401f7917c00SJeff Kirsher 	val = 1;
402f7917c00SJeff Kirsher 	if (advert & ADVERTISED_10baseT_Half)
403f7917c00SJeff Kirsher 		val |= ADVERTISE_10HALF;
404f7917c00SJeff Kirsher 	if (advert & ADVERTISED_10baseT_Full)
405f7917c00SJeff Kirsher 		val |= ADVERTISE_10FULL;
406f7917c00SJeff Kirsher 	if (advert & ADVERTISED_100baseT_Half)
407f7917c00SJeff Kirsher 		val |= ADVERTISE_100HALF;
408f7917c00SJeff Kirsher 	if (advert & ADVERTISED_100baseT_Full)
409f7917c00SJeff Kirsher 		val |= ADVERTISE_100FULL;
410f7917c00SJeff Kirsher 	if (advert & ADVERTISED_Pause)
411f7917c00SJeff Kirsher 		val |= ADVERTISE_PAUSE_CAP;
412f7917c00SJeff Kirsher 	if (advert & ADVERTISED_Asym_Pause)
413f7917c00SJeff Kirsher 		val |= ADVERTISE_PAUSE_ASYM;
414f7917c00SJeff Kirsher 	return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val);
415f7917c00SJeff Kirsher }
416f7917c00SJeff Kirsher 
417f7917c00SJeff Kirsher /**
418f7917c00SJeff Kirsher  *	t3_phy_advertise_fiber - set fiber PHY advertisement register
419f7917c00SJeff Kirsher  *	@phy: the PHY to operate on
420f7917c00SJeff Kirsher  *	@advert: bitmap of capabilities the PHY should advertise
421f7917c00SJeff Kirsher  *
422f7917c00SJeff Kirsher  *	Sets a fiber PHY's advertisement register to advertise the
423f7917c00SJeff Kirsher  *	requested capabilities.
424f7917c00SJeff Kirsher  */
425f7917c00SJeff Kirsher int t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert)
426f7917c00SJeff Kirsher {
427f7917c00SJeff Kirsher 	unsigned int val = 0;
428f7917c00SJeff Kirsher 
429f7917c00SJeff Kirsher 	if (advert & ADVERTISED_1000baseT_Half)
430f7917c00SJeff Kirsher 		val |= ADVERTISE_1000XHALF;
431f7917c00SJeff Kirsher 	if (advert & ADVERTISED_1000baseT_Full)
432f7917c00SJeff Kirsher 		val |= ADVERTISE_1000XFULL;
433f7917c00SJeff Kirsher 	if (advert & ADVERTISED_Pause)
434f7917c00SJeff Kirsher 		val |= ADVERTISE_1000XPAUSE;
435f7917c00SJeff Kirsher 	if (advert & ADVERTISED_Asym_Pause)
436f7917c00SJeff Kirsher 		val |= ADVERTISE_1000XPSE_ASYM;
437f7917c00SJeff Kirsher 	return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_ADVERTISE, val);
438f7917c00SJeff Kirsher }
439f7917c00SJeff Kirsher 
440f7917c00SJeff Kirsher /**
441f7917c00SJeff Kirsher  *	t3_set_phy_speed_duplex - force PHY speed and duplex
442f7917c00SJeff Kirsher  *	@phy: the PHY to operate on
443f7917c00SJeff Kirsher  *	@speed: requested PHY speed
444f7917c00SJeff Kirsher  *	@duplex: requested PHY duplex
445f7917c00SJeff Kirsher  *
446f7917c00SJeff Kirsher  *	Force a 10/100/1000 PHY's speed and duplex.  This also disables
447f7917c00SJeff Kirsher  *	auto-negotiation except for GigE, where auto-negotiation is mandatory.
448f7917c00SJeff Kirsher  */
449f7917c00SJeff Kirsher int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
450f7917c00SJeff Kirsher {
451f7917c00SJeff Kirsher 	int err;
452f7917c00SJeff Kirsher 	unsigned int ctl;
453f7917c00SJeff Kirsher 
454f7917c00SJeff Kirsher 	err = t3_mdio_read(phy, MDIO_DEVAD_NONE, MII_BMCR, &ctl);
455f7917c00SJeff Kirsher 	if (err)
456f7917c00SJeff Kirsher 		return err;
457f7917c00SJeff Kirsher 
458f7917c00SJeff Kirsher 	if (speed >= 0) {
459f7917c00SJeff Kirsher 		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
460f7917c00SJeff Kirsher 		if (speed == SPEED_100)
461f7917c00SJeff Kirsher 			ctl |= BMCR_SPEED100;
462f7917c00SJeff Kirsher 		else if (speed == SPEED_1000)
463f7917c00SJeff Kirsher 			ctl |= BMCR_SPEED1000;
464f7917c00SJeff Kirsher 	}
465f7917c00SJeff Kirsher 	if (duplex >= 0) {
466f7917c00SJeff Kirsher 		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
467f7917c00SJeff Kirsher 		if (duplex == DUPLEX_FULL)
468f7917c00SJeff Kirsher 			ctl |= BMCR_FULLDPLX;
469f7917c00SJeff Kirsher 	}
470f7917c00SJeff Kirsher 	if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
471f7917c00SJeff Kirsher 		ctl |= BMCR_ANENABLE;
472f7917c00SJeff Kirsher 	return t3_mdio_write(phy, MDIO_DEVAD_NONE, MII_BMCR, ctl);
473f7917c00SJeff Kirsher }
474f7917c00SJeff Kirsher 
475f7917c00SJeff Kirsher int t3_phy_lasi_intr_enable(struct cphy *phy)
476f7917c00SJeff Kirsher {
477f7917c00SJeff Kirsher 	return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL,
478f7917c00SJeff Kirsher 			     MDIO_PMA_LASI_LSALARM);
479f7917c00SJeff Kirsher }
480f7917c00SJeff Kirsher 
481f7917c00SJeff Kirsher int t3_phy_lasi_intr_disable(struct cphy *phy)
482f7917c00SJeff Kirsher {
483f7917c00SJeff Kirsher 	return t3_mdio_write(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_CTRL, 0);
484f7917c00SJeff Kirsher }
485f7917c00SJeff Kirsher 
486f7917c00SJeff Kirsher int t3_phy_lasi_intr_clear(struct cphy *phy)
487f7917c00SJeff Kirsher {
488f7917c00SJeff Kirsher 	u32 val;
489f7917c00SJeff Kirsher 
490f7917c00SJeff Kirsher 	return t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT, &val);
491f7917c00SJeff Kirsher }
492f7917c00SJeff Kirsher 
493f7917c00SJeff Kirsher int t3_phy_lasi_intr_handler(struct cphy *phy)
494f7917c00SJeff Kirsher {
495f7917c00SJeff Kirsher 	unsigned int status;
496f7917c00SJeff Kirsher 	int err = t3_mdio_read(phy, MDIO_MMD_PMAPMD, MDIO_PMA_LASI_STAT,
497f7917c00SJeff Kirsher 			       &status);
498f7917c00SJeff Kirsher 
499f7917c00SJeff Kirsher 	if (err)
500f7917c00SJeff Kirsher 		return err;
501f7917c00SJeff Kirsher 	return (status & MDIO_PMA_LASI_LSALARM) ? cphy_cause_link_change : 0;
502f7917c00SJeff Kirsher }
503f7917c00SJeff Kirsher 
504f7917c00SJeff Kirsher static const struct adapter_info t3_adap_info[] = {
505f7917c00SJeff Kirsher 	{1, 1, 0,
506f7917c00SJeff Kirsher 	 F_GPIO2_OEN | F_GPIO4_OEN |
507f7917c00SJeff Kirsher 	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
508f7917c00SJeff Kirsher 	 &mi1_mdio_ops, "Chelsio PE9000"},
509f7917c00SJeff Kirsher 	{1, 1, 0,
510f7917c00SJeff Kirsher 	 F_GPIO2_OEN | F_GPIO4_OEN |
511f7917c00SJeff Kirsher 	 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
512f7917c00SJeff Kirsher 	 &mi1_mdio_ops, "Chelsio T302"},
513f7917c00SJeff Kirsher 	{1, 0, 0,
514f7917c00SJeff Kirsher 	 F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
515f7917c00SJeff Kirsher 	 F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
516f7917c00SJeff Kirsher 	 { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
517f7917c00SJeff Kirsher 	 &mi1_mdio_ext_ops, "Chelsio T310"},
518f7917c00SJeff Kirsher 	{1, 1, 0,
519f7917c00SJeff Kirsher 	 F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
520f7917c00SJeff Kirsher 	 F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
521f7917c00SJeff Kirsher 	 F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
522f7917c00SJeff Kirsher 	 { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
523f7917c00SJeff Kirsher 	 &mi1_mdio_ext_ops, "Chelsio T320"},
524f7917c00SJeff Kirsher 	{},
525f7917c00SJeff Kirsher 	{},
526f7917c00SJeff Kirsher 	{1, 0, 0,
527f7917c00SJeff Kirsher 	 F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
528f7917c00SJeff Kirsher 	 F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
529f7917c00SJeff Kirsher 	 { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
530f7917c00SJeff Kirsher 	 &mi1_mdio_ext_ops, "Chelsio T310" },
531f7917c00SJeff Kirsher 	{1, 0, 0,
532f7917c00SJeff Kirsher 	 F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
533f7917c00SJeff Kirsher 	 F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL,
534f7917c00SJeff Kirsher 	 { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
535f7917c00SJeff Kirsher 	 &mi1_mdio_ext_ops, "Chelsio N320E-G2" },
536f7917c00SJeff Kirsher };
537f7917c00SJeff Kirsher 
538f7917c00SJeff Kirsher /*
539f7917c00SJeff Kirsher  * Return the adapter_info structure with a given index.  Out-of-range indices
540f7917c00SJeff Kirsher  * return NULL.
541f7917c00SJeff Kirsher  */
542f7917c00SJeff Kirsher const struct adapter_info *t3_get_adapter_info(unsigned int id)
543f7917c00SJeff Kirsher {
544f7917c00SJeff Kirsher 	return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
545f7917c00SJeff Kirsher }
546f7917c00SJeff Kirsher 
547f7917c00SJeff Kirsher struct port_type_info {
548f7917c00SJeff Kirsher 	int (*phy_prep)(struct cphy *phy, struct adapter *adapter,
549f7917c00SJeff Kirsher 			int phy_addr, const struct mdio_ops *ops);
550f7917c00SJeff Kirsher };
551f7917c00SJeff Kirsher 
552f7917c00SJeff Kirsher static const struct port_type_info port_types[] = {
553f7917c00SJeff Kirsher 	{ NULL },
554f7917c00SJeff Kirsher 	{ t3_ael1002_phy_prep },
555f7917c00SJeff Kirsher 	{ t3_vsc8211_phy_prep },
556f7917c00SJeff Kirsher 	{ NULL},
557f7917c00SJeff Kirsher 	{ t3_xaui_direct_phy_prep },
558f7917c00SJeff Kirsher 	{ t3_ael2005_phy_prep },
559f7917c00SJeff Kirsher 	{ t3_qt2045_phy_prep },
560f7917c00SJeff Kirsher 	{ t3_ael1006_phy_prep },
561f7917c00SJeff Kirsher 	{ NULL },
562f7917c00SJeff Kirsher 	{ t3_aq100x_phy_prep },
563f7917c00SJeff Kirsher 	{ t3_ael2020_phy_prep },
564f7917c00SJeff Kirsher };
565f7917c00SJeff Kirsher 
566f7917c00SJeff Kirsher #define VPD_ENTRY(name, len) \
567f7917c00SJeff Kirsher 	u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
568f7917c00SJeff Kirsher 
569f7917c00SJeff Kirsher /*
570f7917c00SJeff Kirsher  * Partial EEPROM Vital Product Data structure.  Includes only the ID and
571f7917c00SJeff Kirsher  * VPD-R sections.
572f7917c00SJeff Kirsher  */
573f7917c00SJeff Kirsher struct t3_vpd {
574f7917c00SJeff Kirsher 	u8 id_tag;
575f7917c00SJeff Kirsher 	u8 id_len[2];
576f7917c00SJeff Kirsher 	u8 id_data[16];
577f7917c00SJeff Kirsher 	u8 vpdr_tag;
578f7917c00SJeff Kirsher 	u8 vpdr_len[2];
579f7917c00SJeff Kirsher 	VPD_ENTRY(pn, 16);	/* part number */
580f7917c00SJeff Kirsher 	VPD_ENTRY(ec, 16);	/* EC level */
581f7917c00SJeff Kirsher 	VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
582f7917c00SJeff Kirsher 	VPD_ENTRY(na, 12);	/* MAC address base */
583f7917c00SJeff Kirsher 	VPD_ENTRY(cclk, 6);	/* core clock */
584f7917c00SJeff Kirsher 	VPD_ENTRY(mclk, 6);	/* mem clock */
585f7917c00SJeff Kirsher 	VPD_ENTRY(uclk, 6);	/* uP clk */
586f7917c00SJeff Kirsher 	VPD_ENTRY(mdc, 6);	/* MDIO clk */
587f7917c00SJeff Kirsher 	VPD_ENTRY(mt, 2);	/* mem timing */
588f7917c00SJeff Kirsher 	VPD_ENTRY(xaui0cfg, 6);	/* XAUI0 config */
589f7917c00SJeff Kirsher 	VPD_ENTRY(xaui1cfg, 6);	/* XAUI1 config */
590f7917c00SJeff Kirsher 	VPD_ENTRY(port0, 2);	/* PHY0 complex */
591f7917c00SJeff Kirsher 	VPD_ENTRY(port1, 2);	/* PHY1 complex */
592f7917c00SJeff Kirsher 	VPD_ENTRY(port2, 2);	/* PHY2 complex */
593f7917c00SJeff Kirsher 	VPD_ENTRY(port3, 2);	/* PHY3 complex */
594f7917c00SJeff Kirsher 	VPD_ENTRY(rv, 1);	/* csum */
595f7917c00SJeff Kirsher 	u32 pad;		/* for multiple-of-4 sizing and alignment */
596f7917c00SJeff Kirsher };
597f7917c00SJeff Kirsher 
598f7917c00SJeff Kirsher #define EEPROM_MAX_POLL   40
599f7917c00SJeff Kirsher #define EEPROM_STAT_ADDR  0x4000
600f7917c00SJeff Kirsher #define VPD_BASE          0xc00
601f7917c00SJeff Kirsher 
602f7917c00SJeff Kirsher /**
603f7917c00SJeff Kirsher  *	t3_seeprom_read - read a VPD EEPROM location
604f7917c00SJeff Kirsher  *	@adapter: adapter to read
605f7917c00SJeff Kirsher  *	@addr: EEPROM address
606f7917c00SJeff Kirsher  *	@data: where to store the read data
607f7917c00SJeff Kirsher  *
608f7917c00SJeff Kirsher  *	Read a 32-bit word from a location in VPD EEPROM using the card's PCI
609f7917c00SJeff Kirsher  *	VPD ROM capability.  A zero is written to the flag bit when the
610f7917c00SJeff Kirsher  *	address is written to the control register.  The hardware device will
611f7917c00SJeff Kirsher  *	set the flag to 1 when 4 bytes have been read into the data register.
612f7917c00SJeff Kirsher  */
613f7917c00SJeff Kirsher int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data)
614f7917c00SJeff Kirsher {
615f7917c00SJeff Kirsher 	u16 val;
616f7917c00SJeff Kirsher 	int attempts = EEPROM_MAX_POLL;
617f7917c00SJeff Kirsher 	u32 v;
618f7917c00SJeff Kirsher 	unsigned int base = adapter->params.pci.vpd_cap_addr;
619f7917c00SJeff Kirsher 
620f7917c00SJeff Kirsher 	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
621f7917c00SJeff Kirsher 		return -EINVAL;
622f7917c00SJeff Kirsher 
623f7917c00SJeff Kirsher 	pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
624f7917c00SJeff Kirsher 	do {
625f7917c00SJeff Kirsher 		udelay(10);
626f7917c00SJeff Kirsher 		pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
627f7917c00SJeff Kirsher 	} while (!(val & PCI_VPD_ADDR_F) && --attempts);
628f7917c00SJeff Kirsher 
629f7917c00SJeff Kirsher 	if (!(val & PCI_VPD_ADDR_F)) {
630f7917c00SJeff Kirsher 		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
631f7917c00SJeff Kirsher 		return -EIO;
632f7917c00SJeff Kirsher 	}
633f7917c00SJeff Kirsher 	pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v);
634f7917c00SJeff Kirsher 	*data = cpu_to_le32(v);
635f7917c00SJeff Kirsher 	return 0;
636f7917c00SJeff Kirsher }
637f7917c00SJeff Kirsher 
638f7917c00SJeff Kirsher /**
639f7917c00SJeff Kirsher  *	t3_seeprom_write - write a VPD EEPROM location
640f7917c00SJeff Kirsher  *	@adapter: adapter to write
641f7917c00SJeff Kirsher  *	@addr: EEPROM address
642f7917c00SJeff Kirsher  *	@data: value to write
643f7917c00SJeff Kirsher  *
644f7917c00SJeff Kirsher  *	Write a 32-bit word to a location in VPD EEPROM using the card's PCI
645f7917c00SJeff Kirsher  *	VPD ROM capability.
646f7917c00SJeff Kirsher  */
647f7917c00SJeff Kirsher int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data)
648f7917c00SJeff Kirsher {
649f7917c00SJeff Kirsher 	u16 val;
650f7917c00SJeff Kirsher 	int attempts = EEPROM_MAX_POLL;
651f7917c00SJeff Kirsher 	unsigned int base = adapter->params.pci.vpd_cap_addr;
652f7917c00SJeff Kirsher 
653f7917c00SJeff Kirsher 	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
654f7917c00SJeff Kirsher 		return -EINVAL;
655f7917c00SJeff Kirsher 
656f7917c00SJeff Kirsher 	pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
657f7917c00SJeff Kirsher 			       le32_to_cpu(data));
658f7917c00SJeff Kirsher 	pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
659f7917c00SJeff Kirsher 			      addr | PCI_VPD_ADDR_F);
660f7917c00SJeff Kirsher 	do {
661f7917c00SJeff Kirsher 		msleep(1);
662f7917c00SJeff Kirsher 		pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
663f7917c00SJeff Kirsher 	} while ((val & PCI_VPD_ADDR_F) && --attempts);
664f7917c00SJeff Kirsher 
665f7917c00SJeff Kirsher 	if (val & PCI_VPD_ADDR_F) {
666f7917c00SJeff Kirsher 		CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
667f7917c00SJeff Kirsher 		return -EIO;
668f7917c00SJeff Kirsher 	}
669f7917c00SJeff Kirsher 	return 0;
670f7917c00SJeff Kirsher }
671f7917c00SJeff Kirsher 
672f7917c00SJeff Kirsher /**
673f7917c00SJeff Kirsher  *	t3_seeprom_wp - enable/disable EEPROM write protection
674f7917c00SJeff Kirsher  *	@adapter: the adapter
675f7917c00SJeff Kirsher  *	@enable: 1 to enable write protection, 0 to disable it
676f7917c00SJeff Kirsher  *
677f7917c00SJeff Kirsher  *	Enables or disables write protection on the serial EEPROM.
678f7917c00SJeff Kirsher  */
679f7917c00SJeff Kirsher int t3_seeprom_wp(struct adapter *adapter, int enable)
680f7917c00SJeff Kirsher {
681f7917c00SJeff Kirsher 	return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
682f7917c00SJeff Kirsher }
683f7917c00SJeff Kirsher 
684c33b3b9fSGustavo A. R. Silva static int vpdstrtouint(char *s, u8 len, unsigned int base, unsigned int *val)
6851003e19cSSteve Wise {
686c33b3b9fSGustavo A. R. Silva 	char tok[256];
6871003e19cSSteve Wise 
6881003e19cSSteve Wise 	memcpy(tok, s, len);
6891003e19cSSteve Wise 	tok[len] = 0;
6901003e19cSSteve Wise 	return kstrtouint(strim(tok), base, val);
6911003e19cSSteve Wise }
6921003e19cSSteve Wise 
693c33b3b9fSGustavo A. R. Silva static int vpdstrtou16(char *s, u8 len, unsigned int base, u16 *val)
6941003e19cSSteve Wise {
695c33b3b9fSGustavo A. R. Silva 	char tok[256];
6961003e19cSSteve Wise 
6971003e19cSSteve Wise 	memcpy(tok, s, len);
6981003e19cSSteve Wise 	tok[len] = 0;
6991003e19cSSteve Wise 	return kstrtou16(strim(tok), base, val);
7001003e19cSSteve Wise }
7011003e19cSSteve Wise 
702f7917c00SJeff Kirsher /**
703f7917c00SJeff Kirsher  *	get_vpd_params - read VPD parameters from VPD EEPROM
704f7917c00SJeff Kirsher  *	@adapter: adapter to read
705f7917c00SJeff Kirsher  *	@p: where to store the parameters
706f7917c00SJeff Kirsher  *
707f7917c00SJeff Kirsher  *	Reads card parameters stored in VPD EEPROM.
708f7917c00SJeff Kirsher  */
709f7917c00SJeff Kirsher static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
710f7917c00SJeff Kirsher {
711f7917c00SJeff Kirsher 	int i, addr, ret;
712f7917c00SJeff Kirsher 	struct t3_vpd vpd;
713f7917c00SJeff Kirsher 
714f7917c00SJeff Kirsher 	/*
715f7917c00SJeff Kirsher 	 * Card information is normally at VPD_BASE but some early cards had
716f7917c00SJeff Kirsher 	 * it at 0.
717f7917c00SJeff Kirsher 	 */
718f7917c00SJeff Kirsher 	ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd);
719f7917c00SJeff Kirsher 	if (ret)
720f7917c00SJeff Kirsher 		return ret;
721f7917c00SJeff Kirsher 	addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
722f7917c00SJeff Kirsher 
723f7917c00SJeff Kirsher 	for (i = 0; i < sizeof(vpd); i += 4) {
724f7917c00SJeff Kirsher 		ret = t3_seeprom_read(adapter, addr + i,
725f7917c00SJeff Kirsher 				      (__le32 *)((u8 *)&vpd + i));
726f7917c00SJeff Kirsher 		if (ret)
727f7917c00SJeff Kirsher 			return ret;
728f7917c00SJeff Kirsher 	}
729f7917c00SJeff Kirsher 
7301003e19cSSteve Wise 	ret = vpdstrtouint(vpd.cclk_data, vpd.cclk_len, 10, &p->cclk);
731e72c932dSLABBE Corentin 	if (ret)
732e72c932dSLABBE Corentin 		return ret;
7331003e19cSSteve Wise 	ret = vpdstrtouint(vpd.mclk_data, vpd.mclk_len, 10, &p->mclk);
734e72c932dSLABBE Corentin 	if (ret)
735e72c932dSLABBE Corentin 		return ret;
7361003e19cSSteve Wise 	ret = vpdstrtouint(vpd.uclk_data, vpd.uclk_len, 10, &p->uclk);
737e72c932dSLABBE Corentin 	if (ret)
738e72c932dSLABBE Corentin 		return ret;
7391003e19cSSteve Wise 	ret = vpdstrtouint(vpd.mdc_data, vpd.mdc_len, 10, &p->mdc);
740e72c932dSLABBE Corentin 	if (ret)
741e72c932dSLABBE Corentin 		return ret;
7421003e19cSSteve Wise 	ret = vpdstrtouint(vpd.mt_data, vpd.mt_len, 10, &p->mem_timing);
743e72c932dSLABBE Corentin 	if (ret)
744e72c932dSLABBE Corentin 		return ret;
745f7917c00SJeff Kirsher 	memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
746f7917c00SJeff Kirsher 
747f7917c00SJeff Kirsher 	/* Old eeproms didn't have port information */
748f7917c00SJeff Kirsher 	if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
749f7917c00SJeff Kirsher 		p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
750f7917c00SJeff Kirsher 		p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
751f7917c00SJeff Kirsher 	} else {
752f7917c00SJeff Kirsher 		p->port_type[0] = hex_to_bin(vpd.port0_data[0]);
753f7917c00SJeff Kirsher 		p->port_type[1] = hex_to_bin(vpd.port1_data[0]);
7541003e19cSSteve Wise 		ret = vpdstrtou16(vpd.xaui0cfg_data, vpd.xaui0cfg_len, 16,
7551003e19cSSteve Wise 				  &p->xauicfg[0]);
756e72c932dSLABBE Corentin 		if (ret)
757e72c932dSLABBE Corentin 			return ret;
7581003e19cSSteve Wise 		ret = vpdstrtou16(vpd.xaui1cfg_data, vpd.xaui1cfg_len, 16,
7591003e19cSSteve Wise 				  &p->xauicfg[1]);
760e72c932dSLABBE Corentin 		if (ret)
761e72c932dSLABBE Corentin 			return ret;
762f7917c00SJeff Kirsher 	}
763f7917c00SJeff Kirsher 
7647aee42c6SAndy Shevchenko 	ret = hex2bin(p->eth_base, vpd.na_data, 6);
7657aee42c6SAndy Shevchenko 	if (ret < 0)
7667aee42c6SAndy Shevchenko 		return -EINVAL;
767f7917c00SJeff Kirsher 	return 0;
768f7917c00SJeff Kirsher }
769f7917c00SJeff Kirsher 
770f7917c00SJeff Kirsher /* serial flash and firmware constants */
771f7917c00SJeff Kirsher enum {
772f7917c00SJeff Kirsher 	SF_ATTEMPTS = 5,	/* max retries for SF1 operations */
773f7917c00SJeff Kirsher 	SF_SEC_SIZE = 64 * 1024,	/* serial flash sector size */
774f7917c00SJeff Kirsher 	SF_SIZE = SF_SEC_SIZE * 8,	/* serial flash size */
775f7917c00SJeff Kirsher 
776f7917c00SJeff Kirsher 	/* flash command opcodes */
777f7917c00SJeff Kirsher 	SF_PROG_PAGE = 2,	/* program page */
778f7917c00SJeff Kirsher 	SF_WR_DISABLE = 4,	/* disable writes */
779f7917c00SJeff Kirsher 	SF_RD_STATUS = 5,	/* read status register */
780f7917c00SJeff Kirsher 	SF_WR_ENABLE = 6,	/* enable writes */
781f7917c00SJeff Kirsher 	SF_RD_DATA_FAST = 0xb,	/* read flash */
782f7917c00SJeff Kirsher 	SF_ERASE_SECTOR = 0xd8,	/* erase sector */
783f7917c00SJeff Kirsher 
784f7917c00SJeff Kirsher 	FW_FLASH_BOOT_ADDR = 0x70000,	/* start address of FW in flash */
785f7917c00SJeff Kirsher 	FW_VERS_ADDR = 0x7fffc,    /* flash address holding FW version */
786f7917c00SJeff Kirsher 	FW_MIN_SIZE = 8            /* at least version and csum */
787f7917c00SJeff Kirsher };
788f7917c00SJeff Kirsher 
789f7917c00SJeff Kirsher /**
790f7917c00SJeff Kirsher  *	sf1_read - read data from the serial flash
791f7917c00SJeff Kirsher  *	@adapter: the adapter
792f7917c00SJeff Kirsher  *	@byte_cnt: number of bytes to read
793f7917c00SJeff Kirsher  *	@cont: whether another operation will be chained
794f7917c00SJeff Kirsher  *	@valp: where to store the read data
795f7917c00SJeff Kirsher  *
796f7917c00SJeff Kirsher  *	Reads up to 4 bytes of data from the serial flash.  The location of
797f7917c00SJeff Kirsher  *	the read needs to be specified prior to calling this by issuing the
798f7917c00SJeff Kirsher  *	appropriate commands to the serial flash.
799f7917c00SJeff Kirsher  */
800f7917c00SJeff Kirsher static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
801f7917c00SJeff Kirsher 		    u32 *valp)
802f7917c00SJeff Kirsher {
803f7917c00SJeff Kirsher 	int ret;
804f7917c00SJeff Kirsher 
805f7917c00SJeff Kirsher 	if (!byte_cnt || byte_cnt > 4)
806f7917c00SJeff Kirsher 		return -EINVAL;
807f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
808f7917c00SJeff Kirsher 		return -EBUSY;
809f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
810f7917c00SJeff Kirsher 	ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
811f7917c00SJeff Kirsher 	if (!ret)
812f7917c00SJeff Kirsher 		*valp = t3_read_reg(adapter, A_SF_DATA);
813f7917c00SJeff Kirsher 	return ret;
814f7917c00SJeff Kirsher }
815f7917c00SJeff Kirsher 
816f7917c00SJeff Kirsher /**
817f7917c00SJeff Kirsher  *	sf1_write - write data to the serial flash
818f7917c00SJeff Kirsher  *	@adapter: the adapter
819f7917c00SJeff Kirsher  *	@byte_cnt: number of bytes to write
820f7917c00SJeff Kirsher  *	@cont: whether another operation will be chained
821f7917c00SJeff Kirsher  *	@val: value to write
822f7917c00SJeff Kirsher  *
823f7917c00SJeff Kirsher  *	Writes up to 4 bytes of data to the serial flash.  The location of
824f7917c00SJeff Kirsher  *	the write needs to be specified prior to calling this by issuing the
825f7917c00SJeff Kirsher  *	appropriate commands to the serial flash.
826f7917c00SJeff Kirsher  */
827f7917c00SJeff Kirsher static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
828f7917c00SJeff Kirsher 		     u32 val)
829f7917c00SJeff Kirsher {
830f7917c00SJeff Kirsher 	if (!byte_cnt || byte_cnt > 4)
831f7917c00SJeff Kirsher 		return -EINVAL;
832f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
833f7917c00SJeff Kirsher 		return -EBUSY;
834f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SF_DATA, val);
835f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SF_OP,
836f7917c00SJeff Kirsher 		     V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
837f7917c00SJeff Kirsher 	return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
838f7917c00SJeff Kirsher }
839f7917c00SJeff Kirsher 
840f7917c00SJeff Kirsher /**
841f7917c00SJeff Kirsher  *	flash_wait_op - wait for a flash operation to complete
842f7917c00SJeff Kirsher  *	@adapter: the adapter
843f7917c00SJeff Kirsher  *	@attempts: max number of polls of the status register
844f7917c00SJeff Kirsher  *	@delay: delay between polls in ms
845f7917c00SJeff Kirsher  *
846f7917c00SJeff Kirsher  *	Wait for a flash operation to complete by polling the status register.
847f7917c00SJeff Kirsher  */
848f7917c00SJeff Kirsher static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
849f7917c00SJeff Kirsher {
850f7917c00SJeff Kirsher 	int ret;
851f7917c00SJeff Kirsher 	u32 status;
852f7917c00SJeff Kirsher 
853f7917c00SJeff Kirsher 	while (1) {
854f7917c00SJeff Kirsher 		if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
855f7917c00SJeff Kirsher 		    (ret = sf1_read(adapter, 1, 0, &status)) != 0)
856f7917c00SJeff Kirsher 			return ret;
857f7917c00SJeff Kirsher 		if (!(status & 1))
858f7917c00SJeff Kirsher 			return 0;
859f7917c00SJeff Kirsher 		if (--attempts == 0)
860f7917c00SJeff Kirsher 			return -EAGAIN;
861f7917c00SJeff Kirsher 		if (delay)
862f7917c00SJeff Kirsher 			msleep(delay);
863f7917c00SJeff Kirsher 	}
864f7917c00SJeff Kirsher }
865f7917c00SJeff Kirsher 
866f7917c00SJeff Kirsher /**
867f7917c00SJeff Kirsher  *	t3_read_flash - read words from serial flash
868f7917c00SJeff Kirsher  *	@adapter: the adapter
869f7917c00SJeff Kirsher  *	@addr: the start address for the read
870f7917c00SJeff Kirsher  *	@nwords: how many 32-bit words to read
871f7917c00SJeff Kirsher  *	@data: where to store the read data
872f7917c00SJeff Kirsher  *	@byte_oriented: whether to store data as bytes or as words
873f7917c00SJeff Kirsher  *
874f7917c00SJeff Kirsher  *	Read the specified number of 32-bit words from the serial flash.
875f7917c00SJeff Kirsher  *	If @byte_oriented is set the read data is stored as a byte array
876f7917c00SJeff Kirsher  *	(i.e., big-endian), otherwise as 32-bit words in the platform's
877dbedd44eSJoe Perches  *	natural endianness.
878f7917c00SJeff Kirsher  */
879f7917c00SJeff Kirsher static int t3_read_flash(struct adapter *adapter, unsigned int addr,
880f7917c00SJeff Kirsher 			 unsigned int nwords, u32 *data, int byte_oriented)
881f7917c00SJeff Kirsher {
882f7917c00SJeff Kirsher 	int ret;
883f7917c00SJeff Kirsher 
884f7917c00SJeff Kirsher 	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
885f7917c00SJeff Kirsher 		return -EINVAL;
886f7917c00SJeff Kirsher 
887f7917c00SJeff Kirsher 	addr = swab32(addr) | SF_RD_DATA_FAST;
888f7917c00SJeff Kirsher 
889f7917c00SJeff Kirsher 	if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
890f7917c00SJeff Kirsher 	    (ret = sf1_read(adapter, 1, 1, data)) != 0)
891f7917c00SJeff Kirsher 		return ret;
892f7917c00SJeff Kirsher 
893f7917c00SJeff Kirsher 	for (; nwords; nwords--, data++) {
894f7917c00SJeff Kirsher 		ret = sf1_read(adapter, 4, nwords > 1, data);
895f7917c00SJeff Kirsher 		if (ret)
896f7917c00SJeff Kirsher 			return ret;
897f7917c00SJeff Kirsher 		if (byte_oriented)
898f7917c00SJeff Kirsher 			*data = htonl(*data);
899f7917c00SJeff Kirsher 	}
900f7917c00SJeff Kirsher 	return 0;
901f7917c00SJeff Kirsher }
902f7917c00SJeff Kirsher 
903f7917c00SJeff Kirsher /**
904f7917c00SJeff Kirsher  *	t3_write_flash - write up to a page of data to the serial flash
905f7917c00SJeff Kirsher  *	@adapter: the adapter
906f7917c00SJeff Kirsher  *	@addr: the start address to write
907f7917c00SJeff Kirsher  *	@n: length of data to write
908f7917c00SJeff Kirsher  *	@data: the data to write
909f7917c00SJeff Kirsher  *
910f7917c00SJeff Kirsher  *	Writes up to a page of data (256 bytes) to the serial flash starting
911f7917c00SJeff Kirsher  *	at the given address.
912f7917c00SJeff Kirsher  */
913f7917c00SJeff Kirsher static int t3_write_flash(struct adapter *adapter, unsigned int addr,
914f7917c00SJeff Kirsher 			  unsigned int n, const u8 *data)
915f7917c00SJeff Kirsher {
916f7917c00SJeff Kirsher 	int ret;
917f7917c00SJeff Kirsher 	u32 buf[64];
918f7917c00SJeff Kirsher 	unsigned int i, c, left, val, offset = addr & 0xff;
919f7917c00SJeff Kirsher 
920f7917c00SJeff Kirsher 	if (addr + n > SF_SIZE || offset + n > 256)
921f7917c00SJeff Kirsher 		return -EINVAL;
922f7917c00SJeff Kirsher 
923f7917c00SJeff Kirsher 	val = swab32(addr) | SF_PROG_PAGE;
924f7917c00SJeff Kirsher 
925f7917c00SJeff Kirsher 	if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
926f7917c00SJeff Kirsher 	    (ret = sf1_write(adapter, 4, 1, val)) != 0)
927f7917c00SJeff Kirsher 		return ret;
928f7917c00SJeff Kirsher 
929f7917c00SJeff Kirsher 	for (left = n; left; left -= c) {
930f7917c00SJeff Kirsher 		c = min(left, 4U);
931f7917c00SJeff Kirsher 		for (val = 0, i = 0; i < c; ++i)
932f7917c00SJeff Kirsher 			val = (val << 8) + *data++;
933f7917c00SJeff Kirsher 
934f7917c00SJeff Kirsher 		ret = sf1_write(adapter, c, c != left, val);
935f7917c00SJeff Kirsher 		if (ret)
936f7917c00SJeff Kirsher 			return ret;
937f7917c00SJeff Kirsher 	}
938f7917c00SJeff Kirsher 	if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
939f7917c00SJeff Kirsher 		return ret;
940f7917c00SJeff Kirsher 
941f7917c00SJeff Kirsher 	/* Read the page to verify the write succeeded */
942f7917c00SJeff Kirsher 	ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
943f7917c00SJeff Kirsher 	if (ret)
944f7917c00SJeff Kirsher 		return ret;
945f7917c00SJeff Kirsher 
946f7917c00SJeff Kirsher 	if (memcmp(data - n, (u8 *) buf + offset, n))
947f7917c00SJeff Kirsher 		return -EIO;
948f7917c00SJeff Kirsher 	return 0;
949f7917c00SJeff Kirsher }
950f7917c00SJeff Kirsher 
951f7917c00SJeff Kirsher /**
952f7917c00SJeff Kirsher  *	t3_get_tp_version - read the tp sram version
953f7917c00SJeff Kirsher  *	@adapter: the adapter
954f7917c00SJeff Kirsher  *	@vers: where to place the version
955f7917c00SJeff Kirsher  *
956f7917c00SJeff Kirsher  *	Reads the protocol sram version from sram.
957f7917c00SJeff Kirsher  */
958f7917c00SJeff Kirsher int t3_get_tp_version(struct adapter *adapter, u32 *vers)
959f7917c00SJeff Kirsher {
960f7917c00SJeff Kirsher 	int ret;
961f7917c00SJeff Kirsher 
962f7917c00SJeff Kirsher 	/* Get version loaded in SRAM */
963f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
964f7917c00SJeff Kirsher 	ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
965f7917c00SJeff Kirsher 			      1, 1, 5, 1);
966f7917c00SJeff Kirsher 	if (ret)
967f7917c00SJeff Kirsher 		return ret;
968f7917c00SJeff Kirsher 
969f7917c00SJeff Kirsher 	*vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
970f7917c00SJeff Kirsher 
971f7917c00SJeff Kirsher 	return 0;
972f7917c00SJeff Kirsher }
973f7917c00SJeff Kirsher 
974f7917c00SJeff Kirsher /**
975f7917c00SJeff Kirsher  *	t3_check_tpsram_version - read the tp sram version
976f7917c00SJeff Kirsher  *	@adapter: the adapter
977f7917c00SJeff Kirsher  *
978f7917c00SJeff Kirsher  *	Reads the protocol sram version from flash.
979f7917c00SJeff Kirsher  */
980f7917c00SJeff Kirsher int t3_check_tpsram_version(struct adapter *adapter)
981f7917c00SJeff Kirsher {
982f7917c00SJeff Kirsher 	int ret;
983f7917c00SJeff Kirsher 	u32 vers;
984f7917c00SJeff Kirsher 	unsigned int major, minor;
985f7917c00SJeff Kirsher 
986f7917c00SJeff Kirsher 	if (adapter->params.rev == T3_REV_A)
987f7917c00SJeff Kirsher 		return 0;
988f7917c00SJeff Kirsher 
989f7917c00SJeff Kirsher 
990f7917c00SJeff Kirsher 	ret = t3_get_tp_version(adapter, &vers);
991f7917c00SJeff Kirsher 	if (ret)
992f7917c00SJeff Kirsher 		return ret;
993f7917c00SJeff Kirsher 
994f7917c00SJeff Kirsher 	major = G_TP_VERSION_MAJOR(vers);
995f7917c00SJeff Kirsher 	minor = G_TP_VERSION_MINOR(vers);
996f7917c00SJeff Kirsher 
997f7917c00SJeff Kirsher 	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
998f7917c00SJeff Kirsher 		return 0;
999f7917c00SJeff Kirsher 	else {
1000f7917c00SJeff Kirsher 		CH_ERR(adapter, "found wrong TP version (%u.%u), "
1001f7917c00SJeff Kirsher 		       "driver compiled for version %d.%d\n", major, minor,
1002f7917c00SJeff Kirsher 		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
1003f7917c00SJeff Kirsher 	}
1004f7917c00SJeff Kirsher 	return -EINVAL;
1005f7917c00SJeff Kirsher }
1006f7917c00SJeff Kirsher 
1007f7917c00SJeff Kirsher /**
1008f7917c00SJeff Kirsher  *	t3_check_tpsram - check if provided protocol SRAM
1009f7917c00SJeff Kirsher  *			  is compatible with this driver
1010f7917c00SJeff Kirsher  *	@adapter: the adapter
1011f7917c00SJeff Kirsher  *	@tp_sram: the firmware image to write
1012f7917c00SJeff Kirsher  *	@size: image size
1013f7917c00SJeff Kirsher  *
1014f7917c00SJeff Kirsher  *	Checks if an adapter's tp sram is compatible with the driver.
1015f7917c00SJeff Kirsher  *	Returns 0 if the versions are compatible, a negative error otherwise.
1016f7917c00SJeff Kirsher  */
1017f7917c00SJeff Kirsher int t3_check_tpsram(struct adapter *adapter, const u8 *tp_sram,
1018f7917c00SJeff Kirsher 		    unsigned int size)
1019f7917c00SJeff Kirsher {
1020f7917c00SJeff Kirsher 	u32 csum;
1021f7917c00SJeff Kirsher 	unsigned int i;
1022f7917c00SJeff Kirsher 	const __be32 *p = (const __be32 *)tp_sram;
1023f7917c00SJeff Kirsher 
1024f7917c00SJeff Kirsher 	/* Verify checksum */
1025f7917c00SJeff Kirsher 	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1026f7917c00SJeff Kirsher 		csum += ntohl(p[i]);
1027f7917c00SJeff Kirsher 	if (csum != 0xffffffff) {
1028f7917c00SJeff Kirsher 		CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
1029f7917c00SJeff Kirsher 		       csum);
1030f7917c00SJeff Kirsher 		return -EINVAL;
1031f7917c00SJeff Kirsher 	}
1032f7917c00SJeff Kirsher 
1033f7917c00SJeff Kirsher 	return 0;
1034f7917c00SJeff Kirsher }
1035f7917c00SJeff Kirsher 
1036f7917c00SJeff Kirsher enum fw_version_type {
1037f7917c00SJeff Kirsher 	FW_VERSION_N3,
1038f7917c00SJeff Kirsher 	FW_VERSION_T3
1039f7917c00SJeff Kirsher };
1040f7917c00SJeff Kirsher 
1041f7917c00SJeff Kirsher /**
1042f7917c00SJeff Kirsher  *	t3_get_fw_version - read the firmware version
1043f7917c00SJeff Kirsher  *	@adapter: the adapter
1044f7917c00SJeff Kirsher  *	@vers: where to place the version
1045f7917c00SJeff Kirsher  *
1046f7917c00SJeff Kirsher  *	Reads the FW version from flash.
1047f7917c00SJeff Kirsher  */
1048f7917c00SJeff Kirsher int t3_get_fw_version(struct adapter *adapter, u32 *vers)
1049f7917c00SJeff Kirsher {
1050f7917c00SJeff Kirsher 	return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
1051f7917c00SJeff Kirsher }
1052f7917c00SJeff Kirsher 
1053f7917c00SJeff Kirsher /**
1054f7917c00SJeff Kirsher  *	t3_check_fw_version - check if the FW is compatible with this driver
1055f7917c00SJeff Kirsher  *	@adapter: the adapter
1056f7917c00SJeff Kirsher  *
1057f7917c00SJeff Kirsher  *	Checks if an adapter's FW is compatible with the driver.  Returns 0
1058f7917c00SJeff Kirsher  *	if the versions are compatible, a negative error otherwise.
1059f7917c00SJeff Kirsher  */
1060f7917c00SJeff Kirsher int t3_check_fw_version(struct adapter *adapter)
1061f7917c00SJeff Kirsher {
1062f7917c00SJeff Kirsher 	int ret;
1063f7917c00SJeff Kirsher 	u32 vers;
1064f7917c00SJeff Kirsher 	unsigned int type, major, minor;
1065f7917c00SJeff Kirsher 
1066f7917c00SJeff Kirsher 	ret = t3_get_fw_version(adapter, &vers);
1067f7917c00SJeff Kirsher 	if (ret)
1068f7917c00SJeff Kirsher 		return ret;
1069f7917c00SJeff Kirsher 
1070f7917c00SJeff Kirsher 	type = G_FW_VERSION_TYPE(vers);
1071f7917c00SJeff Kirsher 	major = G_FW_VERSION_MAJOR(vers);
1072f7917c00SJeff Kirsher 	minor = G_FW_VERSION_MINOR(vers);
1073f7917c00SJeff Kirsher 
1074f7917c00SJeff Kirsher 	if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR &&
1075f7917c00SJeff Kirsher 	    minor == FW_VERSION_MINOR)
1076f7917c00SJeff Kirsher 		return 0;
1077f7917c00SJeff Kirsher 	else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR)
1078f7917c00SJeff Kirsher 		CH_WARN(adapter, "found old FW minor version(%u.%u), "
1079f7917c00SJeff Kirsher 		        "driver compiled for version %u.%u\n", major, minor,
1080f7917c00SJeff Kirsher 			FW_VERSION_MAJOR, FW_VERSION_MINOR);
1081f7917c00SJeff Kirsher 	else {
1082f7917c00SJeff Kirsher 		CH_WARN(adapter, "found newer FW version(%u.%u), "
1083f7917c00SJeff Kirsher 		        "driver compiled for version %u.%u\n", major, minor,
1084f7917c00SJeff Kirsher 			FW_VERSION_MAJOR, FW_VERSION_MINOR);
1085f7917c00SJeff Kirsher 		return 0;
1086f7917c00SJeff Kirsher 	}
1087f7917c00SJeff Kirsher 	return -EINVAL;
1088f7917c00SJeff Kirsher }
1089f7917c00SJeff Kirsher 
1090f7917c00SJeff Kirsher /**
1091f7917c00SJeff Kirsher  *	t3_flash_erase_sectors - erase a range of flash sectors
1092f7917c00SJeff Kirsher  *	@adapter: the adapter
1093f7917c00SJeff Kirsher  *	@start: the first sector to erase
1094f7917c00SJeff Kirsher  *	@end: the last sector to erase
1095f7917c00SJeff Kirsher  *
1096f7917c00SJeff Kirsher  *	Erases the sectors in the given range.
1097f7917c00SJeff Kirsher  */
1098f7917c00SJeff Kirsher static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
1099f7917c00SJeff Kirsher {
1100f7917c00SJeff Kirsher 	while (start <= end) {
1101f7917c00SJeff Kirsher 		int ret;
1102f7917c00SJeff Kirsher 
1103f7917c00SJeff Kirsher 		if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
1104f7917c00SJeff Kirsher 		    (ret = sf1_write(adapter, 4, 0,
1105f7917c00SJeff Kirsher 				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
1106f7917c00SJeff Kirsher 		    (ret = flash_wait_op(adapter, 5, 500)) != 0)
1107f7917c00SJeff Kirsher 			return ret;
1108f7917c00SJeff Kirsher 		start++;
1109f7917c00SJeff Kirsher 	}
1110f7917c00SJeff Kirsher 	return 0;
1111f7917c00SJeff Kirsher }
1112f7917c00SJeff Kirsher 
111349ce9c2cSBen Hutchings /**
1114f7917c00SJeff Kirsher  *	t3_load_fw - download firmware
1115f7917c00SJeff Kirsher  *	@adapter: the adapter
1116f7917c00SJeff Kirsher  *	@fw_data: the firmware image to write
1117f7917c00SJeff Kirsher  *	@size: image size
1118f7917c00SJeff Kirsher  *
1119f7917c00SJeff Kirsher  *	Write the supplied firmware image to the card's serial flash.
1120f7917c00SJeff Kirsher  *	The FW image has the following sections: @size - 8 bytes of code and
1121f7917c00SJeff Kirsher  *	data, followed by 4 bytes of FW version, followed by the 32-bit
1122f7917c00SJeff Kirsher  *	1's complement checksum of the whole image.
1123f7917c00SJeff Kirsher  */
1124f7917c00SJeff Kirsher int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
1125f7917c00SJeff Kirsher {
1126f7917c00SJeff Kirsher 	u32 csum;
1127f7917c00SJeff Kirsher 	unsigned int i;
1128f7917c00SJeff Kirsher 	const __be32 *p = (const __be32 *)fw_data;
1129f7917c00SJeff Kirsher 	int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
1130f7917c00SJeff Kirsher 
1131f7917c00SJeff Kirsher 	if ((size & 3) || size < FW_MIN_SIZE)
1132f7917c00SJeff Kirsher 		return -EINVAL;
1133f7917c00SJeff Kirsher 	if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
1134f7917c00SJeff Kirsher 		return -EFBIG;
1135f7917c00SJeff Kirsher 
1136f7917c00SJeff Kirsher 	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1137f7917c00SJeff Kirsher 		csum += ntohl(p[i]);
1138f7917c00SJeff Kirsher 	if (csum != 0xffffffff) {
1139f7917c00SJeff Kirsher 		CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
1140f7917c00SJeff Kirsher 		       csum);
1141f7917c00SJeff Kirsher 		return -EINVAL;
1142f7917c00SJeff Kirsher 	}
1143f7917c00SJeff Kirsher 
1144f7917c00SJeff Kirsher 	ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
1145f7917c00SJeff Kirsher 	if (ret)
1146f7917c00SJeff Kirsher 		goto out;
1147f7917c00SJeff Kirsher 
1148f7917c00SJeff Kirsher 	size -= 8;		/* trim off version and checksum */
1149f7917c00SJeff Kirsher 	for (addr = FW_FLASH_BOOT_ADDR; size;) {
1150f7917c00SJeff Kirsher 		unsigned int chunk_size = min(size, 256U);
1151f7917c00SJeff Kirsher 
1152f7917c00SJeff Kirsher 		ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
1153f7917c00SJeff Kirsher 		if (ret)
1154f7917c00SJeff Kirsher 			goto out;
1155f7917c00SJeff Kirsher 
1156f7917c00SJeff Kirsher 		addr += chunk_size;
1157f7917c00SJeff Kirsher 		fw_data += chunk_size;
1158f7917c00SJeff Kirsher 		size -= chunk_size;
1159f7917c00SJeff Kirsher 	}
1160f7917c00SJeff Kirsher 
1161f7917c00SJeff Kirsher 	ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
1162f7917c00SJeff Kirsher out:
1163f7917c00SJeff Kirsher 	if (ret)
1164f7917c00SJeff Kirsher 		CH_ERR(adapter, "firmware download failed, error %d\n", ret);
1165f7917c00SJeff Kirsher 	return ret;
1166f7917c00SJeff Kirsher }
1167f7917c00SJeff Kirsher 
1168f7917c00SJeff Kirsher #define CIM_CTL_BASE 0x2000
1169f7917c00SJeff Kirsher 
1170f7917c00SJeff Kirsher /**
1171f7917c00SJeff Kirsher  *      t3_cim_ctl_blk_read - read a block from CIM control region
1172f7917c00SJeff Kirsher  *
1173f7917c00SJeff Kirsher  *      @adap: the adapter
1174f7917c00SJeff Kirsher  *      @addr: the start address within the CIM control region
1175f7917c00SJeff Kirsher  *      @n: number of words to read
1176f7917c00SJeff Kirsher  *      @valp: where to store the result
1177f7917c00SJeff Kirsher  *
1178f7917c00SJeff Kirsher  *      Reads a block of 4-byte words from the CIM control region.
1179f7917c00SJeff Kirsher  */
1180f7917c00SJeff Kirsher int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
1181f7917c00SJeff Kirsher 			unsigned int n, unsigned int *valp)
1182f7917c00SJeff Kirsher {
1183f7917c00SJeff Kirsher 	int ret = 0;
1184f7917c00SJeff Kirsher 
1185f7917c00SJeff Kirsher 	if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1186f7917c00SJeff Kirsher 		return -EBUSY;
1187f7917c00SJeff Kirsher 
1188f7917c00SJeff Kirsher 	for ( ; !ret && n--; addr += 4) {
1189f7917c00SJeff Kirsher 		t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
1190f7917c00SJeff Kirsher 		ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1191f7917c00SJeff Kirsher 				      0, 5, 2);
1192f7917c00SJeff Kirsher 		if (!ret)
1193f7917c00SJeff Kirsher 			*valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
1194f7917c00SJeff Kirsher 	}
1195f7917c00SJeff Kirsher 	return ret;
1196f7917c00SJeff Kirsher }
1197f7917c00SJeff Kirsher 
1198f7917c00SJeff Kirsher static void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg,
1199f7917c00SJeff Kirsher 			       u32 *rx_hash_high, u32 *rx_hash_low)
1200f7917c00SJeff Kirsher {
1201f7917c00SJeff Kirsher 	/* stop Rx unicast traffic */
1202f7917c00SJeff Kirsher 	t3_mac_disable_exact_filters(mac);
1203f7917c00SJeff Kirsher 
1204f7917c00SJeff Kirsher 	/* stop broadcast, multicast, promiscuous mode traffic */
1205f7917c00SJeff Kirsher 	*rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG);
1206f7917c00SJeff Kirsher 	t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
1207f7917c00SJeff Kirsher 			 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
1208f7917c00SJeff Kirsher 			 F_DISBCAST);
1209f7917c00SJeff Kirsher 
1210f7917c00SJeff Kirsher 	*rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH);
1211f7917c00SJeff Kirsher 	t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, 0);
1212f7917c00SJeff Kirsher 
1213f7917c00SJeff Kirsher 	*rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW);
1214f7917c00SJeff Kirsher 	t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, 0);
1215f7917c00SJeff Kirsher 
1216f7917c00SJeff Kirsher 	/* Leave time to drain max RX fifo */
1217f7917c00SJeff Kirsher 	msleep(1);
1218f7917c00SJeff Kirsher }
1219f7917c00SJeff Kirsher 
1220f7917c00SJeff Kirsher static void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg,
1221f7917c00SJeff Kirsher 			       u32 rx_hash_high, u32 rx_hash_low)
1222f7917c00SJeff Kirsher {
1223f7917c00SJeff Kirsher 	t3_mac_enable_exact_filters(mac);
1224f7917c00SJeff Kirsher 	t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
1225f7917c00SJeff Kirsher 			 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
1226f7917c00SJeff Kirsher 			 rx_cfg);
1227f7917c00SJeff Kirsher 	t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, rx_hash_high);
1228f7917c00SJeff Kirsher 	t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, rx_hash_low);
1229f7917c00SJeff Kirsher }
1230f7917c00SJeff Kirsher 
1231f7917c00SJeff Kirsher /**
1232f7917c00SJeff Kirsher  *	t3_link_changed - handle interface link changes
1233f7917c00SJeff Kirsher  *	@adapter: the adapter
1234f7917c00SJeff Kirsher  *	@port_id: the port index that changed link state
1235f7917c00SJeff Kirsher  *
1236f7917c00SJeff Kirsher  *	Called when a port's link settings change to propagate the new values
1237f7917c00SJeff Kirsher  *	to the associated PHY and MAC.  After performing the common tasks it
1238f7917c00SJeff Kirsher  *	invokes an OS-specific handler.
1239f7917c00SJeff Kirsher  */
1240f7917c00SJeff Kirsher void t3_link_changed(struct adapter *adapter, int port_id)
1241f7917c00SJeff Kirsher {
1242f7917c00SJeff Kirsher 	int link_ok, speed, duplex, fc;
1243f7917c00SJeff Kirsher 	struct port_info *pi = adap2pinfo(adapter, port_id);
1244f7917c00SJeff Kirsher 	struct cphy *phy = &pi->phy;
1245f7917c00SJeff Kirsher 	struct cmac *mac = &pi->mac;
1246f7917c00SJeff Kirsher 	struct link_config *lc = &pi->link_config;
1247f7917c00SJeff Kirsher 
1248f7917c00SJeff Kirsher 	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1249f7917c00SJeff Kirsher 
1250f7917c00SJeff Kirsher 	if (!lc->link_ok && link_ok) {
1251f7917c00SJeff Kirsher 		u32 rx_cfg, rx_hash_high, rx_hash_low;
1252f7917c00SJeff Kirsher 		u32 status;
1253f7917c00SJeff Kirsher 
1254f7917c00SJeff Kirsher 		t3_xgm_intr_enable(adapter, port_id);
1255f7917c00SJeff Kirsher 		t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
1256f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
1257f7917c00SJeff Kirsher 		t3_mac_enable(mac, MAC_DIRECTION_RX);
1258f7917c00SJeff Kirsher 
1259f7917c00SJeff Kirsher 		status = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
1260f7917c00SJeff Kirsher 		if (status & F_LINKFAULTCHANGE) {
1261f7917c00SJeff Kirsher 			mac->stats.link_faults++;
1262f7917c00SJeff Kirsher 			pi->link_fault = 1;
1263f7917c00SJeff Kirsher 		}
1264f7917c00SJeff Kirsher 		t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
1265f7917c00SJeff Kirsher 	}
1266f7917c00SJeff Kirsher 
1267f7917c00SJeff Kirsher 	if (lc->requested_fc & PAUSE_AUTONEG)
1268f7917c00SJeff Kirsher 		fc &= lc->requested_fc;
1269f7917c00SJeff Kirsher 	else
1270f7917c00SJeff Kirsher 		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1271f7917c00SJeff Kirsher 
1272f7917c00SJeff Kirsher 	if (link_ok == lc->link_ok && speed == lc->speed &&
1273f7917c00SJeff Kirsher 	    duplex == lc->duplex && fc == lc->fc)
1274f7917c00SJeff Kirsher 		return;                            /* nothing changed */
1275f7917c00SJeff Kirsher 
1276f7917c00SJeff Kirsher 	if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
1277f7917c00SJeff Kirsher 	    uses_xaui(adapter)) {
1278f7917c00SJeff Kirsher 		if (link_ok)
1279f7917c00SJeff Kirsher 			t3b_pcs_reset(mac);
1280f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
1281f7917c00SJeff Kirsher 			     link_ok ? F_TXACTENABLE | F_RXEN : 0);
1282f7917c00SJeff Kirsher 	}
1283f7917c00SJeff Kirsher 	lc->link_ok = link_ok;
1284f7917c00SJeff Kirsher 	lc->speed = speed < 0 ? SPEED_INVALID : speed;
1285f7917c00SJeff Kirsher 	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1286f7917c00SJeff Kirsher 
1287f7917c00SJeff Kirsher 	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
1288f7917c00SJeff Kirsher 		/* Set MAC speed, duplex, and flow control to match PHY. */
1289f7917c00SJeff Kirsher 		t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
1290f7917c00SJeff Kirsher 		lc->fc = fc;
1291f7917c00SJeff Kirsher 	}
1292f7917c00SJeff Kirsher 
1293f7917c00SJeff Kirsher 	t3_os_link_changed(adapter, port_id, link_ok && !pi->link_fault,
1294f7917c00SJeff Kirsher 			   speed, duplex, fc);
1295f7917c00SJeff Kirsher }
1296f7917c00SJeff Kirsher 
1297f7917c00SJeff Kirsher void t3_link_fault(struct adapter *adapter, int port_id)
1298f7917c00SJeff Kirsher {
1299f7917c00SJeff Kirsher 	struct port_info *pi = adap2pinfo(adapter, port_id);
1300f7917c00SJeff Kirsher 	struct cmac *mac = &pi->mac;
1301f7917c00SJeff Kirsher 	struct cphy *phy = &pi->phy;
1302f7917c00SJeff Kirsher 	struct link_config *lc = &pi->link_config;
1303f7917c00SJeff Kirsher 	int link_ok, speed, duplex, fc, link_fault;
1304f7917c00SJeff Kirsher 	u32 rx_cfg, rx_hash_high, rx_hash_low;
1305f7917c00SJeff Kirsher 
1306f7917c00SJeff Kirsher 	t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
1307f7917c00SJeff Kirsher 
1308f7917c00SJeff Kirsher 	if (adapter->params.rev > 0 && uses_xaui(adapter))
1309f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 0);
1310f7917c00SJeff Kirsher 
1311f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
1312f7917c00SJeff Kirsher 	t3_mac_enable(mac, MAC_DIRECTION_RX);
1313f7917c00SJeff Kirsher 
1314f7917c00SJeff Kirsher 	t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
1315f7917c00SJeff Kirsher 
1316f7917c00SJeff Kirsher 	link_fault = t3_read_reg(adapter,
1317f7917c00SJeff Kirsher 				 A_XGM_INT_STATUS + mac->offset);
1318f7917c00SJeff Kirsher 	link_fault &= F_LINKFAULTCHANGE;
1319f7917c00SJeff Kirsher 
1320f7917c00SJeff Kirsher 	link_ok = lc->link_ok;
1321f7917c00SJeff Kirsher 	speed = lc->speed;
1322f7917c00SJeff Kirsher 	duplex = lc->duplex;
1323f7917c00SJeff Kirsher 	fc = lc->fc;
1324f7917c00SJeff Kirsher 
1325f7917c00SJeff Kirsher 	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1326f7917c00SJeff Kirsher 
1327f7917c00SJeff Kirsher 	if (link_fault) {
1328f7917c00SJeff Kirsher 		lc->link_ok = 0;
1329f7917c00SJeff Kirsher 		lc->speed = SPEED_INVALID;
1330f7917c00SJeff Kirsher 		lc->duplex = DUPLEX_INVALID;
1331f7917c00SJeff Kirsher 
1332f7917c00SJeff Kirsher 		t3_os_link_fault(adapter, port_id, 0);
1333f7917c00SJeff Kirsher 
1334f7917c00SJeff Kirsher 		/* Account link faults only when the phy reports a link up */
1335f7917c00SJeff Kirsher 		if (link_ok)
1336f7917c00SJeff Kirsher 			mac->stats.link_faults++;
1337f7917c00SJeff Kirsher 	} else {
1338f7917c00SJeff Kirsher 		if (link_ok)
1339f7917c00SJeff Kirsher 			t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
1340f7917c00SJeff Kirsher 				     F_TXACTENABLE | F_RXEN);
1341f7917c00SJeff Kirsher 
1342f7917c00SJeff Kirsher 		pi->link_fault = 0;
1343f7917c00SJeff Kirsher 		lc->link_ok = (unsigned char)link_ok;
1344f7917c00SJeff Kirsher 		lc->speed = speed < 0 ? SPEED_INVALID : speed;
1345f7917c00SJeff Kirsher 		lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1346f7917c00SJeff Kirsher 		t3_os_link_fault(adapter, port_id, link_ok);
1347f7917c00SJeff Kirsher 	}
1348f7917c00SJeff Kirsher }
1349f7917c00SJeff Kirsher 
1350f7917c00SJeff Kirsher /**
1351f7917c00SJeff Kirsher  *	t3_link_start - apply link configuration to MAC/PHY
1352f7917c00SJeff Kirsher  *	@phy: the PHY to setup
1353f7917c00SJeff Kirsher  *	@mac: the MAC to setup
1354f7917c00SJeff Kirsher  *	@lc: the requested link configuration
1355f7917c00SJeff Kirsher  *
1356f7917c00SJeff Kirsher  *	Set up a port's MAC and PHY according to a desired link configuration.
1357f7917c00SJeff Kirsher  *	- If the PHY can auto-negotiate first decide what to advertise, then
1358f7917c00SJeff Kirsher  *	  enable/disable auto-negotiation as desired, and reset.
1359f7917c00SJeff Kirsher  *	- If the PHY does not auto-negotiate just reset it.
1360f7917c00SJeff Kirsher  *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
1361f7917c00SJeff Kirsher  *	  otherwise do it later based on the outcome of auto-negotiation.
1362f7917c00SJeff Kirsher  */
1363f7917c00SJeff Kirsher int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
1364f7917c00SJeff Kirsher {
1365f7917c00SJeff Kirsher 	unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1366f7917c00SJeff Kirsher 
1367f7917c00SJeff Kirsher 	lc->link_ok = 0;
1368f7917c00SJeff Kirsher 	if (lc->supported & SUPPORTED_Autoneg) {
1369f7917c00SJeff Kirsher 		lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
1370f7917c00SJeff Kirsher 		if (fc) {
1371f7917c00SJeff Kirsher 			lc->advertising |= ADVERTISED_Asym_Pause;
1372f7917c00SJeff Kirsher 			if (fc & PAUSE_RX)
1373f7917c00SJeff Kirsher 				lc->advertising |= ADVERTISED_Pause;
1374f7917c00SJeff Kirsher 		}
1375f7917c00SJeff Kirsher 		phy->ops->advertise(phy, lc->advertising);
1376f7917c00SJeff Kirsher 
1377f7917c00SJeff Kirsher 		if (lc->autoneg == AUTONEG_DISABLE) {
1378f7917c00SJeff Kirsher 			lc->speed = lc->requested_speed;
1379f7917c00SJeff Kirsher 			lc->duplex = lc->requested_duplex;
1380f7917c00SJeff Kirsher 			lc->fc = (unsigned char)fc;
1381f7917c00SJeff Kirsher 			t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
1382f7917c00SJeff Kirsher 						   fc);
1383f7917c00SJeff Kirsher 			/* Also disables autoneg */
1384f7917c00SJeff Kirsher 			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
1385f7917c00SJeff Kirsher 		} else
1386f7917c00SJeff Kirsher 			phy->ops->autoneg_enable(phy);
1387f7917c00SJeff Kirsher 	} else {
1388f7917c00SJeff Kirsher 		t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
1389f7917c00SJeff Kirsher 		lc->fc = (unsigned char)fc;
1390f7917c00SJeff Kirsher 		phy->ops->reset(phy, 0);
1391f7917c00SJeff Kirsher 	}
1392f7917c00SJeff Kirsher 	return 0;
1393f7917c00SJeff Kirsher }
1394f7917c00SJeff Kirsher 
1395f7917c00SJeff Kirsher /**
1396f7917c00SJeff Kirsher  *	t3_set_vlan_accel - control HW VLAN extraction
1397f7917c00SJeff Kirsher  *	@adapter: the adapter
1398f7917c00SJeff Kirsher  *	@ports: bitmap of adapter ports to operate on
1399f7917c00SJeff Kirsher  *	@on: enable (1) or disable (0) HW VLAN extraction
1400f7917c00SJeff Kirsher  *
1401f7917c00SJeff Kirsher  *	Enables or disables HW extraction of VLAN tags for the given port.
1402f7917c00SJeff Kirsher  */
1403f7917c00SJeff Kirsher void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
1404f7917c00SJeff Kirsher {
1405f7917c00SJeff Kirsher 	t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
1406f7917c00SJeff Kirsher 			 ports << S_VLANEXTRACTIONENABLE,
1407f7917c00SJeff Kirsher 			 on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
1408f7917c00SJeff Kirsher }
1409f7917c00SJeff Kirsher 
1410f7917c00SJeff Kirsher struct intr_info {
1411f7917c00SJeff Kirsher 	unsigned int mask;	/* bits to check in interrupt status */
1412f7917c00SJeff Kirsher 	const char *msg;	/* message to print or NULL */
1413f7917c00SJeff Kirsher 	short stat_idx;		/* stat counter to increment or -1 */
1414f7917c00SJeff Kirsher 	unsigned short fatal;	/* whether the condition reported is fatal */
1415f7917c00SJeff Kirsher };
1416f7917c00SJeff Kirsher 
1417f7917c00SJeff Kirsher /**
1418f7917c00SJeff Kirsher  *	t3_handle_intr_status - table driven interrupt handler
1419f7917c00SJeff Kirsher  *	@adapter: the adapter that generated the interrupt
1420f7917c00SJeff Kirsher  *	@reg: the interrupt status register to process
1421f7917c00SJeff Kirsher  *	@mask: a mask to apply to the interrupt status
1422f7917c00SJeff Kirsher  *	@acts: table of interrupt actions
1423f7917c00SJeff Kirsher  *	@stats: statistics counters tracking interrupt occurrences
1424f7917c00SJeff Kirsher  *
1425f7917c00SJeff Kirsher  *	A table driven interrupt handler that applies a set of masks to an
1426f7917c00SJeff Kirsher  *	interrupt status word and performs the corresponding actions if the
1427f7917c00SJeff Kirsher  *	interrupts described by the mask have occurred.  The actions include
1428f7917c00SJeff Kirsher  *	optionally printing a warning or alert message, and optionally
1429f7917c00SJeff Kirsher  *	incrementing a stat counter.  The table is terminated by an entry
1430f7917c00SJeff Kirsher  *	specifying mask 0.  Returns the number of fatal interrupt conditions.
1431f7917c00SJeff Kirsher  */
1432f7917c00SJeff Kirsher static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
1433f7917c00SJeff Kirsher 				 unsigned int mask,
1434f7917c00SJeff Kirsher 				 const struct intr_info *acts,
1435f7917c00SJeff Kirsher 				 unsigned long *stats)
1436f7917c00SJeff Kirsher {
1437f7917c00SJeff Kirsher 	int fatal = 0;
1438f7917c00SJeff Kirsher 	unsigned int status = t3_read_reg(adapter, reg) & mask;
1439f7917c00SJeff Kirsher 
1440f7917c00SJeff Kirsher 	for (; acts->mask; ++acts) {
1441f7917c00SJeff Kirsher 		if (!(status & acts->mask))
1442f7917c00SJeff Kirsher 			continue;
1443f7917c00SJeff Kirsher 		if (acts->fatal) {
1444f7917c00SJeff Kirsher 			fatal++;
1445f7917c00SJeff Kirsher 			CH_ALERT(adapter, "%s (0x%x)\n",
1446f7917c00SJeff Kirsher 				 acts->msg, status & acts->mask);
1447f7917c00SJeff Kirsher 			status &= ~acts->mask;
1448f7917c00SJeff Kirsher 		} else if (acts->msg)
1449f7917c00SJeff Kirsher 			CH_WARN(adapter, "%s (0x%x)\n",
1450f7917c00SJeff Kirsher 				acts->msg, status & acts->mask);
1451f7917c00SJeff Kirsher 		if (acts->stat_idx >= 0)
1452f7917c00SJeff Kirsher 			stats[acts->stat_idx]++;
1453f7917c00SJeff Kirsher 	}
1454f7917c00SJeff Kirsher 	if (status)		/* clear processed interrupts */
1455f7917c00SJeff Kirsher 		t3_write_reg(adapter, reg, status);
1456f7917c00SJeff Kirsher 	return fatal;
1457f7917c00SJeff Kirsher }
1458f7917c00SJeff Kirsher 
1459f7917c00SJeff Kirsher #define SGE_INTR_MASK (F_RSPQDISABLED | \
1460f7917c00SJeff Kirsher 		       F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \
1461f7917c00SJeff Kirsher 		       F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
1462f7917c00SJeff Kirsher 		       F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
1463f7917c00SJeff Kirsher 		       V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
1464f7917c00SJeff Kirsher 		       F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
1465f7917c00SJeff Kirsher 		       F_HIRCQPARITYERROR | F_LOPRIORITYDBFULL | \
1466f7917c00SJeff Kirsher 		       F_HIPRIORITYDBFULL | F_LOPRIORITYDBEMPTY | \
1467f7917c00SJeff Kirsher 		       F_HIPRIORITYDBEMPTY | F_HIPIODRBDROPERR | \
1468f7917c00SJeff Kirsher 		       F_LOPIODRBDROPERR)
1469f7917c00SJeff Kirsher #define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
1470f7917c00SJeff Kirsher 		       F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
1471f7917c00SJeff Kirsher 		       F_NFASRCHFAIL)
1472f7917c00SJeff Kirsher #define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
1473f7917c00SJeff Kirsher #define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1474f7917c00SJeff Kirsher 		       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
1475f7917c00SJeff Kirsher 		       F_TXFIFO_UNDERRUN)
1476f7917c00SJeff Kirsher #define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
1477f7917c00SJeff Kirsher 			F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
1478f7917c00SJeff Kirsher 			F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
1479f7917c00SJeff Kirsher 			F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
1480f7917c00SJeff Kirsher 			V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
1481f7917c00SJeff Kirsher 			V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
1482f7917c00SJeff Kirsher #define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
1483f7917c00SJeff Kirsher 			F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
1484f7917c00SJeff Kirsher 			/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
1485f7917c00SJeff Kirsher 			F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \
1486f7917c00SJeff Kirsher 			F_TXPARERR | V_BISTERR(M_BISTERR))
1487f7917c00SJeff Kirsher #define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \
1488f7917c00SJeff Kirsher 			 F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \
1489f7917c00SJeff Kirsher 			 F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0)
1490f7917c00SJeff Kirsher #define ULPTX_INTR_MASK 0xfc
1491f7917c00SJeff Kirsher #define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \
1492f7917c00SJeff Kirsher 			 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
1493f7917c00SJeff Kirsher 			 F_ZERO_SWITCH_ERROR)
1494f7917c00SJeff Kirsher #define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
1495f7917c00SJeff Kirsher 		       F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
1496f7917c00SJeff Kirsher 		       F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
1497f7917c00SJeff Kirsher 	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \
1498f7917c00SJeff Kirsher 		       F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \
1499f7917c00SJeff Kirsher 		       F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \
1500f7917c00SJeff Kirsher 		       F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \
1501f7917c00SJeff Kirsher 		       F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR)
1502f7917c00SJeff Kirsher #define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
1503f7917c00SJeff Kirsher 			V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
1504f7917c00SJeff Kirsher 			V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
1505f7917c00SJeff Kirsher #define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
1506f7917c00SJeff Kirsher 			V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
1507f7917c00SJeff Kirsher 			V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
1508f7917c00SJeff Kirsher #define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
1509f7917c00SJeff Kirsher 		       V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
1510f7917c00SJeff Kirsher 		       V_RXTPPARERRENB(M_RXTPPARERRENB) | \
1511f7917c00SJeff Kirsher 		       V_MCAPARERRENB(M_MCAPARERRENB))
1512f7917c00SJeff Kirsher #define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE)
1513f7917c00SJeff Kirsher #define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
1514f7917c00SJeff Kirsher 		      F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
1515f7917c00SJeff Kirsher 		      F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
1516f7917c00SJeff Kirsher 		      F_MPS0 | F_CPL_SWITCH)
1517f7917c00SJeff Kirsher /*
1518f7917c00SJeff Kirsher  * Interrupt handler for the PCIX1 module.
1519f7917c00SJeff Kirsher  */
1520f7917c00SJeff Kirsher static void pci_intr_handler(struct adapter *adapter)
1521f7917c00SJeff Kirsher {
1522f7917c00SJeff Kirsher 	static const struct intr_info pcix1_intr_info[] = {
1523f7917c00SJeff Kirsher 		{F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
1524f7917c00SJeff Kirsher 		{F_SIGTARABT, "PCI signaled target abort", -1, 1},
1525f7917c00SJeff Kirsher 		{F_RCVTARABT, "PCI received target abort", -1, 1},
1526f7917c00SJeff Kirsher 		{F_RCVMSTABT, "PCI received master abort", -1, 1},
1527f7917c00SJeff Kirsher 		{F_SIGSYSERR, "PCI signaled system error", -1, 1},
1528f7917c00SJeff Kirsher 		{F_DETPARERR, "PCI detected parity error", -1, 1},
1529f7917c00SJeff Kirsher 		{F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
1530f7917c00SJeff Kirsher 		{F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
1531f7917c00SJeff Kirsher 		{F_RCVSPLCMPERR, "PCI received split completion error", -1,
1532f7917c00SJeff Kirsher 		 1},
1533f7917c00SJeff Kirsher 		{F_DETCORECCERR, "PCI correctable ECC error",
1534f7917c00SJeff Kirsher 		 STAT_PCI_CORR_ECC, 0},
1535f7917c00SJeff Kirsher 		{F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
1536f7917c00SJeff Kirsher 		{F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
1537f7917c00SJeff Kirsher 		{V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
1538f7917c00SJeff Kirsher 		 1},
1539f7917c00SJeff Kirsher 		{V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
1540f7917c00SJeff Kirsher 		 1},
1541f7917c00SJeff Kirsher 		{V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
1542f7917c00SJeff Kirsher 		 1},
1543f7917c00SJeff Kirsher 		{V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
1544f7917c00SJeff Kirsher 		 "error", -1, 1},
1545f7917c00SJeff Kirsher 		{0}
1546f7917c00SJeff Kirsher 	};
1547f7917c00SJeff Kirsher 
1548f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
1549f7917c00SJeff Kirsher 				  pcix1_intr_info, adapter->irq_stats))
1550f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1551f7917c00SJeff Kirsher }
1552f7917c00SJeff Kirsher 
1553f7917c00SJeff Kirsher /*
1554f7917c00SJeff Kirsher  * Interrupt handler for the PCIE module.
1555f7917c00SJeff Kirsher  */
1556f7917c00SJeff Kirsher static void pcie_intr_handler(struct adapter *adapter)
1557f7917c00SJeff Kirsher {
1558f7917c00SJeff Kirsher 	static const struct intr_info pcie_intr_info[] = {
1559f7917c00SJeff Kirsher 		{F_PEXERR, "PCI PEX error", -1, 1},
1560f7917c00SJeff Kirsher 		{F_UNXSPLCPLERRR,
1561f7917c00SJeff Kirsher 		 "PCI unexpected split completion DMA read error", -1, 1},
1562f7917c00SJeff Kirsher 		{F_UNXSPLCPLERRC,
1563f7917c00SJeff Kirsher 		 "PCI unexpected split completion DMA command error", -1, 1},
1564f7917c00SJeff Kirsher 		{F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
1565f7917c00SJeff Kirsher 		{F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
1566f7917c00SJeff Kirsher 		{F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
1567f7917c00SJeff Kirsher 		{F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
1568f7917c00SJeff Kirsher 		{V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
1569f7917c00SJeff Kirsher 		 "PCI MSI-X table/PBA parity error", -1, 1},
1570f7917c00SJeff Kirsher 		{F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1},
1571f7917c00SJeff Kirsher 		{F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1},
1572f7917c00SJeff Kirsher 		{F_RXPARERR, "PCI Rx parity error", -1, 1},
1573f7917c00SJeff Kirsher 		{F_TXPARERR, "PCI Tx parity error", -1, 1},
1574f7917c00SJeff Kirsher 		{V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
1575f7917c00SJeff Kirsher 		{0}
1576f7917c00SJeff Kirsher 	};
1577f7917c00SJeff Kirsher 
1578f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
1579f7917c00SJeff Kirsher 		CH_ALERT(adapter, "PEX error code 0x%x\n",
1580f7917c00SJeff Kirsher 			 t3_read_reg(adapter, A_PCIE_PEX_ERR));
1581f7917c00SJeff Kirsher 
1582f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
1583f7917c00SJeff Kirsher 				  pcie_intr_info, adapter->irq_stats))
1584f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1585f7917c00SJeff Kirsher }
1586f7917c00SJeff Kirsher 
1587f7917c00SJeff Kirsher /*
1588f7917c00SJeff Kirsher  * TP interrupt handler.
1589f7917c00SJeff Kirsher  */
1590f7917c00SJeff Kirsher static void tp_intr_handler(struct adapter *adapter)
1591f7917c00SJeff Kirsher {
1592f7917c00SJeff Kirsher 	static const struct intr_info tp_intr_info[] = {
1593f7917c00SJeff Kirsher 		{0xffffff, "TP parity error", -1, 1},
1594f7917c00SJeff Kirsher 		{0x1000000, "TP out of Rx pages", -1, 1},
1595f7917c00SJeff Kirsher 		{0x2000000, "TP out of Tx pages", -1, 1},
1596f7917c00SJeff Kirsher 		{0}
1597f7917c00SJeff Kirsher 	};
1598f7917c00SJeff Kirsher 
1599f7917c00SJeff Kirsher 	static const struct intr_info tp_intr_info_t3c[] = {
1600f7917c00SJeff Kirsher 		{0x1fffffff, "TP parity error", -1, 1},
1601f7917c00SJeff Kirsher 		{F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1},
1602f7917c00SJeff Kirsher 		{F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1},
1603f7917c00SJeff Kirsher 		{0}
1604f7917c00SJeff Kirsher 	};
1605f7917c00SJeff Kirsher 
1606f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
1607f7917c00SJeff Kirsher 				  adapter->params.rev < T3_REV_C ?
1608f7917c00SJeff Kirsher 				  tp_intr_info : tp_intr_info_t3c, NULL))
1609f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1610f7917c00SJeff Kirsher }
1611f7917c00SJeff Kirsher 
1612f7917c00SJeff Kirsher /*
1613f7917c00SJeff Kirsher  * CIM interrupt handler.
1614f7917c00SJeff Kirsher  */
1615f7917c00SJeff Kirsher static void cim_intr_handler(struct adapter *adapter)
1616f7917c00SJeff Kirsher {
1617f7917c00SJeff Kirsher 	static const struct intr_info cim_intr_info[] = {
1618f7917c00SJeff Kirsher 		{F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
1619f7917c00SJeff Kirsher 		{F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
1620f7917c00SJeff Kirsher 		{F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
1621f7917c00SJeff Kirsher 		{F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
1622f7917c00SJeff Kirsher 		{F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
1623f7917c00SJeff Kirsher 		{F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
1624f7917c00SJeff Kirsher 		{F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
1625f7917c00SJeff Kirsher 		{F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
1626f7917c00SJeff Kirsher 		{F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
1627f7917c00SJeff Kirsher 		{F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
1628f7917c00SJeff Kirsher 		{F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
1629f7917c00SJeff Kirsher 		{F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
1630f7917c00SJeff Kirsher 		{F_DRAMPARERR, "CIM DRAM parity error", -1, 1},
1631f7917c00SJeff Kirsher 		{F_ICACHEPARERR, "CIM icache parity error", -1, 1},
1632f7917c00SJeff Kirsher 		{F_DCACHEPARERR, "CIM dcache parity error", -1, 1},
1633f7917c00SJeff Kirsher 		{F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1},
1634f7917c00SJeff Kirsher 		{F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1},
1635f7917c00SJeff Kirsher 		{F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1},
1636f7917c00SJeff Kirsher 		{F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1},
1637f7917c00SJeff Kirsher 		{F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1},
1638f7917c00SJeff Kirsher 		{F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1},
1639f7917c00SJeff Kirsher 		{F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1},
1640f7917c00SJeff Kirsher 		{F_ITAGPARERR, "CIM itag parity error", -1, 1},
1641f7917c00SJeff Kirsher 		{F_DTAGPARERR, "CIM dtag parity error", -1, 1},
1642f7917c00SJeff Kirsher 		{0}
1643f7917c00SJeff Kirsher 	};
1644f7917c00SJeff Kirsher 
1645f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
1646f7917c00SJeff Kirsher 				  cim_intr_info, NULL))
1647f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1648f7917c00SJeff Kirsher }
1649f7917c00SJeff Kirsher 
1650f7917c00SJeff Kirsher /*
1651f7917c00SJeff Kirsher  * ULP RX interrupt handler.
1652f7917c00SJeff Kirsher  */
1653f7917c00SJeff Kirsher static void ulprx_intr_handler(struct adapter *adapter)
1654f7917c00SJeff Kirsher {
1655f7917c00SJeff Kirsher 	static const struct intr_info ulprx_intr_info[] = {
1656f7917c00SJeff Kirsher 		{F_PARERRDATA, "ULP RX data parity error", -1, 1},
1657f7917c00SJeff Kirsher 		{F_PARERRPCMD, "ULP RX command parity error", -1, 1},
1658f7917c00SJeff Kirsher 		{F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1},
1659f7917c00SJeff Kirsher 		{F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1},
1660f7917c00SJeff Kirsher 		{F_ARBFPERR, "ULP RX ArbF parity error", -1, 1},
1661f7917c00SJeff Kirsher 		{F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1},
1662f7917c00SJeff Kirsher 		{F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1},
1663f7917c00SJeff Kirsher 		{F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1},
1664f7917c00SJeff Kirsher 		{0}
1665f7917c00SJeff Kirsher 	};
1666f7917c00SJeff Kirsher 
1667f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
1668f7917c00SJeff Kirsher 				  ulprx_intr_info, NULL))
1669f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1670f7917c00SJeff Kirsher }
1671f7917c00SJeff Kirsher 
1672f7917c00SJeff Kirsher /*
1673f7917c00SJeff Kirsher  * ULP TX interrupt handler.
1674f7917c00SJeff Kirsher  */
1675f7917c00SJeff Kirsher static void ulptx_intr_handler(struct adapter *adapter)
1676f7917c00SJeff Kirsher {
1677f7917c00SJeff Kirsher 	static const struct intr_info ulptx_intr_info[] = {
1678f7917c00SJeff Kirsher 		{F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
1679f7917c00SJeff Kirsher 		 STAT_ULP_CH0_PBL_OOB, 0},
1680f7917c00SJeff Kirsher 		{F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
1681f7917c00SJeff Kirsher 		 STAT_ULP_CH1_PBL_OOB, 0},
1682f7917c00SJeff Kirsher 		{0xfc, "ULP TX parity error", -1, 1},
1683f7917c00SJeff Kirsher 		{0}
1684f7917c00SJeff Kirsher 	};
1685f7917c00SJeff Kirsher 
1686f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
1687f7917c00SJeff Kirsher 				  ulptx_intr_info, adapter->irq_stats))
1688f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1689f7917c00SJeff Kirsher }
1690f7917c00SJeff Kirsher 
1691f7917c00SJeff Kirsher #define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
1692f7917c00SJeff Kirsher 	F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
1693f7917c00SJeff Kirsher 	F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
1694f7917c00SJeff Kirsher 	F_ICSPI1_TX_FRAMING_ERROR)
1695f7917c00SJeff Kirsher #define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
1696f7917c00SJeff Kirsher 	F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
1697f7917c00SJeff Kirsher 	F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
1698f7917c00SJeff Kirsher 	F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
1699f7917c00SJeff Kirsher 
1700f7917c00SJeff Kirsher /*
1701f7917c00SJeff Kirsher  * PM TX interrupt handler.
1702f7917c00SJeff Kirsher  */
1703f7917c00SJeff Kirsher static void pmtx_intr_handler(struct adapter *adapter)
1704f7917c00SJeff Kirsher {
1705f7917c00SJeff Kirsher 	static const struct intr_info pmtx_intr_info[] = {
1706f7917c00SJeff Kirsher 		{F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
1707f7917c00SJeff Kirsher 		{ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
1708f7917c00SJeff Kirsher 		{OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
1709f7917c00SJeff Kirsher 		{V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
1710f7917c00SJeff Kirsher 		 "PMTX ispi parity error", -1, 1},
1711f7917c00SJeff Kirsher 		{V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
1712f7917c00SJeff Kirsher 		 "PMTX ospi parity error", -1, 1},
1713f7917c00SJeff Kirsher 		{0}
1714f7917c00SJeff Kirsher 	};
1715f7917c00SJeff Kirsher 
1716f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
1717f7917c00SJeff Kirsher 				  pmtx_intr_info, NULL))
1718f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1719f7917c00SJeff Kirsher }
1720f7917c00SJeff Kirsher 
1721f7917c00SJeff Kirsher #define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
1722f7917c00SJeff Kirsher 	F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
1723f7917c00SJeff Kirsher 	F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
1724f7917c00SJeff Kirsher 	F_IESPI1_TX_FRAMING_ERROR)
1725f7917c00SJeff Kirsher #define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
1726f7917c00SJeff Kirsher 	F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
1727f7917c00SJeff Kirsher 	F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
1728f7917c00SJeff Kirsher 	F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
1729f7917c00SJeff Kirsher 
1730f7917c00SJeff Kirsher /*
1731f7917c00SJeff Kirsher  * PM RX interrupt handler.
1732f7917c00SJeff Kirsher  */
1733f7917c00SJeff Kirsher static void pmrx_intr_handler(struct adapter *adapter)
1734f7917c00SJeff Kirsher {
1735f7917c00SJeff Kirsher 	static const struct intr_info pmrx_intr_info[] = {
1736f7917c00SJeff Kirsher 		{F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
1737f7917c00SJeff Kirsher 		{IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
1738f7917c00SJeff Kirsher 		{OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
1739f7917c00SJeff Kirsher 		{V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
1740f7917c00SJeff Kirsher 		 "PMRX ispi parity error", -1, 1},
1741f7917c00SJeff Kirsher 		{V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
1742f7917c00SJeff Kirsher 		 "PMRX ospi parity error", -1, 1},
1743f7917c00SJeff Kirsher 		{0}
1744f7917c00SJeff Kirsher 	};
1745f7917c00SJeff Kirsher 
1746f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
1747f7917c00SJeff Kirsher 				  pmrx_intr_info, NULL))
1748f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1749f7917c00SJeff Kirsher }
1750f7917c00SJeff Kirsher 
1751f7917c00SJeff Kirsher /*
1752f7917c00SJeff Kirsher  * CPL switch interrupt handler.
1753f7917c00SJeff Kirsher  */
1754f7917c00SJeff Kirsher static void cplsw_intr_handler(struct adapter *adapter)
1755f7917c00SJeff Kirsher {
1756f7917c00SJeff Kirsher 	static const struct intr_info cplsw_intr_info[] = {
1757f7917c00SJeff Kirsher 		{F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1},
1758f7917c00SJeff Kirsher 		{F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1},
1759f7917c00SJeff Kirsher 		{F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
1760f7917c00SJeff Kirsher 		{F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
1761f7917c00SJeff Kirsher 		{F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
1762f7917c00SJeff Kirsher 		{F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
1763f7917c00SJeff Kirsher 		{0}
1764f7917c00SJeff Kirsher 	};
1765f7917c00SJeff Kirsher 
1766f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
1767f7917c00SJeff Kirsher 				  cplsw_intr_info, NULL))
1768f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1769f7917c00SJeff Kirsher }
1770f7917c00SJeff Kirsher 
1771f7917c00SJeff Kirsher /*
1772f7917c00SJeff Kirsher  * MPS interrupt handler.
1773f7917c00SJeff Kirsher  */
1774f7917c00SJeff Kirsher static void mps_intr_handler(struct adapter *adapter)
1775f7917c00SJeff Kirsher {
1776f7917c00SJeff Kirsher 	static const struct intr_info mps_intr_info[] = {
1777f7917c00SJeff Kirsher 		{0x1ff, "MPS parity error", -1, 1},
1778f7917c00SJeff Kirsher 		{0}
1779f7917c00SJeff Kirsher 	};
1780f7917c00SJeff Kirsher 
1781f7917c00SJeff Kirsher 	if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
1782f7917c00SJeff Kirsher 				  mps_intr_info, NULL))
1783f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1784f7917c00SJeff Kirsher }
1785f7917c00SJeff Kirsher 
1786f7917c00SJeff Kirsher #define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
1787f7917c00SJeff Kirsher 
1788f7917c00SJeff Kirsher /*
1789f7917c00SJeff Kirsher  * MC7 interrupt handler.
1790f7917c00SJeff Kirsher  */
1791f7917c00SJeff Kirsher static void mc7_intr_handler(struct mc7 *mc7)
1792f7917c00SJeff Kirsher {
1793f7917c00SJeff Kirsher 	struct adapter *adapter = mc7->adapter;
1794f7917c00SJeff Kirsher 	u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
1795f7917c00SJeff Kirsher 
1796f7917c00SJeff Kirsher 	if (cause & F_CE) {
1797f7917c00SJeff Kirsher 		mc7->stats.corr_err++;
1798f7917c00SJeff Kirsher 		CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
1799f7917c00SJeff Kirsher 			"data 0x%x 0x%x 0x%x\n", mc7->name,
1800f7917c00SJeff Kirsher 			t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
1801f7917c00SJeff Kirsher 			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
1802f7917c00SJeff Kirsher 			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
1803f7917c00SJeff Kirsher 			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
1804f7917c00SJeff Kirsher 	}
1805f7917c00SJeff Kirsher 
1806f7917c00SJeff Kirsher 	if (cause & F_UE) {
1807f7917c00SJeff Kirsher 		mc7->stats.uncorr_err++;
1808f7917c00SJeff Kirsher 		CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
1809f7917c00SJeff Kirsher 			 "data 0x%x 0x%x 0x%x\n", mc7->name,
1810f7917c00SJeff Kirsher 			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
1811f7917c00SJeff Kirsher 			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
1812f7917c00SJeff Kirsher 			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
1813f7917c00SJeff Kirsher 			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
1814f7917c00SJeff Kirsher 	}
1815f7917c00SJeff Kirsher 
1816f7917c00SJeff Kirsher 	if (G_PE(cause)) {
1817f7917c00SJeff Kirsher 		mc7->stats.parity_err++;
1818f7917c00SJeff Kirsher 		CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
1819f7917c00SJeff Kirsher 			 mc7->name, G_PE(cause));
1820f7917c00SJeff Kirsher 	}
1821f7917c00SJeff Kirsher 
1822f7917c00SJeff Kirsher 	if (cause & F_AE) {
1823f7917c00SJeff Kirsher 		u32 addr = 0;
1824f7917c00SJeff Kirsher 
1825f7917c00SJeff Kirsher 		if (adapter->params.rev > 0)
1826f7917c00SJeff Kirsher 			addr = t3_read_reg(adapter,
1827f7917c00SJeff Kirsher 					   mc7->offset + A_MC7_ERR_ADDR);
1828f7917c00SJeff Kirsher 		mc7->stats.addr_err++;
1829f7917c00SJeff Kirsher 		CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
1830f7917c00SJeff Kirsher 			 mc7->name, addr);
1831f7917c00SJeff Kirsher 	}
1832f7917c00SJeff Kirsher 
1833f7917c00SJeff Kirsher 	if (cause & MC7_INTR_FATAL)
1834f7917c00SJeff Kirsher 		t3_fatal_err(adapter);
1835f7917c00SJeff Kirsher 
1836f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
1837f7917c00SJeff Kirsher }
1838f7917c00SJeff Kirsher 
1839f7917c00SJeff Kirsher #define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1840f7917c00SJeff Kirsher 			V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
1841f7917c00SJeff Kirsher /*
1842f7917c00SJeff Kirsher  * XGMAC interrupt handler.
1843f7917c00SJeff Kirsher  */
1844f7917c00SJeff Kirsher static int mac_intr_handler(struct adapter *adap, unsigned int idx)
1845f7917c00SJeff Kirsher {
1846f7917c00SJeff Kirsher 	struct cmac *mac = &adap2pinfo(adap, idx)->mac;
1847f7917c00SJeff Kirsher 	/*
1848f7917c00SJeff Kirsher 	 * We mask out interrupt causes for which we're not taking interrupts.
1849f7917c00SJeff Kirsher 	 * This allows us to use polling logic to monitor some of the other
1850f7917c00SJeff Kirsher 	 * conditions when taking interrupts would impose too much load on the
1851f7917c00SJeff Kirsher 	 * system.
1852f7917c00SJeff Kirsher 	 */
1853f7917c00SJeff Kirsher 	u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) &
1854f7917c00SJeff Kirsher 		    ~F_RXFIFO_OVERFLOW;
1855f7917c00SJeff Kirsher 
1856f7917c00SJeff Kirsher 	if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
1857f7917c00SJeff Kirsher 		mac->stats.tx_fifo_parity_err++;
1858f7917c00SJeff Kirsher 		CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
1859f7917c00SJeff Kirsher 	}
1860f7917c00SJeff Kirsher 	if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
1861f7917c00SJeff Kirsher 		mac->stats.rx_fifo_parity_err++;
1862f7917c00SJeff Kirsher 		CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
1863f7917c00SJeff Kirsher 	}
1864f7917c00SJeff Kirsher 	if (cause & F_TXFIFO_UNDERRUN)
1865f7917c00SJeff Kirsher 		mac->stats.tx_fifo_urun++;
1866f7917c00SJeff Kirsher 	if (cause & F_RXFIFO_OVERFLOW)
1867f7917c00SJeff Kirsher 		mac->stats.rx_fifo_ovfl++;
1868f7917c00SJeff Kirsher 	if (cause & V_SERDES_LOS(M_SERDES_LOS))
1869f7917c00SJeff Kirsher 		mac->stats.serdes_signal_loss++;
1870f7917c00SJeff Kirsher 	if (cause & F_XAUIPCSCTCERR)
1871f7917c00SJeff Kirsher 		mac->stats.xaui_pcs_ctc_err++;
1872f7917c00SJeff Kirsher 	if (cause & F_XAUIPCSALIGNCHANGE)
1873f7917c00SJeff Kirsher 		mac->stats.xaui_pcs_align_change++;
1874f7917c00SJeff Kirsher 	if (cause & F_XGM_INT) {
1875f7917c00SJeff Kirsher 		t3_set_reg_field(adap,
1876f7917c00SJeff Kirsher 				 A_XGM_INT_ENABLE + mac->offset,
1877f7917c00SJeff Kirsher 				 F_XGM_INT, 0);
1878f7917c00SJeff Kirsher 		mac->stats.link_faults++;
1879f7917c00SJeff Kirsher 
1880f7917c00SJeff Kirsher 		t3_os_link_fault_handler(adap, idx);
1881f7917c00SJeff Kirsher 	}
1882f7917c00SJeff Kirsher 
1883f7917c00SJeff Kirsher 	if (cause & XGM_INTR_FATAL)
1884f7917c00SJeff Kirsher 		t3_fatal_err(adap);
1885f7917c00SJeff Kirsher 
1886f7917c00SJeff Kirsher 	t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
1887f7917c00SJeff Kirsher 	return cause != 0;
1888f7917c00SJeff Kirsher }
1889f7917c00SJeff Kirsher 
1890f7917c00SJeff Kirsher /*
1891f7917c00SJeff Kirsher  * Interrupt handler for PHY events.
1892f7917c00SJeff Kirsher  */
1893f7917c00SJeff Kirsher int t3_phy_intr_handler(struct adapter *adapter)
1894f7917c00SJeff Kirsher {
1895f7917c00SJeff Kirsher 	u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
1896f7917c00SJeff Kirsher 
1897f7917c00SJeff Kirsher 	for_each_port(adapter, i) {
1898f7917c00SJeff Kirsher 		struct port_info *p = adap2pinfo(adapter, i);
1899f7917c00SJeff Kirsher 
1900f7917c00SJeff Kirsher 		if (!(p->phy.caps & SUPPORTED_IRQ))
1901f7917c00SJeff Kirsher 			continue;
1902f7917c00SJeff Kirsher 
1903f7917c00SJeff Kirsher 		if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) {
1904f7917c00SJeff Kirsher 			int phy_cause = p->phy.ops->intr_handler(&p->phy);
1905f7917c00SJeff Kirsher 
1906f7917c00SJeff Kirsher 			if (phy_cause & cphy_cause_link_change)
1907f7917c00SJeff Kirsher 				t3_link_changed(adapter, i);
1908f7917c00SJeff Kirsher 			if (phy_cause & cphy_cause_fifo_error)
1909f7917c00SJeff Kirsher 				p->phy.fifo_errors++;
1910f7917c00SJeff Kirsher 			if (phy_cause & cphy_cause_module_change)
1911f7917c00SJeff Kirsher 				t3_os_phymod_changed(adapter, i);
1912f7917c00SJeff Kirsher 		}
1913f7917c00SJeff Kirsher 	}
1914f7917c00SJeff Kirsher 
1915f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
1916f7917c00SJeff Kirsher 	return 0;
1917f7917c00SJeff Kirsher }
1918f7917c00SJeff Kirsher 
1919f7917c00SJeff Kirsher /*
1920f7917c00SJeff Kirsher  * T3 slow path (non-data) interrupt handler.
1921f7917c00SJeff Kirsher  */
1922f7917c00SJeff Kirsher int t3_slow_intr_handler(struct adapter *adapter)
1923f7917c00SJeff Kirsher {
1924f7917c00SJeff Kirsher 	u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
1925f7917c00SJeff Kirsher 
1926f7917c00SJeff Kirsher 	cause &= adapter->slow_intr_mask;
1927f7917c00SJeff Kirsher 	if (!cause)
1928f7917c00SJeff Kirsher 		return 0;
1929f7917c00SJeff Kirsher 	if (cause & F_PCIM0) {
1930f7917c00SJeff Kirsher 		if (is_pcie(adapter))
1931f7917c00SJeff Kirsher 			pcie_intr_handler(adapter);
1932f7917c00SJeff Kirsher 		else
1933f7917c00SJeff Kirsher 			pci_intr_handler(adapter);
1934f7917c00SJeff Kirsher 	}
1935f7917c00SJeff Kirsher 	if (cause & F_SGE3)
1936f7917c00SJeff Kirsher 		t3_sge_err_intr_handler(adapter);
1937f7917c00SJeff Kirsher 	if (cause & F_MC7_PMRX)
1938f7917c00SJeff Kirsher 		mc7_intr_handler(&adapter->pmrx);
1939f7917c00SJeff Kirsher 	if (cause & F_MC7_PMTX)
1940f7917c00SJeff Kirsher 		mc7_intr_handler(&adapter->pmtx);
1941f7917c00SJeff Kirsher 	if (cause & F_MC7_CM)
1942f7917c00SJeff Kirsher 		mc7_intr_handler(&adapter->cm);
1943f7917c00SJeff Kirsher 	if (cause & F_CIM)
1944f7917c00SJeff Kirsher 		cim_intr_handler(adapter);
1945f7917c00SJeff Kirsher 	if (cause & F_TP1)
1946f7917c00SJeff Kirsher 		tp_intr_handler(adapter);
1947f7917c00SJeff Kirsher 	if (cause & F_ULP2_RX)
1948f7917c00SJeff Kirsher 		ulprx_intr_handler(adapter);
1949f7917c00SJeff Kirsher 	if (cause & F_ULP2_TX)
1950f7917c00SJeff Kirsher 		ulptx_intr_handler(adapter);
1951f7917c00SJeff Kirsher 	if (cause & F_PM1_RX)
1952f7917c00SJeff Kirsher 		pmrx_intr_handler(adapter);
1953f7917c00SJeff Kirsher 	if (cause & F_PM1_TX)
1954f7917c00SJeff Kirsher 		pmtx_intr_handler(adapter);
1955f7917c00SJeff Kirsher 	if (cause & F_CPL_SWITCH)
1956f7917c00SJeff Kirsher 		cplsw_intr_handler(adapter);
1957f7917c00SJeff Kirsher 	if (cause & F_MPS0)
1958f7917c00SJeff Kirsher 		mps_intr_handler(adapter);
1959f7917c00SJeff Kirsher 	if (cause & F_MC5A)
1960f7917c00SJeff Kirsher 		t3_mc5_intr_handler(&adapter->mc5);
1961f7917c00SJeff Kirsher 	if (cause & F_XGMAC0_0)
1962f7917c00SJeff Kirsher 		mac_intr_handler(adapter, 0);
1963f7917c00SJeff Kirsher 	if (cause & F_XGMAC0_1)
1964f7917c00SJeff Kirsher 		mac_intr_handler(adapter, 1);
1965f7917c00SJeff Kirsher 	if (cause & F_T3DBG)
1966f7917c00SJeff Kirsher 		t3_os_ext_intr_handler(adapter);
1967f7917c00SJeff Kirsher 
1968f7917c00SJeff Kirsher 	/* Clear the interrupts just processed. */
1969f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
1970f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_PL_INT_CAUSE0);	/* flush */
1971f7917c00SJeff Kirsher 	return 1;
1972f7917c00SJeff Kirsher }
1973f7917c00SJeff Kirsher 
1974f7917c00SJeff Kirsher static unsigned int calc_gpio_intr(struct adapter *adap)
1975f7917c00SJeff Kirsher {
1976f7917c00SJeff Kirsher 	unsigned int i, gpi_intr = 0;
1977f7917c00SJeff Kirsher 
1978f7917c00SJeff Kirsher 	for_each_port(adap, i)
1979f7917c00SJeff Kirsher 		if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) &&
1980f7917c00SJeff Kirsher 		    adapter_info(adap)->gpio_intr[i])
1981f7917c00SJeff Kirsher 			gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i];
1982f7917c00SJeff Kirsher 	return gpi_intr;
1983f7917c00SJeff Kirsher }
1984f7917c00SJeff Kirsher 
1985f7917c00SJeff Kirsher /**
1986f7917c00SJeff Kirsher  *	t3_intr_enable - enable interrupts
1987f7917c00SJeff Kirsher  *	@adapter: the adapter whose interrupts should be enabled
1988f7917c00SJeff Kirsher  *
1989f7917c00SJeff Kirsher  *	Enable interrupts by setting the interrupt enable registers of the
1990f7917c00SJeff Kirsher  *	various HW modules and then enabling the top-level interrupt
1991f7917c00SJeff Kirsher  *	concentrator.
1992f7917c00SJeff Kirsher  */
1993f7917c00SJeff Kirsher void t3_intr_enable(struct adapter *adapter)
1994f7917c00SJeff Kirsher {
1995f7917c00SJeff Kirsher 	static const struct addr_val_pair intr_en_avp[] = {
1996f7917c00SJeff Kirsher 		{A_SG_INT_ENABLE, SGE_INTR_MASK},
1997f7917c00SJeff Kirsher 		{A_MC7_INT_ENABLE, MC7_INTR_MASK},
1998f7917c00SJeff Kirsher 		{A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
1999f7917c00SJeff Kirsher 		 MC7_INTR_MASK},
2000f7917c00SJeff Kirsher 		{A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
2001f7917c00SJeff Kirsher 		 MC7_INTR_MASK},
2002f7917c00SJeff Kirsher 		{A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
2003f7917c00SJeff Kirsher 		{A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
2004f7917c00SJeff Kirsher 		{A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
2005f7917c00SJeff Kirsher 		{A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
2006f7917c00SJeff Kirsher 		{A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
2007f7917c00SJeff Kirsher 		{A_MPS_INT_ENABLE, MPS_INTR_MASK},
2008f7917c00SJeff Kirsher 	};
2009f7917c00SJeff Kirsher 
2010f7917c00SJeff Kirsher 	adapter->slow_intr_mask = PL_INTR_MASK;
2011f7917c00SJeff Kirsher 
2012f7917c00SJeff Kirsher 	t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
2013f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_TP_INT_ENABLE,
2014f7917c00SJeff Kirsher 		     adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff);
2015f7917c00SJeff Kirsher 
2016f7917c00SJeff Kirsher 	if (adapter->params.rev > 0) {
2017f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_CPL_INTR_ENABLE,
2018f7917c00SJeff Kirsher 			     CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
2019f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
2020f7917c00SJeff Kirsher 			     ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
2021f7917c00SJeff Kirsher 			     F_PBL_BOUND_ERR_CH1);
2022f7917c00SJeff Kirsher 	} else {
2023f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
2024f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
2025f7917c00SJeff Kirsher 	}
2026f7917c00SJeff Kirsher 
2027f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter));
2028f7917c00SJeff Kirsher 
2029f7917c00SJeff Kirsher 	if (is_pcie(adapter))
2030f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
2031f7917c00SJeff Kirsher 	else
2032f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
2033f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
2034f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_PL_INT_ENABLE0);	/* flush */
2035f7917c00SJeff Kirsher }
2036f7917c00SJeff Kirsher 
2037f7917c00SJeff Kirsher /**
2038f7917c00SJeff Kirsher  *	t3_intr_disable - disable a card's interrupts
2039f7917c00SJeff Kirsher  *	@adapter: the adapter whose interrupts should be disabled
2040f7917c00SJeff Kirsher  *
2041f7917c00SJeff Kirsher  *	Disable interrupts.  We only disable the top-level interrupt
2042f7917c00SJeff Kirsher  *	concentrator and the SGE data interrupts.
2043f7917c00SJeff Kirsher  */
2044f7917c00SJeff Kirsher void t3_intr_disable(struct adapter *adapter)
2045f7917c00SJeff Kirsher {
2046f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
2047f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_PL_INT_ENABLE0);	/* flush */
2048f7917c00SJeff Kirsher 	adapter->slow_intr_mask = 0;
2049f7917c00SJeff Kirsher }
2050f7917c00SJeff Kirsher 
2051f7917c00SJeff Kirsher /**
2052f7917c00SJeff Kirsher  *	t3_intr_clear - clear all interrupts
2053f7917c00SJeff Kirsher  *	@adapter: the adapter whose interrupts should be cleared
2054f7917c00SJeff Kirsher  *
2055f7917c00SJeff Kirsher  *	Clears all interrupts.
2056f7917c00SJeff Kirsher  */
2057f7917c00SJeff Kirsher void t3_intr_clear(struct adapter *adapter)
2058f7917c00SJeff Kirsher {
2059f7917c00SJeff Kirsher 	static const unsigned int cause_reg_addr[] = {
2060f7917c00SJeff Kirsher 		A_SG_INT_CAUSE,
2061f7917c00SJeff Kirsher 		A_SG_RSPQ_FL_STATUS,
2062f7917c00SJeff Kirsher 		A_PCIX_INT_CAUSE,
2063f7917c00SJeff Kirsher 		A_MC7_INT_CAUSE,
2064f7917c00SJeff Kirsher 		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
2065f7917c00SJeff Kirsher 		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
2066f7917c00SJeff Kirsher 		A_CIM_HOST_INT_CAUSE,
2067f7917c00SJeff Kirsher 		A_TP_INT_CAUSE,
2068f7917c00SJeff Kirsher 		A_MC5_DB_INT_CAUSE,
2069f7917c00SJeff Kirsher 		A_ULPRX_INT_CAUSE,
2070f7917c00SJeff Kirsher 		A_ULPTX_INT_CAUSE,
2071f7917c00SJeff Kirsher 		A_CPL_INTR_CAUSE,
2072f7917c00SJeff Kirsher 		A_PM1_TX_INT_CAUSE,
2073f7917c00SJeff Kirsher 		A_PM1_RX_INT_CAUSE,
2074f7917c00SJeff Kirsher 		A_MPS_INT_CAUSE,
2075f7917c00SJeff Kirsher 		A_T3DBG_INT_CAUSE,
2076f7917c00SJeff Kirsher 	};
2077f7917c00SJeff Kirsher 	unsigned int i;
2078f7917c00SJeff Kirsher 
2079f7917c00SJeff Kirsher 	/* Clear PHY and MAC interrupts for each port. */
2080f7917c00SJeff Kirsher 	for_each_port(adapter, i)
2081f7917c00SJeff Kirsher 	    t3_port_intr_clear(adapter, i);
2082f7917c00SJeff Kirsher 
2083f7917c00SJeff Kirsher 	for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
2084f7917c00SJeff Kirsher 		t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
2085f7917c00SJeff Kirsher 
2086f7917c00SJeff Kirsher 	if (is_pcie(adapter))
2087f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
2088f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
2089f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_PL_INT_CAUSE0);	/* flush */
2090f7917c00SJeff Kirsher }
2091f7917c00SJeff Kirsher 
2092f7917c00SJeff Kirsher void t3_xgm_intr_enable(struct adapter *adapter, int idx)
2093f7917c00SJeff Kirsher {
2094f7917c00SJeff Kirsher 	struct port_info *pi = adap2pinfo(adapter, idx);
2095f7917c00SJeff Kirsher 
2096f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset,
2097f7917c00SJeff Kirsher 		     XGM_EXTRA_INTR_MASK);
2098f7917c00SJeff Kirsher }
2099f7917c00SJeff Kirsher 
2100f7917c00SJeff Kirsher void t3_xgm_intr_disable(struct adapter *adapter, int idx)
2101f7917c00SJeff Kirsher {
2102f7917c00SJeff Kirsher 	struct port_info *pi = adap2pinfo(adapter, idx);
2103f7917c00SJeff Kirsher 
2104f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset,
2105f7917c00SJeff Kirsher 		     0x7ff);
2106f7917c00SJeff Kirsher }
2107f7917c00SJeff Kirsher 
2108f7917c00SJeff Kirsher /**
2109f7917c00SJeff Kirsher  *	t3_port_intr_enable - enable port-specific interrupts
2110f7917c00SJeff Kirsher  *	@adapter: associated adapter
2111f7917c00SJeff Kirsher  *	@idx: index of port whose interrupts should be enabled
2112f7917c00SJeff Kirsher  *
2113f7917c00SJeff Kirsher  *	Enable port-specific (i.e., MAC and PHY) interrupts for the given
2114f7917c00SJeff Kirsher  *	adapter port.
2115f7917c00SJeff Kirsher  */
2116f7917c00SJeff Kirsher void t3_port_intr_enable(struct adapter *adapter, int idx)
2117f7917c00SJeff Kirsher {
2118f7917c00SJeff Kirsher 	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
2119f7917c00SJeff Kirsher 
2120f7917c00SJeff Kirsher 	t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
2121f7917c00SJeff Kirsher 	t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
2122f7917c00SJeff Kirsher 	phy->ops->intr_enable(phy);
2123f7917c00SJeff Kirsher }
2124f7917c00SJeff Kirsher 
2125f7917c00SJeff Kirsher /**
2126f7917c00SJeff Kirsher  *	t3_port_intr_disable - disable port-specific interrupts
2127f7917c00SJeff Kirsher  *	@adapter: associated adapter
2128f7917c00SJeff Kirsher  *	@idx: index of port whose interrupts should be disabled
2129f7917c00SJeff Kirsher  *
2130f7917c00SJeff Kirsher  *	Disable port-specific (i.e., MAC and PHY) interrupts for the given
2131f7917c00SJeff Kirsher  *	adapter port.
2132f7917c00SJeff Kirsher  */
2133f7917c00SJeff Kirsher void t3_port_intr_disable(struct adapter *adapter, int idx)
2134f7917c00SJeff Kirsher {
2135f7917c00SJeff Kirsher 	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
2136f7917c00SJeff Kirsher 
2137f7917c00SJeff Kirsher 	t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
2138f7917c00SJeff Kirsher 	t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
2139f7917c00SJeff Kirsher 	phy->ops->intr_disable(phy);
2140f7917c00SJeff Kirsher }
2141f7917c00SJeff Kirsher 
2142f7917c00SJeff Kirsher /**
2143f7917c00SJeff Kirsher  *	t3_port_intr_clear - clear port-specific interrupts
2144f7917c00SJeff Kirsher  *	@adapter: associated adapter
2145f7917c00SJeff Kirsher  *	@idx: index of port whose interrupts to clear
2146f7917c00SJeff Kirsher  *
2147f7917c00SJeff Kirsher  *	Clear port-specific (i.e., MAC and PHY) interrupts for the given
2148f7917c00SJeff Kirsher  *	adapter port.
2149f7917c00SJeff Kirsher  */
2150f7917c00SJeff Kirsher static void t3_port_intr_clear(struct adapter *adapter, int idx)
2151f7917c00SJeff Kirsher {
2152f7917c00SJeff Kirsher 	struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
2153f7917c00SJeff Kirsher 
2154f7917c00SJeff Kirsher 	t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
2155f7917c00SJeff Kirsher 	t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
2156f7917c00SJeff Kirsher 	phy->ops->intr_clear(phy);
2157f7917c00SJeff Kirsher }
2158f7917c00SJeff Kirsher 
2159f7917c00SJeff Kirsher #define SG_CONTEXT_CMD_ATTEMPTS 100
2160f7917c00SJeff Kirsher 
2161f7917c00SJeff Kirsher /**
2162f7917c00SJeff Kirsher  * 	t3_sge_write_context - write an SGE context
2163f7917c00SJeff Kirsher  * 	@adapter: the adapter
2164f7917c00SJeff Kirsher  * 	@id: the context id
2165f7917c00SJeff Kirsher  * 	@type: the context type
2166f7917c00SJeff Kirsher  *
2167f7917c00SJeff Kirsher  * 	Program an SGE context with the values already loaded in the
2168f7917c00SJeff Kirsher  * 	CONTEXT_DATA? registers.
2169f7917c00SJeff Kirsher  */
2170f7917c00SJeff Kirsher static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
2171f7917c00SJeff Kirsher 				unsigned int type)
2172f7917c00SJeff Kirsher {
2173f7917c00SJeff Kirsher 	if (type == F_RESPONSEQ) {
2174f7917c00SJeff Kirsher 		/*
2175f7917c00SJeff Kirsher 		 * Can't write the Response Queue Context bits for
2176f7917c00SJeff Kirsher 		 * Interrupt Armed or the Reserve bits after the chip
2177f7917c00SJeff Kirsher 		 * has been initialized out of reset.  Writing to these
2178f7917c00SJeff Kirsher 		 * bits can confuse the hardware.
2179f7917c00SJeff Kirsher 		 */
2180f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
2181f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
2182f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff);
2183f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
2184f7917c00SJeff Kirsher 	} else {
2185f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
2186f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
2187f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
2188f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
2189f7917c00SJeff Kirsher 	}
2190f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2191f7917c00SJeff Kirsher 		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
2192f7917c00SJeff Kirsher 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2193f7917c00SJeff Kirsher 			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2194f7917c00SJeff Kirsher }
2195f7917c00SJeff Kirsher 
2196f7917c00SJeff Kirsher /**
2197f7917c00SJeff Kirsher  *	clear_sge_ctxt - completely clear an SGE context
219845677bc6SWang Hai  *	@adap: the adapter
2199f7917c00SJeff Kirsher  *	@id: the context id
2200f7917c00SJeff Kirsher  *	@type: the context type
2201f7917c00SJeff Kirsher  *
2202f7917c00SJeff Kirsher  *	Completely clear an SGE context.  Used predominantly at post-reset
2203f7917c00SJeff Kirsher  *	initialization.  Note in particular that we don't skip writing to any
2204f7917c00SJeff Kirsher  *	"sensitive bits" in the contexts the way that t3_sge_write_context()
2205f7917c00SJeff Kirsher  *	does ...
2206f7917c00SJeff Kirsher  */
2207f7917c00SJeff Kirsher static int clear_sge_ctxt(struct adapter *adap, unsigned int id,
2208f7917c00SJeff Kirsher 			  unsigned int type)
2209f7917c00SJeff Kirsher {
2210f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0);
2211f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0);
2212f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0);
2213f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0);
2214f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff);
2215f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff);
2216f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff);
2217f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff);
2218f7917c00SJeff Kirsher 	t3_write_reg(adap, A_SG_CONTEXT_CMD,
2219f7917c00SJeff Kirsher 		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
2220f7917c00SJeff Kirsher 	return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2221f7917c00SJeff Kirsher 			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2222f7917c00SJeff Kirsher }
2223f7917c00SJeff Kirsher 
2224f7917c00SJeff Kirsher /**
2225f7917c00SJeff Kirsher  *	t3_sge_init_ecntxt - initialize an SGE egress context
2226f7917c00SJeff Kirsher  *	@adapter: the adapter to configure
2227f7917c00SJeff Kirsher  *	@id: the context id
2228f7917c00SJeff Kirsher  *	@gts_enable: whether to enable GTS for the context
2229f7917c00SJeff Kirsher  *	@type: the egress context type
2230f7917c00SJeff Kirsher  *	@respq: associated response queue
2231f7917c00SJeff Kirsher  *	@base_addr: base address of queue
2232f7917c00SJeff Kirsher  *	@size: number of queue entries
2233f7917c00SJeff Kirsher  *	@token: uP token
2234f7917c00SJeff Kirsher  *	@gen: initial generation value for the context
2235f7917c00SJeff Kirsher  *	@cidx: consumer pointer
2236f7917c00SJeff Kirsher  *
2237f7917c00SJeff Kirsher  *	Initialize an SGE egress context and make it ready for use.  If the
2238f7917c00SJeff Kirsher  *	platform allows concurrent context operations, the caller is
2239f7917c00SJeff Kirsher  *	responsible for appropriate locking.
2240f7917c00SJeff Kirsher  */
2241f7917c00SJeff Kirsher int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
2242f7917c00SJeff Kirsher 		       enum sge_context_type type, int respq, u64 base_addr,
2243f7917c00SJeff Kirsher 		       unsigned int size, unsigned int token, int gen,
2244f7917c00SJeff Kirsher 		       unsigned int cidx)
2245f7917c00SJeff Kirsher {
2246f7917c00SJeff Kirsher 	unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
2247f7917c00SJeff Kirsher 
2248f7917c00SJeff Kirsher 	if (base_addr & 0xfff)	/* must be 4K aligned */
2249f7917c00SJeff Kirsher 		return -EINVAL;
2250f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2251f7917c00SJeff Kirsher 		return -EBUSY;
2252f7917c00SJeff Kirsher 
2253f7917c00SJeff Kirsher 	base_addr >>= 12;
2254f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
2255f7917c00SJeff Kirsher 		     V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
2256f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
2257f7917c00SJeff Kirsher 		     V_EC_BASE_LO(base_addr & 0xffff));
2258f7917c00SJeff Kirsher 	base_addr >>= 16;
2259f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
2260f7917c00SJeff Kirsher 	base_addr >>= 32;
2261f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2262f7917c00SJeff Kirsher 		     V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
2263f7917c00SJeff Kirsher 		     V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
2264f7917c00SJeff Kirsher 		     F_EC_VALID);
2265f7917c00SJeff Kirsher 	return t3_sge_write_context(adapter, id, F_EGRESS);
2266f7917c00SJeff Kirsher }
2267f7917c00SJeff Kirsher 
2268f7917c00SJeff Kirsher /**
2269f7917c00SJeff Kirsher  *	t3_sge_init_flcntxt - initialize an SGE free-buffer list context
2270f7917c00SJeff Kirsher  *	@adapter: the adapter to configure
2271f7917c00SJeff Kirsher  *	@id: the context id
2272f7917c00SJeff Kirsher  *	@gts_enable: whether to enable GTS for the context
2273f7917c00SJeff Kirsher  *	@base_addr: base address of queue
2274f7917c00SJeff Kirsher  *	@size: number of queue entries
2275f7917c00SJeff Kirsher  *	@bsize: size of each buffer for this queue
2276f7917c00SJeff Kirsher  *	@cong_thres: threshold to signal congestion to upstream producers
2277f7917c00SJeff Kirsher  *	@gen: initial generation value for the context
2278f7917c00SJeff Kirsher  *	@cidx: consumer pointer
2279f7917c00SJeff Kirsher  *
2280f7917c00SJeff Kirsher  *	Initialize an SGE free list context and make it ready for use.  The
2281f7917c00SJeff Kirsher  *	caller is responsible for ensuring only one context operation occurs
2282f7917c00SJeff Kirsher  *	at a time.
2283f7917c00SJeff Kirsher  */
2284f7917c00SJeff Kirsher int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
2285f7917c00SJeff Kirsher 			int gts_enable, u64 base_addr, unsigned int size,
2286f7917c00SJeff Kirsher 			unsigned int bsize, unsigned int cong_thres, int gen,
2287f7917c00SJeff Kirsher 			unsigned int cidx)
2288f7917c00SJeff Kirsher {
2289f7917c00SJeff Kirsher 	if (base_addr & 0xfff)	/* must be 4K aligned */
2290f7917c00SJeff Kirsher 		return -EINVAL;
2291f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2292f7917c00SJeff Kirsher 		return -EBUSY;
2293f7917c00SJeff Kirsher 
2294f7917c00SJeff Kirsher 	base_addr >>= 12;
2295f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
2296f7917c00SJeff Kirsher 	base_addr >>= 32;
2297f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
2298f7917c00SJeff Kirsher 		     V_FL_BASE_HI((u32) base_addr) |
2299f7917c00SJeff Kirsher 		     V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
2300f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
2301f7917c00SJeff Kirsher 		     V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
2302f7917c00SJeff Kirsher 		     V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
2303f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2304f7917c00SJeff Kirsher 		     V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
2305f7917c00SJeff Kirsher 		     V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
2306f7917c00SJeff Kirsher 	return t3_sge_write_context(adapter, id, F_FREELIST);
2307f7917c00SJeff Kirsher }
2308f7917c00SJeff Kirsher 
2309f7917c00SJeff Kirsher /**
2310f7917c00SJeff Kirsher  *	t3_sge_init_rspcntxt - initialize an SGE response queue context
2311f7917c00SJeff Kirsher  *	@adapter: the adapter to configure
2312f7917c00SJeff Kirsher  *	@id: the context id
2313f7917c00SJeff Kirsher  *	@irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
2314f7917c00SJeff Kirsher  *	@base_addr: base address of queue
2315f7917c00SJeff Kirsher  *	@size: number of queue entries
2316f7917c00SJeff Kirsher  *	@fl_thres: threshold for selecting the normal or jumbo free list
2317f7917c00SJeff Kirsher  *	@gen: initial generation value for the context
2318f7917c00SJeff Kirsher  *	@cidx: consumer pointer
2319f7917c00SJeff Kirsher  *
2320f7917c00SJeff Kirsher  *	Initialize an SGE response queue context and make it ready for use.
2321f7917c00SJeff Kirsher  *	The caller is responsible for ensuring only one context operation
2322f7917c00SJeff Kirsher  *	occurs at a time.
2323f7917c00SJeff Kirsher  */
2324f7917c00SJeff Kirsher int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
2325f7917c00SJeff Kirsher 			 int irq_vec_idx, u64 base_addr, unsigned int size,
2326f7917c00SJeff Kirsher 			 unsigned int fl_thres, int gen, unsigned int cidx)
2327f7917c00SJeff Kirsher {
2328f7917c00SJeff Kirsher 	unsigned int intr = 0;
2329f7917c00SJeff Kirsher 
2330f7917c00SJeff Kirsher 	if (base_addr & 0xfff)	/* must be 4K aligned */
2331f7917c00SJeff Kirsher 		return -EINVAL;
2332f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2333f7917c00SJeff Kirsher 		return -EBUSY;
2334f7917c00SJeff Kirsher 
2335f7917c00SJeff Kirsher 	base_addr >>= 12;
2336f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
2337f7917c00SJeff Kirsher 		     V_CQ_INDEX(cidx));
2338f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
2339f7917c00SJeff Kirsher 	base_addr >>= 32;
2340f7917c00SJeff Kirsher 	if (irq_vec_idx >= 0)
2341f7917c00SJeff Kirsher 		intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
2342f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2343f7917c00SJeff Kirsher 		     V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
2344f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
2345f7917c00SJeff Kirsher 	return t3_sge_write_context(adapter, id, F_RESPONSEQ);
2346f7917c00SJeff Kirsher }
2347f7917c00SJeff Kirsher 
2348f7917c00SJeff Kirsher /**
2349f7917c00SJeff Kirsher  *	t3_sge_init_cqcntxt - initialize an SGE completion queue context
2350f7917c00SJeff Kirsher  *	@adapter: the adapter to configure
2351f7917c00SJeff Kirsher  *	@id: the context id
2352f7917c00SJeff Kirsher  *	@base_addr: base address of queue
2353f7917c00SJeff Kirsher  *	@size: number of queue entries
2354f7917c00SJeff Kirsher  *	@rspq: response queue for async notifications
2355f7917c00SJeff Kirsher  *	@ovfl_mode: CQ overflow mode
2356f7917c00SJeff Kirsher  *	@credits: completion queue credits
2357f7917c00SJeff Kirsher  *	@credit_thres: the credit threshold
2358f7917c00SJeff Kirsher  *
2359f7917c00SJeff Kirsher  *	Initialize an SGE completion queue context and make it ready for use.
2360f7917c00SJeff Kirsher  *	The caller is responsible for ensuring only one context operation
2361f7917c00SJeff Kirsher  *	occurs at a time.
2362f7917c00SJeff Kirsher  */
2363f7917c00SJeff Kirsher int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
2364f7917c00SJeff Kirsher 			unsigned int size, int rspq, int ovfl_mode,
2365f7917c00SJeff Kirsher 			unsigned int credits, unsigned int credit_thres)
2366f7917c00SJeff Kirsher {
2367f7917c00SJeff Kirsher 	if (base_addr & 0xfff)	/* must be 4K aligned */
2368f7917c00SJeff Kirsher 		return -EINVAL;
2369f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2370f7917c00SJeff Kirsher 		return -EBUSY;
2371f7917c00SJeff Kirsher 
2372f7917c00SJeff Kirsher 	base_addr >>= 12;
2373f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
2374f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
2375f7917c00SJeff Kirsher 	base_addr >>= 32;
2376f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2377f7917c00SJeff Kirsher 		     V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
2378f7917c00SJeff Kirsher 		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
2379f7917c00SJeff Kirsher 		     V_CQ_ERR(ovfl_mode));
2380f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
2381f7917c00SJeff Kirsher 		     V_CQ_CREDIT_THRES(credit_thres));
2382f7917c00SJeff Kirsher 	return t3_sge_write_context(adapter, id, F_CQ);
2383f7917c00SJeff Kirsher }
2384f7917c00SJeff Kirsher 
2385f7917c00SJeff Kirsher /**
2386f7917c00SJeff Kirsher  *	t3_sge_enable_ecntxt - enable/disable an SGE egress context
2387f7917c00SJeff Kirsher  *	@adapter: the adapter
2388f7917c00SJeff Kirsher  *	@id: the egress context id
2389f7917c00SJeff Kirsher  *	@enable: enable (1) or disable (0) the context
2390f7917c00SJeff Kirsher  *
2391f7917c00SJeff Kirsher  *	Enable or disable an SGE egress context.  The caller is responsible for
2392f7917c00SJeff Kirsher  *	ensuring only one context operation occurs at a time.
2393f7917c00SJeff Kirsher  */
2394f7917c00SJeff Kirsher int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
2395f7917c00SJeff Kirsher {
2396f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2397f7917c00SJeff Kirsher 		return -EBUSY;
2398f7917c00SJeff Kirsher 
2399f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2400f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2401f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2402f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
2403f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
2404f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2405f7917c00SJeff Kirsher 		     V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
2406f7917c00SJeff Kirsher 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2407f7917c00SJeff Kirsher 			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2408f7917c00SJeff Kirsher }
2409f7917c00SJeff Kirsher 
2410f7917c00SJeff Kirsher /**
2411f7917c00SJeff Kirsher  *	t3_sge_disable_fl - disable an SGE free-buffer list
2412f7917c00SJeff Kirsher  *	@adapter: the adapter
2413f7917c00SJeff Kirsher  *	@id: the free list context id
2414f7917c00SJeff Kirsher  *
2415f7917c00SJeff Kirsher  *	Disable an SGE free-buffer list.  The caller is responsible for
2416f7917c00SJeff Kirsher  *	ensuring only one context operation occurs at a time.
2417f7917c00SJeff Kirsher  */
2418f7917c00SJeff Kirsher int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
2419f7917c00SJeff Kirsher {
2420f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2421f7917c00SJeff Kirsher 		return -EBUSY;
2422f7917c00SJeff Kirsher 
2423f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2424f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2425f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
2426f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2427f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
2428f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2429f7917c00SJeff Kirsher 		     V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
2430f7917c00SJeff Kirsher 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2431f7917c00SJeff Kirsher 			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2432f7917c00SJeff Kirsher }
2433f7917c00SJeff Kirsher 
2434f7917c00SJeff Kirsher /**
2435f7917c00SJeff Kirsher  *	t3_sge_disable_rspcntxt - disable an SGE response queue
2436f7917c00SJeff Kirsher  *	@adapter: the adapter
2437f7917c00SJeff Kirsher  *	@id: the response queue context id
2438f7917c00SJeff Kirsher  *
2439f7917c00SJeff Kirsher  *	Disable an SGE response queue.  The caller is responsible for
2440f7917c00SJeff Kirsher  *	ensuring only one context operation occurs at a time.
2441f7917c00SJeff Kirsher  */
2442f7917c00SJeff Kirsher int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
2443f7917c00SJeff Kirsher {
2444f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2445f7917c00SJeff Kirsher 		return -EBUSY;
2446f7917c00SJeff Kirsher 
2447f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2448f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2449f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2450f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2451f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2452f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2453f7917c00SJeff Kirsher 		     V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
2454f7917c00SJeff Kirsher 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2455f7917c00SJeff Kirsher 			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2456f7917c00SJeff Kirsher }
2457f7917c00SJeff Kirsher 
2458f7917c00SJeff Kirsher /**
2459f7917c00SJeff Kirsher  *	t3_sge_disable_cqcntxt - disable an SGE completion queue
2460f7917c00SJeff Kirsher  *	@adapter: the adapter
2461f7917c00SJeff Kirsher  *	@id: the completion queue context id
2462f7917c00SJeff Kirsher  *
2463f7917c00SJeff Kirsher  *	Disable an SGE completion queue.  The caller is responsible for
2464f7917c00SJeff Kirsher  *	ensuring only one context operation occurs at a time.
2465f7917c00SJeff Kirsher  */
2466f7917c00SJeff Kirsher int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
2467f7917c00SJeff Kirsher {
2468f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2469f7917c00SJeff Kirsher 		return -EBUSY;
2470f7917c00SJeff Kirsher 
2471f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2472f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2473f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2474f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2475f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2476f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2477f7917c00SJeff Kirsher 		     V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
2478f7917c00SJeff Kirsher 	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2479f7917c00SJeff Kirsher 			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2480f7917c00SJeff Kirsher }
2481f7917c00SJeff Kirsher 
2482f7917c00SJeff Kirsher /**
2483f7917c00SJeff Kirsher  *	t3_sge_cqcntxt_op - perform an operation on a completion queue context
2484f7917c00SJeff Kirsher  *	@adapter: the adapter
2485f7917c00SJeff Kirsher  *	@id: the context id
2486f7917c00SJeff Kirsher  *	@op: the operation to perform
2487d0ea5cbdSJesse Brandeburg  *	@credits: credit value to write
2488f7917c00SJeff Kirsher  *
2489f7917c00SJeff Kirsher  *	Perform the selected operation on an SGE completion queue context.
2490f7917c00SJeff Kirsher  *	The caller is responsible for ensuring only one context operation
2491f7917c00SJeff Kirsher  *	occurs at a time.
2492f7917c00SJeff Kirsher  */
2493f7917c00SJeff Kirsher int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
2494f7917c00SJeff Kirsher 		      unsigned int credits)
2495f7917c00SJeff Kirsher {
2496f7917c00SJeff Kirsher 	u32 val;
2497f7917c00SJeff Kirsher 
2498f7917c00SJeff Kirsher 	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2499f7917c00SJeff Kirsher 		return -EBUSY;
2500f7917c00SJeff Kirsher 
2501f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
2502f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
2503f7917c00SJeff Kirsher 		     V_CONTEXT(id) | F_CQ);
2504f7917c00SJeff Kirsher 	if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2505f7917c00SJeff Kirsher 				0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
2506f7917c00SJeff Kirsher 		return -EIO;
2507f7917c00SJeff Kirsher 
2508f7917c00SJeff Kirsher 	if (op >= 2 && op < 7) {
2509f7917c00SJeff Kirsher 		if (adapter->params.rev > 0)
2510f7917c00SJeff Kirsher 			return G_CQ_INDEX(val);
2511f7917c00SJeff Kirsher 
2512f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2513f7917c00SJeff Kirsher 			     V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
2514f7917c00SJeff Kirsher 		if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
2515f7917c00SJeff Kirsher 				    F_CONTEXT_CMD_BUSY, 0,
2516f7917c00SJeff Kirsher 				    SG_CONTEXT_CMD_ATTEMPTS, 1))
2517f7917c00SJeff Kirsher 			return -EIO;
2518f7917c00SJeff Kirsher 		return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
2519f7917c00SJeff Kirsher 	}
2520f7917c00SJeff Kirsher 	return 0;
2521f7917c00SJeff Kirsher }
2522f7917c00SJeff Kirsher 
2523f7917c00SJeff Kirsher /**
2524f7917c00SJeff Kirsher  *	t3_config_rss - configure Rx packet steering
2525f7917c00SJeff Kirsher  *	@adapter: the adapter
2526f7917c00SJeff Kirsher  *	@rss_config: RSS settings (written to TP_RSS_CONFIG)
2527f7917c00SJeff Kirsher  *	@cpus: values for the CPU lookup table (0xff terminated)
2528f7917c00SJeff Kirsher  *	@rspq: values for the response queue lookup table (0xffff terminated)
2529f7917c00SJeff Kirsher  *
2530f7917c00SJeff Kirsher  *	Programs the receive packet steering logic.  @cpus and @rspq provide
2531f7917c00SJeff Kirsher  *	the values for the CPU and response queue lookup tables.  If they
2532f7917c00SJeff Kirsher  *	provide fewer values than the size of the tables the supplied values
2533f7917c00SJeff Kirsher  *	are used repeatedly until the tables are fully populated.
2534f7917c00SJeff Kirsher  */
2535f7917c00SJeff Kirsher void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
2536f7917c00SJeff Kirsher 		   const u8 * cpus, const u16 *rspq)
2537f7917c00SJeff Kirsher {
2538f7917c00SJeff Kirsher 	int i, j, cpu_idx = 0, q_idx = 0;
2539f7917c00SJeff Kirsher 
2540f7917c00SJeff Kirsher 	if (cpus)
2541f7917c00SJeff Kirsher 		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2542f7917c00SJeff Kirsher 			u32 val = i << 16;
2543f7917c00SJeff Kirsher 
2544f7917c00SJeff Kirsher 			for (j = 0; j < 2; ++j) {
2545f7917c00SJeff Kirsher 				val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
2546f7917c00SJeff Kirsher 				if (cpus[cpu_idx] == 0xff)
2547f7917c00SJeff Kirsher 					cpu_idx = 0;
2548f7917c00SJeff Kirsher 			}
2549f7917c00SJeff Kirsher 			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
2550f7917c00SJeff Kirsher 		}
2551f7917c00SJeff Kirsher 
2552f7917c00SJeff Kirsher 	if (rspq)
2553f7917c00SJeff Kirsher 		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2554f7917c00SJeff Kirsher 			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
2555f7917c00SJeff Kirsher 				     (i << 16) | rspq[q_idx++]);
2556f7917c00SJeff Kirsher 			if (rspq[q_idx] == 0xffff)
2557f7917c00SJeff Kirsher 				q_idx = 0;
2558f7917c00SJeff Kirsher 		}
2559f7917c00SJeff Kirsher 
2560f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
2561f7917c00SJeff Kirsher }
2562f7917c00SJeff Kirsher 
2563f7917c00SJeff Kirsher /**
2564f7917c00SJeff Kirsher  *	t3_tp_set_offload_mode - put TP in NIC/offload mode
2565f7917c00SJeff Kirsher  *	@adap: the adapter
2566f7917c00SJeff Kirsher  *	@enable: 1 to select offload mode, 0 for regular NIC
2567f7917c00SJeff Kirsher  *
2568f7917c00SJeff Kirsher  *	Switches TP to NIC/offload mode.
2569f7917c00SJeff Kirsher  */
2570f7917c00SJeff Kirsher void t3_tp_set_offload_mode(struct adapter *adap, int enable)
2571f7917c00SJeff Kirsher {
2572f7917c00SJeff Kirsher 	if (is_offload(adap) || !enable)
2573f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
2574f7917c00SJeff Kirsher 				 V_NICMODE(!enable));
2575f7917c00SJeff Kirsher }
2576f7917c00SJeff Kirsher 
2577f7917c00SJeff Kirsher /**
2578f7917c00SJeff Kirsher  *	pm_num_pages - calculate the number of pages of the payload memory
2579f7917c00SJeff Kirsher  *	@mem_size: the size of the payload memory
2580f7917c00SJeff Kirsher  *	@pg_size: the size of each payload memory page
2581f7917c00SJeff Kirsher  *
2582f7917c00SJeff Kirsher  *	Calculate the number of pages, each of the given size, that fit in a
2583f7917c00SJeff Kirsher  *	memory of the specified size, respecting the HW requirement that the
2584f7917c00SJeff Kirsher  *	number of pages must be a multiple of 24.
2585f7917c00SJeff Kirsher  */
2586f7917c00SJeff Kirsher static inline unsigned int pm_num_pages(unsigned int mem_size,
2587f7917c00SJeff Kirsher 					unsigned int pg_size)
2588f7917c00SJeff Kirsher {
2589f7917c00SJeff Kirsher 	unsigned int n = mem_size / pg_size;
2590f7917c00SJeff Kirsher 
2591f7917c00SJeff Kirsher 	return n - n % 24;
2592f7917c00SJeff Kirsher }
2593f7917c00SJeff Kirsher 
2594f7917c00SJeff Kirsher #define mem_region(adap, start, size, reg) \
2595f7917c00SJeff Kirsher 	t3_write_reg((adap), A_ ## reg, (start)); \
2596f7917c00SJeff Kirsher 	start += size
2597f7917c00SJeff Kirsher 
2598f7917c00SJeff Kirsher /**
2599f7917c00SJeff Kirsher  *	partition_mem - partition memory and configure TP memory settings
2600f7917c00SJeff Kirsher  *	@adap: the adapter
2601f7917c00SJeff Kirsher  *	@p: the TP parameters
2602f7917c00SJeff Kirsher  *
2603f7917c00SJeff Kirsher  *	Partitions context and payload memory and configures TP's memory
2604f7917c00SJeff Kirsher  *	registers.
2605f7917c00SJeff Kirsher  */
2606f7917c00SJeff Kirsher static void partition_mem(struct adapter *adap, const struct tp_params *p)
2607f7917c00SJeff Kirsher {
2608f7917c00SJeff Kirsher 	unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
2609f7917c00SJeff Kirsher 	unsigned int timers = 0, timers_shift = 22;
2610f7917c00SJeff Kirsher 
2611f7917c00SJeff Kirsher 	if (adap->params.rev > 0) {
2612f7917c00SJeff Kirsher 		if (tids <= 16 * 1024) {
2613f7917c00SJeff Kirsher 			timers = 1;
2614f7917c00SJeff Kirsher 			timers_shift = 16;
2615f7917c00SJeff Kirsher 		} else if (tids <= 64 * 1024) {
2616f7917c00SJeff Kirsher 			timers = 2;
2617f7917c00SJeff Kirsher 			timers_shift = 18;
2618f7917c00SJeff Kirsher 		} else if (tids <= 256 * 1024) {
2619f7917c00SJeff Kirsher 			timers = 3;
2620f7917c00SJeff Kirsher 			timers_shift = 20;
2621f7917c00SJeff Kirsher 		}
2622f7917c00SJeff Kirsher 	}
2623f7917c00SJeff Kirsher 
2624f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PMM_SIZE,
2625f7917c00SJeff Kirsher 		     p->chan_rx_size | (p->chan_tx_size >> 16));
2626f7917c00SJeff Kirsher 
2627f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
2628f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
2629f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
2630f7917c00SJeff Kirsher 	t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
2631f7917c00SJeff Kirsher 			 V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
2632f7917c00SJeff Kirsher 
2633f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
2634f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
2635f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
2636f7917c00SJeff Kirsher 
2637f7917c00SJeff Kirsher 	pstructs = p->rx_num_pgs + p->tx_num_pgs;
2638f7917c00SJeff Kirsher 	/* Add a bit of headroom and make multiple of 24 */
2639f7917c00SJeff Kirsher 	pstructs += 48;
2640f7917c00SJeff Kirsher 	pstructs -= pstructs % 24;
2641f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
2642f7917c00SJeff Kirsher 
2643f7917c00SJeff Kirsher 	m = tids * TCB_SIZE;
2644f7917c00SJeff Kirsher 	mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
2645f7917c00SJeff Kirsher 	mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
2646f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
2647f7917c00SJeff Kirsher 	m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
2648f7917c00SJeff Kirsher 	mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
2649f7917c00SJeff Kirsher 	mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
2650f7917c00SJeff Kirsher 	mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
2651f7917c00SJeff Kirsher 	mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
2652f7917c00SJeff Kirsher 
2653f7917c00SJeff Kirsher 	m = (m + 4095) & ~0xfff;
2654f7917c00SJeff Kirsher 	t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
2655f7917c00SJeff Kirsher 	t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
2656f7917c00SJeff Kirsher 
2657f7917c00SJeff Kirsher 	tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
2658f7917c00SJeff Kirsher 	m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
2659f7917c00SJeff Kirsher 	    adap->params.mc5.nfilters - adap->params.mc5.nroutes;
2660f7917c00SJeff Kirsher 	if (tids < m)
2661f7917c00SJeff Kirsher 		adap->params.mc5.nservers += m - tids;
2662f7917c00SJeff Kirsher }
2663f7917c00SJeff Kirsher 
2664f7917c00SJeff Kirsher static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
2665f7917c00SJeff Kirsher 				  u32 val)
2666f7917c00SJeff Kirsher {
2667f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
2668f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PIO_DATA, val);
2669f7917c00SJeff Kirsher }
2670f7917c00SJeff Kirsher 
2671f7917c00SJeff Kirsher static void tp_config(struct adapter *adap, const struct tp_params *p)
2672f7917c00SJeff Kirsher {
2673f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
2674f7917c00SJeff Kirsher 		     F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
2675f7917c00SJeff Kirsher 		     F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
2676f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
2677f7917c00SJeff Kirsher 		     F_MTUENABLE | V_WINDOWSCALEMODE(1) |
2678f7917c00SJeff Kirsher 		     V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
2679f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
2680f7917c00SJeff Kirsher 		     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
2681f7917c00SJeff Kirsher 		     V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) |
2682f7917c00SJeff Kirsher 		     F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
2683f7917c00SJeff Kirsher 	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO,
2684f7917c00SJeff Kirsher 			 F_IPV6ENABLE | F_NICMODE);
2685f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
2686f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
2687f7917c00SJeff Kirsher 	t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
2688f7917c00SJeff Kirsher 			 adap->params.rev > 0 ? F_ENABLEESND :
2689f7917c00SJeff Kirsher 			 F_T3A_ENABLEESND);
2690f7917c00SJeff Kirsher 
2691f7917c00SJeff Kirsher 	t3_set_reg_field(adap, A_TP_PC_CONFIG,
2692f7917c00SJeff Kirsher 			 F_ENABLEEPCMDAFULL,
2693f7917c00SJeff Kirsher 			 F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
2694f7917c00SJeff Kirsher 			 F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
2695f7917c00SJeff Kirsher 	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL,
2696f7917c00SJeff Kirsher 			 F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN |
2697f7917c00SJeff Kirsher 			 F_ENABLEARPMISS | F_DISBLEDAPARBIT0);
2698f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
2699f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
2700f7917c00SJeff Kirsher 
2701f7917c00SJeff Kirsher 	if (adap->params.rev > 0) {
2702f7917c00SJeff Kirsher 		tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
2703f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
2704f7917c00SJeff Kirsher 				 F_TXPACEAUTO);
2705f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
2706f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
2707f7917c00SJeff Kirsher 	} else
2708f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
2709f7917c00SJeff Kirsher 
2710f7917c00SJeff Kirsher 	if (adap->params.rev == T3_REV_C)
2711f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_TP_PC_CONFIG,
2712f7917c00SJeff Kirsher 				 V_TABLELATENCYDELTA(M_TABLELATENCYDELTA),
2713f7917c00SJeff Kirsher 				 V_TABLELATENCYDELTA(4));
2714f7917c00SJeff Kirsher 
2715f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
2716f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
2717f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
2718f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
2719f7917c00SJeff Kirsher }
2720f7917c00SJeff Kirsher 
2721f7917c00SJeff Kirsher /* Desired TP timer resolution in usec */
2722f7917c00SJeff Kirsher #define TP_TMR_RES 50
2723f7917c00SJeff Kirsher 
2724f7917c00SJeff Kirsher /* TCP timer values in ms */
2725f7917c00SJeff Kirsher #define TP_DACK_TIMER 50
2726f7917c00SJeff Kirsher #define TP_RTO_MIN    250
2727f7917c00SJeff Kirsher 
2728f7917c00SJeff Kirsher /**
2729f7917c00SJeff Kirsher  *	tp_set_timers - set TP timing parameters
2730f7917c00SJeff Kirsher  *	@adap: the adapter to set
2731f7917c00SJeff Kirsher  *	@core_clk: the core clock frequency in Hz
2732f7917c00SJeff Kirsher  *
2733f7917c00SJeff Kirsher  *	Set TP's timing parameters, such as the various timer resolutions and
2734f7917c00SJeff Kirsher  *	the TCP timer values.
2735f7917c00SJeff Kirsher  */
2736f7917c00SJeff Kirsher static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
2737f7917c00SJeff Kirsher {
2738f7917c00SJeff Kirsher 	unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
2739f7917c00SJeff Kirsher 	unsigned int dack_re = fls(core_clk / 5000) - 1;	/* 200us */
2740f7917c00SJeff Kirsher 	unsigned int tstamp_re = fls(core_clk / 1000);	/* 1ms, at least */
2741f7917c00SJeff Kirsher 	unsigned int tps = core_clk >> tre;
2742f7917c00SJeff Kirsher 
2743f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
2744f7917c00SJeff Kirsher 		     V_DELAYEDACKRESOLUTION(dack_re) |
2745f7917c00SJeff Kirsher 		     V_TIMESTAMPRESOLUTION(tstamp_re));
2746f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_DACK_TIMER,
2747f7917c00SJeff Kirsher 		     (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
2748f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
2749f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
2750f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
2751f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
2752f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
2753f7917c00SJeff Kirsher 		     V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
2754f7917c00SJeff Kirsher 		     V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
2755f7917c00SJeff Kirsher 		     V_KEEPALIVEMAX(9));
2756f7917c00SJeff Kirsher 
2757f7917c00SJeff Kirsher #define SECONDS * tps
2758f7917c00SJeff Kirsher 
2759f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
2760f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
2761f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
2762f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
2763f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
2764f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
2765f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
2766f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
2767f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
2768f7917c00SJeff Kirsher 
2769f7917c00SJeff Kirsher #undef SECONDS
2770f7917c00SJeff Kirsher }
2771f7917c00SJeff Kirsher 
2772f7917c00SJeff Kirsher /**
2773f7917c00SJeff Kirsher  *	t3_tp_set_coalescing_size - set receive coalescing size
2774f7917c00SJeff Kirsher  *	@adap: the adapter
2775f7917c00SJeff Kirsher  *	@size: the receive coalescing size
2776f7917c00SJeff Kirsher  *	@psh: whether a set PSH bit should deliver coalesced data
2777f7917c00SJeff Kirsher  *
2778f7917c00SJeff Kirsher  *	Set the receive coalescing size and PSH bit handling.
2779f7917c00SJeff Kirsher  */
2780f7917c00SJeff Kirsher static int t3_tp_set_coalescing_size(struct adapter *adap,
2781f7917c00SJeff Kirsher 				     unsigned int size, int psh)
2782f7917c00SJeff Kirsher {
2783f7917c00SJeff Kirsher 	u32 val;
2784f7917c00SJeff Kirsher 
2785f7917c00SJeff Kirsher 	if (size > MAX_RX_COALESCING_LEN)
2786f7917c00SJeff Kirsher 		return -EINVAL;
2787f7917c00SJeff Kirsher 
2788f7917c00SJeff Kirsher 	val = t3_read_reg(adap, A_TP_PARA_REG3);
2789f7917c00SJeff Kirsher 	val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
2790f7917c00SJeff Kirsher 
2791f7917c00SJeff Kirsher 	if (size) {
2792f7917c00SJeff Kirsher 		val |= F_RXCOALESCEENABLE;
2793f7917c00SJeff Kirsher 		if (psh)
2794f7917c00SJeff Kirsher 			val |= F_RXCOALESCEPSHEN;
2795f7917c00SJeff Kirsher 		size = min(MAX_RX_COALESCING_LEN, size);
2796f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
2797f7917c00SJeff Kirsher 			     V_MAXRXDATA(MAX_RX_COALESCING_LEN));
2798f7917c00SJeff Kirsher 	}
2799f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PARA_REG3, val);
2800f7917c00SJeff Kirsher 	return 0;
2801f7917c00SJeff Kirsher }
2802f7917c00SJeff Kirsher 
2803f7917c00SJeff Kirsher /**
2804f7917c00SJeff Kirsher  *	t3_tp_set_max_rxsize - set the max receive size
2805f7917c00SJeff Kirsher  *	@adap: the adapter
2806f7917c00SJeff Kirsher  *	@size: the max receive size
2807f7917c00SJeff Kirsher  *
2808f7917c00SJeff Kirsher  *	Set TP's max receive size.  This is the limit that applies when
2809f7917c00SJeff Kirsher  *	receive coalescing is disabled.
2810f7917c00SJeff Kirsher  */
2811f7917c00SJeff Kirsher static void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
2812f7917c00SJeff Kirsher {
2813f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_PARA_REG7,
2814f7917c00SJeff Kirsher 		     V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
2815f7917c00SJeff Kirsher }
2816f7917c00SJeff Kirsher 
2817f7917c00SJeff Kirsher static void init_mtus(unsigned short mtus[])
2818f7917c00SJeff Kirsher {
2819f7917c00SJeff Kirsher 	/*
2820f7917c00SJeff Kirsher 	 * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
2821f7917c00SJeff Kirsher 	 * it can accommodate max size TCP/IP headers when SACK and timestamps
2822f7917c00SJeff Kirsher 	 * are enabled and still have at least 8 bytes of payload.
2823f7917c00SJeff Kirsher 	 */
2824f7917c00SJeff Kirsher 	mtus[0] = 88;
2825f7917c00SJeff Kirsher 	mtus[1] = 88;
2826f7917c00SJeff Kirsher 	mtus[2] = 256;
2827f7917c00SJeff Kirsher 	mtus[3] = 512;
2828f7917c00SJeff Kirsher 	mtus[4] = 576;
2829f7917c00SJeff Kirsher 	mtus[5] = 1024;
2830f7917c00SJeff Kirsher 	mtus[6] = 1280;
2831f7917c00SJeff Kirsher 	mtus[7] = 1492;
2832f7917c00SJeff Kirsher 	mtus[8] = 1500;
2833f7917c00SJeff Kirsher 	mtus[9] = 2002;
2834f7917c00SJeff Kirsher 	mtus[10] = 2048;
2835f7917c00SJeff Kirsher 	mtus[11] = 4096;
2836f7917c00SJeff Kirsher 	mtus[12] = 4352;
2837f7917c00SJeff Kirsher 	mtus[13] = 8192;
2838f7917c00SJeff Kirsher 	mtus[14] = 9000;
2839f7917c00SJeff Kirsher 	mtus[15] = 9600;
2840f7917c00SJeff Kirsher }
2841f7917c00SJeff Kirsher 
2842f7917c00SJeff Kirsher /*
2843f7917c00SJeff Kirsher  * Initial congestion control parameters.
2844f7917c00SJeff Kirsher  */
2845f7917c00SJeff Kirsher static void init_cong_ctrl(unsigned short *a, unsigned short *b)
2846f7917c00SJeff Kirsher {
2847f7917c00SJeff Kirsher 	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
2848f7917c00SJeff Kirsher 	a[9] = 2;
2849f7917c00SJeff Kirsher 	a[10] = 3;
2850f7917c00SJeff Kirsher 	a[11] = 4;
2851f7917c00SJeff Kirsher 	a[12] = 5;
2852f7917c00SJeff Kirsher 	a[13] = 6;
2853f7917c00SJeff Kirsher 	a[14] = 7;
2854f7917c00SJeff Kirsher 	a[15] = 8;
2855f7917c00SJeff Kirsher 	a[16] = 9;
2856f7917c00SJeff Kirsher 	a[17] = 10;
2857f7917c00SJeff Kirsher 	a[18] = 14;
2858f7917c00SJeff Kirsher 	a[19] = 17;
2859f7917c00SJeff Kirsher 	a[20] = 21;
2860f7917c00SJeff Kirsher 	a[21] = 25;
2861f7917c00SJeff Kirsher 	a[22] = 30;
2862f7917c00SJeff Kirsher 	a[23] = 35;
2863f7917c00SJeff Kirsher 	a[24] = 45;
2864f7917c00SJeff Kirsher 	a[25] = 60;
2865f7917c00SJeff Kirsher 	a[26] = 80;
2866f7917c00SJeff Kirsher 	a[27] = 100;
2867f7917c00SJeff Kirsher 	a[28] = 200;
2868f7917c00SJeff Kirsher 	a[29] = 300;
2869f7917c00SJeff Kirsher 	a[30] = 400;
2870f7917c00SJeff Kirsher 	a[31] = 500;
2871f7917c00SJeff Kirsher 
2872f7917c00SJeff Kirsher 	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
2873f7917c00SJeff Kirsher 	b[9] = b[10] = 1;
2874f7917c00SJeff Kirsher 	b[11] = b[12] = 2;
2875f7917c00SJeff Kirsher 	b[13] = b[14] = b[15] = b[16] = 3;
2876f7917c00SJeff Kirsher 	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
2877f7917c00SJeff Kirsher 	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
2878f7917c00SJeff Kirsher 	b[28] = b[29] = 6;
2879f7917c00SJeff Kirsher 	b[30] = b[31] = 7;
2880f7917c00SJeff Kirsher }
2881f7917c00SJeff Kirsher 
2882f7917c00SJeff Kirsher /* The minimum additive increment value for the congestion control table */
2883f7917c00SJeff Kirsher #define CC_MIN_INCR 2U
2884f7917c00SJeff Kirsher 
2885f7917c00SJeff Kirsher /**
2886f7917c00SJeff Kirsher  *	t3_load_mtus - write the MTU and congestion control HW tables
2887f7917c00SJeff Kirsher  *	@adap: the adapter
2888f7917c00SJeff Kirsher  *	@mtus: the unrestricted values for the MTU table
2889d0ea5cbdSJesse Brandeburg  *	@alpha: the values for the congestion control alpha parameter
2890f7917c00SJeff Kirsher  *	@beta: the values for the congestion control beta parameter
2891f7917c00SJeff Kirsher  *	@mtu_cap: the maximum permitted effective MTU
2892f7917c00SJeff Kirsher  *
2893f7917c00SJeff Kirsher  *	Write the MTU table with the supplied MTUs capping each at &mtu_cap.
2894f7917c00SJeff Kirsher  *	Update the high-speed congestion control table with the supplied alpha,
2895f7917c00SJeff Kirsher  * 	beta, and MTUs.
2896f7917c00SJeff Kirsher  */
2897f7917c00SJeff Kirsher void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
2898f7917c00SJeff Kirsher 		  unsigned short alpha[NCCTRL_WIN],
2899f7917c00SJeff Kirsher 		  unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
2900f7917c00SJeff Kirsher {
2901f7917c00SJeff Kirsher 	static const unsigned int avg_pkts[NCCTRL_WIN] = {
2902f7917c00SJeff Kirsher 		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
2903f7917c00SJeff Kirsher 		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
2904f7917c00SJeff Kirsher 		28672, 40960, 57344, 81920, 114688, 163840, 229376
2905f7917c00SJeff Kirsher 	};
2906f7917c00SJeff Kirsher 
2907f7917c00SJeff Kirsher 	unsigned int i, w;
2908f7917c00SJeff Kirsher 
2909f7917c00SJeff Kirsher 	for (i = 0; i < NMTUS; ++i) {
2910f7917c00SJeff Kirsher 		unsigned int mtu = min(mtus[i], mtu_cap);
2911f7917c00SJeff Kirsher 		unsigned int log2 = fls(mtu);
2912f7917c00SJeff Kirsher 
2913f7917c00SJeff Kirsher 		if (!(mtu & ((1 << log2) >> 2)))	/* round */
2914f7917c00SJeff Kirsher 			log2--;
2915f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_MTU_TABLE,
2916f7917c00SJeff Kirsher 			     (i << 24) | (log2 << 16) | mtu);
2917f7917c00SJeff Kirsher 
2918f7917c00SJeff Kirsher 		for (w = 0; w < NCCTRL_WIN; ++w) {
2919f7917c00SJeff Kirsher 			unsigned int inc;
2920f7917c00SJeff Kirsher 
2921f7917c00SJeff Kirsher 			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
2922f7917c00SJeff Kirsher 				  CC_MIN_INCR);
2923f7917c00SJeff Kirsher 
2924f7917c00SJeff Kirsher 			t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
2925f7917c00SJeff Kirsher 				     (w << 16) | (beta[w] << 13) | inc);
2926f7917c00SJeff Kirsher 		}
2927f7917c00SJeff Kirsher 	}
2928f7917c00SJeff Kirsher }
2929f7917c00SJeff Kirsher 
2930f7917c00SJeff Kirsher /**
2931f7917c00SJeff Kirsher  *	t3_tp_get_mib_stats - read TP's MIB counters
2932f7917c00SJeff Kirsher  *	@adap: the adapter
2933f7917c00SJeff Kirsher  *	@tps: holds the returned counter values
2934f7917c00SJeff Kirsher  *
2935f7917c00SJeff Kirsher  *	Returns the values of TP's MIB counters.
2936f7917c00SJeff Kirsher  */
2937f7917c00SJeff Kirsher void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
2938f7917c00SJeff Kirsher {
2939f7917c00SJeff Kirsher 	t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
2940f7917c00SJeff Kirsher 			 sizeof(*tps) / sizeof(u32), 0);
2941f7917c00SJeff Kirsher }
2942f7917c00SJeff Kirsher 
2943f7917c00SJeff Kirsher #define ulp_region(adap, name, start, len) \
2944f7917c00SJeff Kirsher 	t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
2945f7917c00SJeff Kirsher 	t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
2946f7917c00SJeff Kirsher 		     (start) + (len) - 1); \
2947f7917c00SJeff Kirsher 	start += len
2948f7917c00SJeff Kirsher 
2949f7917c00SJeff Kirsher #define ulptx_region(adap, name, start, len) \
2950f7917c00SJeff Kirsher 	t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
2951f7917c00SJeff Kirsher 	t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
2952f7917c00SJeff Kirsher 		     (start) + (len) - 1)
2953f7917c00SJeff Kirsher 
2954f7917c00SJeff Kirsher static void ulp_config(struct adapter *adap, const struct tp_params *p)
2955f7917c00SJeff Kirsher {
2956f7917c00SJeff Kirsher 	unsigned int m = p->chan_rx_size;
2957f7917c00SJeff Kirsher 
2958f7917c00SJeff Kirsher 	ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
2959f7917c00SJeff Kirsher 	ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
2960f7917c00SJeff Kirsher 	ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
2961f7917c00SJeff Kirsher 	ulp_region(adap, STAG, m, p->chan_rx_size / 4);
2962f7917c00SJeff Kirsher 	ulp_region(adap, RQ, m, p->chan_rx_size / 4);
2963f7917c00SJeff Kirsher 	ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
2964f7917c00SJeff Kirsher 	ulp_region(adap, PBL, m, p->chan_rx_size / 4);
2965f7917c00SJeff Kirsher 	t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
2966f7917c00SJeff Kirsher }
2967f7917c00SJeff Kirsher 
2968f7917c00SJeff Kirsher /**
2969f7917c00SJeff Kirsher  *	t3_set_proto_sram - set the contents of the protocol sram
297045677bc6SWang Hai  *	@adap: the adapter
2971f7917c00SJeff Kirsher  *	@data: the protocol image
2972f7917c00SJeff Kirsher  *
2973f7917c00SJeff Kirsher  *	Write the contents of the protocol SRAM.
2974f7917c00SJeff Kirsher  */
2975f7917c00SJeff Kirsher int t3_set_proto_sram(struct adapter *adap, const u8 *data)
2976f7917c00SJeff Kirsher {
2977f7917c00SJeff Kirsher 	int i;
2978f7917c00SJeff Kirsher 	const __be32 *buf = (const __be32 *)data;
2979f7917c00SJeff Kirsher 
2980f7917c00SJeff Kirsher 	for (i = 0; i < PROTO_SRAM_LINES; i++) {
2981f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, be32_to_cpu(*buf++));
2982f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, be32_to_cpu(*buf++));
2983f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, be32_to_cpu(*buf++));
2984f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, be32_to_cpu(*buf++));
2985f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, be32_to_cpu(*buf++));
2986f7917c00SJeff Kirsher 
2987f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
2988f7917c00SJeff Kirsher 		if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
2989f7917c00SJeff Kirsher 			return -EIO;
2990f7917c00SJeff Kirsher 	}
2991f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0);
2992f7917c00SJeff Kirsher 
2993f7917c00SJeff Kirsher 	return 0;
2994f7917c00SJeff Kirsher }
2995f7917c00SJeff Kirsher 
2996f7917c00SJeff Kirsher void t3_config_trace_filter(struct adapter *adapter,
2997f7917c00SJeff Kirsher 			    const struct trace_params *tp, int filter_index,
2998f7917c00SJeff Kirsher 			    int invert, int enable)
2999f7917c00SJeff Kirsher {
3000f7917c00SJeff Kirsher 	u32 addr, key[4], mask[4];
3001f7917c00SJeff Kirsher 
3002f7917c00SJeff Kirsher 	key[0] = tp->sport | (tp->sip << 16);
3003f7917c00SJeff Kirsher 	key[1] = (tp->sip >> 16) | (tp->dport << 16);
3004f7917c00SJeff Kirsher 	key[2] = tp->dip;
3005f7917c00SJeff Kirsher 	key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
3006f7917c00SJeff Kirsher 
3007f7917c00SJeff Kirsher 	mask[0] = tp->sport_mask | (tp->sip_mask << 16);
3008f7917c00SJeff Kirsher 	mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
3009f7917c00SJeff Kirsher 	mask[2] = tp->dip_mask;
3010f7917c00SJeff Kirsher 	mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
3011f7917c00SJeff Kirsher 
3012f7917c00SJeff Kirsher 	if (invert)
3013f7917c00SJeff Kirsher 		key[3] |= (1 << 29);
3014f7917c00SJeff Kirsher 	if (enable)
3015f7917c00SJeff Kirsher 		key[3] |= (1 << 28);
3016f7917c00SJeff Kirsher 
3017f7917c00SJeff Kirsher 	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
3018f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr++, key[0]);
3019f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr++, mask[0]);
3020f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr++, key[1]);
3021f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr++, mask[1]);
3022f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr++, key[2]);
3023f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr++, mask[2]);
3024f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr++, key[3]);
3025f7917c00SJeff Kirsher 	tp_wr_indirect(adapter, addr, mask[3]);
3026f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_TP_PIO_DATA);
3027f7917c00SJeff Kirsher }
3028f7917c00SJeff Kirsher 
3029f7917c00SJeff Kirsher /**
3030f7917c00SJeff Kirsher  *	t3_config_sched - configure a HW traffic scheduler
3031f7917c00SJeff Kirsher  *	@adap: the adapter
3032f7917c00SJeff Kirsher  *	@kbps: target rate in Kbps
3033f7917c00SJeff Kirsher  *	@sched: the scheduler index
3034f7917c00SJeff Kirsher  *
3035f7917c00SJeff Kirsher  *	Configure a HW scheduler for the target rate
3036f7917c00SJeff Kirsher  */
3037f7917c00SJeff Kirsher int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
3038f7917c00SJeff Kirsher {
3039f7917c00SJeff Kirsher 	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
3040f7917c00SJeff Kirsher 	unsigned int clk = adap->params.vpd.cclk * 1000;
3041f7917c00SJeff Kirsher 	unsigned int selected_cpt = 0, selected_bpt = 0;
3042f7917c00SJeff Kirsher 
3043f7917c00SJeff Kirsher 	if (kbps > 0) {
3044f7917c00SJeff Kirsher 		kbps *= 125;	/* -> bytes */
3045f7917c00SJeff Kirsher 		for (cpt = 1; cpt <= 255; cpt++) {
3046f7917c00SJeff Kirsher 			tps = clk / cpt;
3047f7917c00SJeff Kirsher 			bpt = (kbps + tps / 2) / tps;
3048f7917c00SJeff Kirsher 			if (bpt > 0 && bpt <= 255) {
3049f7917c00SJeff Kirsher 				v = bpt * tps;
3050f7917c00SJeff Kirsher 				delta = v >= kbps ? v - kbps : kbps - v;
3051f7917c00SJeff Kirsher 				if (delta <= mindelta) {
3052f7917c00SJeff Kirsher 					mindelta = delta;
3053f7917c00SJeff Kirsher 					selected_cpt = cpt;
3054f7917c00SJeff Kirsher 					selected_bpt = bpt;
3055f7917c00SJeff Kirsher 				}
3056f7917c00SJeff Kirsher 			} else if (selected_cpt)
3057f7917c00SJeff Kirsher 				break;
3058f7917c00SJeff Kirsher 		}
3059f7917c00SJeff Kirsher 		if (!selected_cpt)
3060f7917c00SJeff Kirsher 			return -EINVAL;
3061f7917c00SJeff Kirsher 	}
3062f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TM_PIO_ADDR,
3063f7917c00SJeff Kirsher 		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
3064f7917c00SJeff Kirsher 	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3065f7917c00SJeff Kirsher 	if (sched & 1)
3066f7917c00SJeff Kirsher 		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
3067f7917c00SJeff Kirsher 	else
3068f7917c00SJeff Kirsher 		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
3069f7917c00SJeff Kirsher 	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
3070f7917c00SJeff Kirsher 	return 0;
3071f7917c00SJeff Kirsher }
3072f7917c00SJeff Kirsher 
3073f7917c00SJeff Kirsher static int tp_init(struct adapter *adap, const struct tp_params *p)
3074f7917c00SJeff Kirsher {
3075f7917c00SJeff Kirsher 	int busy = 0;
3076f7917c00SJeff Kirsher 
3077f7917c00SJeff Kirsher 	tp_config(adap, p);
3078f7917c00SJeff Kirsher 	t3_set_vlan_accel(adap, 3, 0);
3079f7917c00SJeff Kirsher 
3080f7917c00SJeff Kirsher 	if (is_offload(adap)) {
3081f7917c00SJeff Kirsher 		tp_set_timers(adap, adap->params.vpd.cclk * 1000);
3082f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
3083f7917c00SJeff Kirsher 		busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
3084f7917c00SJeff Kirsher 				       0, 1000, 5);
3085f7917c00SJeff Kirsher 		if (busy)
3086f7917c00SJeff Kirsher 			CH_ERR(adap, "TP initialization timed out\n");
3087f7917c00SJeff Kirsher 	}
3088f7917c00SJeff Kirsher 
3089f7917c00SJeff Kirsher 	if (!busy)
3090f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_RESET, F_TPRESET);
3091f7917c00SJeff Kirsher 	return busy;
3092f7917c00SJeff Kirsher }
3093f7917c00SJeff Kirsher 
3094f7917c00SJeff Kirsher /*
3095f7917c00SJeff Kirsher  * Perform the bits of HW initialization that are dependent on the Tx
3096f7917c00SJeff Kirsher  * channels being used.
3097f7917c00SJeff Kirsher  */
3098f7917c00SJeff Kirsher static void chan_init_hw(struct adapter *adap, unsigned int chan_map)
3099f7917c00SJeff Kirsher {
3100f7917c00SJeff Kirsher 	int i;
3101f7917c00SJeff Kirsher 
3102f7917c00SJeff Kirsher 	if (chan_map != 3) {                                 /* one channel */
3103f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
3104f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
3105f7917c00SJeff Kirsher 		t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT |
3106f7917c00SJeff Kirsher 			     (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE :
3107f7917c00SJeff Kirsher 					      F_TPTXPORT1EN | F_PORT1ACTIVE));
3108f7917c00SJeff Kirsher 		t3_write_reg(adap, A_PM1_TX_CFG,
3109f7917c00SJeff Kirsher 			     chan_map == 1 ? 0xffffffff : 0);
3110f7917c00SJeff Kirsher 	} else {                                             /* two channels */
3111f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
3112f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
3113f7917c00SJeff Kirsher 		t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
3114f7917c00SJeff Kirsher 			     V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
3115f7917c00SJeff Kirsher 		t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
3116f7917c00SJeff Kirsher 			     F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
3117f7917c00SJeff Kirsher 			     F_ENFORCEPKT);
3118f7917c00SJeff Kirsher 		t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
3119f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
3120f7917c00SJeff Kirsher 		t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3121f7917c00SJeff Kirsher 			     V_TX_MOD_QUEUE_REQ_MAP(0xaa));
3122f7917c00SJeff Kirsher 		for (i = 0; i < 16; i++)
3123f7917c00SJeff Kirsher 			t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
3124f7917c00SJeff Kirsher 				     (i << 16) | 0x1010);
3125f7917c00SJeff Kirsher 	}
3126f7917c00SJeff Kirsher }
3127f7917c00SJeff Kirsher 
3128f7917c00SJeff Kirsher static int calibrate_xgm(struct adapter *adapter)
3129f7917c00SJeff Kirsher {
3130f7917c00SJeff Kirsher 	if (uses_xaui(adapter)) {
3131f7917c00SJeff Kirsher 		unsigned int v, i;
3132f7917c00SJeff Kirsher 
3133f7917c00SJeff Kirsher 		for (i = 0; i < 5; ++i) {
3134f7917c00SJeff Kirsher 			t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
3135f7917c00SJeff Kirsher 			t3_read_reg(adapter, A_XGM_XAUI_IMP);
3136f7917c00SJeff Kirsher 			msleep(1);
3137f7917c00SJeff Kirsher 			v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
3138f7917c00SJeff Kirsher 			if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
3139f7917c00SJeff Kirsher 				t3_write_reg(adapter, A_XGM_XAUI_IMP,
3140f7917c00SJeff Kirsher 					     V_XAUIIMP(G_CALIMP(v) >> 2));
3141f7917c00SJeff Kirsher 				return 0;
3142f7917c00SJeff Kirsher 			}
3143f7917c00SJeff Kirsher 		}
3144f7917c00SJeff Kirsher 		CH_ERR(adapter, "MAC calibration failed\n");
3145f7917c00SJeff Kirsher 		return -1;
3146f7917c00SJeff Kirsher 	} else {
3147f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_XGM_RGMII_IMP,
3148f7917c00SJeff Kirsher 			     V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3149f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3150f7917c00SJeff Kirsher 				 F_XGM_IMPSETUPDATE);
3151f7917c00SJeff Kirsher 	}
3152f7917c00SJeff Kirsher 	return 0;
3153f7917c00SJeff Kirsher }
3154f7917c00SJeff Kirsher 
3155f7917c00SJeff Kirsher static void calibrate_xgm_t3b(struct adapter *adapter)
3156f7917c00SJeff Kirsher {
3157f7917c00SJeff Kirsher 	if (!uses_xaui(adapter)) {
3158f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
3159f7917c00SJeff Kirsher 			     F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3160f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
3161f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
3162f7917c00SJeff Kirsher 				 F_XGM_IMPSETUPDATE);
3163f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3164f7917c00SJeff Kirsher 				 0);
3165f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
3166f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
3167f7917c00SJeff Kirsher 	}
3168f7917c00SJeff Kirsher }
3169f7917c00SJeff Kirsher 
3170f7917c00SJeff Kirsher struct mc7_timing_params {
3171f7917c00SJeff Kirsher 	unsigned char ActToPreDly;
3172f7917c00SJeff Kirsher 	unsigned char ActToRdWrDly;
3173f7917c00SJeff Kirsher 	unsigned char PreCyc;
3174f7917c00SJeff Kirsher 	unsigned char RefCyc[5];
3175f7917c00SJeff Kirsher 	unsigned char BkCyc;
3176f7917c00SJeff Kirsher 	unsigned char WrToRdDly;
3177f7917c00SJeff Kirsher 	unsigned char RdToWrDly;
3178f7917c00SJeff Kirsher };
3179f7917c00SJeff Kirsher 
3180f7917c00SJeff Kirsher /*
3181f7917c00SJeff Kirsher  * Write a value to a register and check that the write completed.  These
3182f7917c00SJeff Kirsher  * writes normally complete in a cycle or two, so one read should suffice.
3183f7917c00SJeff Kirsher  * The very first read exists to flush the posted write to the device.
3184f7917c00SJeff Kirsher  */
3185f7917c00SJeff Kirsher static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
3186f7917c00SJeff Kirsher {
3187f7917c00SJeff Kirsher 	t3_write_reg(adapter, addr, val);
3188f7917c00SJeff Kirsher 	t3_read_reg(adapter, addr);	/* flush */
3189f7917c00SJeff Kirsher 	if (!(t3_read_reg(adapter, addr) & F_BUSY))
3190f7917c00SJeff Kirsher 		return 0;
3191f7917c00SJeff Kirsher 	CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
3192f7917c00SJeff Kirsher 	return -EIO;
3193f7917c00SJeff Kirsher }
3194f7917c00SJeff Kirsher 
3195f7917c00SJeff Kirsher static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
3196f7917c00SJeff Kirsher {
3197f7917c00SJeff Kirsher 	static const unsigned int mc7_mode[] = {
3198f7917c00SJeff Kirsher 		0x632, 0x642, 0x652, 0x432, 0x442
3199f7917c00SJeff Kirsher 	};
3200f7917c00SJeff Kirsher 	static const struct mc7_timing_params mc7_timings[] = {
3201f7917c00SJeff Kirsher 		{12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
3202f7917c00SJeff Kirsher 		{12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
3203f7917c00SJeff Kirsher 		{12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
3204f7917c00SJeff Kirsher 		{9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
3205f7917c00SJeff Kirsher 		{9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
3206f7917c00SJeff Kirsher 	};
3207f7917c00SJeff Kirsher 
3208f7917c00SJeff Kirsher 	u32 val;
3209f7917c00SJeff Kirsher 	unsigned int width, density, slow, attempts;
3210f7917c00SJeff Kirsher 	struct adapter *adapter = mc7->adapter;
3211f7917c00SJeff Kirsher 	const struct mc7_timing_params *p = &mc7_timings[mem_type];
3212f7917c00SJeff Kirsher 
3213f7917c00SJeff Kirsher 	if (!mc7->size)
3214f7917c00SJeff Kirsher 		return 0;
3215f7917c00SJeff Kirsher 
3216f7917c00SJeff Kirsher 	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
3217f7917c00SJeff Kirsher 	slow = val & F_SLOW;
3218f7917c00SJeff Kirsher 	width = G_WIDTH(val);
3219f7917c00SJeff Kirsher 	density = G_DEN(val);
3220f7917c00SJeff Kirsher 
3221f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
3222f7917c00SJeff Kirsher 	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);	/* flush */
3223f7917c00SJeff Kirsher 	msleep(1);
3224f7917c00SJeff Kirsher 
3225f7917c00SJeff Kirsher 	if (!slow) {
3226f7917c00SJeff Kirsher 		t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
3227f7917c00SJeff Kirsher 		t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
3228f7917c00SJeff Kirsher 		msleep(1);
3229f7917c00SJeff Kirsher 		if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
3230f7917c00SJeff Kirsher 		    (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
3231f7917c00SJeff Kirsher 			CH_ERR(adapter, "%s MC7 calibration timed out\n",
3232f7917c00SJeff Kirsher 			       mc7->name);
3233f7917c00SJeff Kirsher 			goto out_fail;
3234f7917c00SJeff Kirsher 		}
3235f7917c00SJeff Kirsher 	}
3236f7917c00SJeff Kirsher 
3237f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
3238f7917c00SJeff Kirsher 		     V_ACTTOPREDLY(p->ActToPreDly) |
3239f7917c00SJeff Kirsher 		     V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
3240f7917c00SJeff Kirsher 		     V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
3241f7917c00SJeff Kirsher 		     V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
3242f7917c00SJeff Kirsher 
3243f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
3244f7917c00SJeff Kirsher 		     val | F_CLKEN | F_TERM150);
3245f7917c00SJeff Kirsher 	t3_read_reg(adapter, mc7->offset + A_MC7_CFG);	/* flush */
3246f7917c00SJeff Kirsher 
3247f7917c00SJeff Kirsher 	if (!slow)
3248f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
3249f7917c00SJeff Kirsher 				 F_DLLENB);
3250f7917c00SJeff Kirsher 	udelay(1);
3251f7917c00SJeff Kirsher 
3252f7917c00SJeff Kirsher 	val = slow ? 3 : 6;
3253f7917c00SJeff Kirsher 	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
3254f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
3255f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
3256f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
3257f7917c00SJeff Kirsher 		goto out_fail;
3258f7917c00SJeff Kirsher 
3259f7917c00SJeff Kirsher 	if (!slow) {
3260f7917c00SJeff Kirsher 		t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
3261f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
3262f7917c00SJeff Kirsher 		udelay(5);
3263f7917c00SJeff Kirsher 	}
3264f7917c00SJeff Kirsher 
3265f7917c00SJeff Kirsher 	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
3266f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
3267f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
3268f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
3269f7917c00SJeff Kirsher 		       mc7_mode[mem_type]) ||
3270f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
3271f7917c00SJeff Kirsher 	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
3272f7917c00SJeff Kirsher 		goto out_fail;
3273f7917c00SJeff Kirsher 
3274f7917c00SJeff Kirsher 	/* clock value is in KHz */
3275f7917c00SJeff Kirsher 	mc7_clock = mc7_clock * 7812 + mc7_clock / 2;	/* ns */
3276f7917c00SJeff Kirsher 	mc7_clock /= 1000000;	/* KHz->MHz, ns->us */
3277f7917c00SJeff Kirsher 
3278f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_REF,
3279f7917c00SJeff Kirsher 		     F_PERREFEN | V_PREREFDIV(mc7_clock));
3280f7917c00SJeff Kirsher 	t3_read_reg(adapter, mc7->offset + A_MC7_REF);	/* flush */
3281f7917c00SJeff Kirsher 
3282f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
3283f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
3284f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
3285f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
3286f7917c00SJeff Kirsher 		     (mc7->size << width) - 1);
3287f7917c00SJeff Kirsher 	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
3288f7917c00SJeff Kirsher 	t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);	/* flush */
3289f7917c00SJeff Kirsher 
3290f7917c00SJeff Kirsher 	attempts = 50;
3291f7917c00SJeff Kirsher 	do {
3292f7917c00SJeff Kirsher 		msleep(250);
3293f7917c00SJeff Kirsher 		val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
3294f7917c00SJeff Kirsher 	} while ((val & F_BUSY) && --attempts);
3295f7917c00SJeff Kirsher 	if (val & F_BUSY) {
3296f7917c00SJeff Kirsher 		CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
3297f7917c00SJeff Kirsher 		goto out_fail;
3298f7917c00SJeff Kirsher 	}
3299f7917c00SJeff Kirsher 
3300f7917c00SJeff Kirsher 	/* Enable normal memory accesses. */
3301f7917c00SJeff Kirsher 	t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
3302f7917c00SJeff Kirsher 	return 0;
3303f7917c00SJeff Kirsher 
3304f7917c00SJeff Kirsher out_fail:
3305f7917c00SJeff Kirsher 	return -1;
3306f7917c00SJeff Kirsher }
3307f7917c00SJeff Kirsher 
3308f7917c00SJeff Kirsher static void config_pcie(struct adapter *adap)
3309f7917c00SJeff Kirsher {
3310f7917c00SJeff Kirsher 	static const u16 ack_lat[4][6] = {
3311f7917c00SJeff Kirsher 		{237, 416, 559, 1071, 2095, 4143},
3312f7917c00SJeff Kirsher 		{128, 217, 289, 545, 1057, 2081},
3313f7917c00SJeff Kirsher 		{73, 118, 154, 282, 538, 1050},
3314f7917c00SJeff Kirsher 		{67, 107, 86, 150, 278, 534}
3315f7917c00SJeff Kirsher 	};
3316f7917c00SJeff Kirsher 	static const u16 rpl_tmr[4][6] = {
3317f7917c00SJeff Kirsher 		{711, 1248, 1677, 3213, 6285, 12429},
3318f7917c00SJeff Kirsher 		{384, 651, 867, 1635, 3171, 6243},
3319f7917c00SJeff Kirsher 		{219, 354, 462, 846, 1614, 3150},
3320f7917c00SJeff Kirsher 		{201, 321, 258, 450, 834, 1602}
3321f7917c00SJeff Kirsher 	};
3322f7917c00SJeff Kirsher 
3323f7917c00SJeff Kirsher 	u16 val, devid;
3324f7917c00SJeff Kirsher 	unsigned int log2_width, pldsize;
3325f7917c00SJeff Kirsher 	unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
3326f7917c00SJeff Kirsher 
3327c772b44eSJiang Liu 	pcie_capability_read_word(adap->pdev, PCI_EXP_DEVCTL, &val);
3328f7917c00SJeff Kirsher 	pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
3329f7917c00SJeff Kirsher 
3330f7917c00SJeff Kirsher 	pci_read_config_word(adap->pdev, 0x2, &devid);
3331f7917c00SJeff Kirsher 	if (devid == 0x37) {
3332c772b44eSJiang Liu 		pcie_capability_write_word(adap->pdev, PCI_EXP_DEVCTL,
3333f7917c00SJeff Kirsher 					   val & ~PCI_EXP_DEVCTL_READRQ &
3334f7917c00SJeff Kirsher 					   ~PCI_EXP_DEVCTL_PAYLOAD);
3335f7917c00SJeff Kirsher 		pldsize = 0;
3336f7917c00SJeff Kirsher 	}
3337f7917c00SJeff Kirsher 
3338c772b44eSJiang Liu 	pcie_capability_read_word(adap->pdev, PCI_EXP_LNKCTL, &val);
3339f7917c00SJeff Kirsher 
3340f7917c00SJeff Kirsher 	fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
3341f7917c00SJeff Kirsher 	fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
3342f7917c00SJeff Kirsher 	    G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
3343f7917c00SJeff Kirsher 	log2_width = fls(adap->params.pci.width) - 1;
3344f7917c00SJeff Kirsher 	acklat = ack_lat[log2_width][pldsize];
3345f2692bd9SBjorn Helgaas 	if (val & PCI_EXP_LNKCTL_ASPM_L0S)	/* check LOsEnable */
3346f7917c00SJeff Kirsher 		acklat += fst_trn_tx * 4;
3347f7917c00SJeff Kirsher 	rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
3348f7917c00SJeff Kirsher 
3349f7917c00SJeff Kirsher 	if (adap->params.rev == 0)
3350f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
3351f7917c00SJeff Kirsher 				 V_T3A_ACKLAT(M_T3A_ACKLAT),
3352f7917c00SJeff Kirsher 				 V_T3A_ACKLAT(acklat));
3353f7917c00SJeff Kirsher 	else
3354f7917c00SJeff Kirsher 		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
3355f7917c00SJeff Kirsher 				 V_ACKLAT(acklat));
3356f7917c00SJeff Kirsher 
3357f7917c00SJeff Kirsher 	t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
3358f7917c00SJeff Kirsher 			 V_REPLAYLMT(rpllmt));
3359f7917c00SJeff Kirsher 
3360f7917c00SJeff Kirsher 	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
3361f7917c00SJeff Kirsher 	t3_set_reg_field(adap, A_PCIE_CFG, 0,
3362f7917c00SJeff Kirsher 			 F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST |
3363f7917c00SJeff Kirsher 			 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
3364f7917c00SJeff Kirsher }
3365f7917c00SJeff Kirsher 
3366f7917c00SJeff Kirsher /*
3367f7917c00SJeff Kirsher  * Initialize and configure T3 HW modules.  This performs the
3368f7917c00SJeff Kirsher  * initialization steps that need to be done once after a card is reset.
3369f7917c00SJeff Kirsher  * MAC and PHY initialization is handled separarely whenever a port is enabled.
3370f7917c00SJeff Kirsher  *
3371f7917c00SJeff Kirsher  * fw_params are passed to FW and their value is platform dependent.  Only the
3372f7917c00SJeff Kirsher  * top 8 bits are available for use, the rest must be 0.
3373f7917c00SJeff Kirsher  */
3374f7917c00SJeff Kirsher int t3_init_hw(struct adapter *adapter, u32 fw_params)
3375f7917c00SJeff Kirsher {
3376f7917c00SJeff Kirsher 	int err = -EIO, attempts, i;
3377f7917c00SJeff Kirsher 	const struct vpd_params *vpd = &adapter->params.vpd;
3378f7917c00SJeff Kirsher 
3379f7917c00SJeff Kirsher 	if (adapter->params.rev > 0)
3380f7917c00SJeff Kirsher 		calibrate_xgm_t3b(adapter);
3381f7917c00SJeff Kirsher 	else if (calibrate_xgm(adapter))
3382f7917c00SJeff Kirsher 		goto out_err;
3383f7917c00SJeff Kirsher 
3384f7917c00SJeff Kirsher 	if (vpd->mclk) {
3385f7917c00SJeff Kirsher 		partition_mem(adapter, &adapter->params.tp);
3386f7917c00SJeff Kirsher 
3387f7917c00SJeff Kirsher 		if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
3388f7917c00SJeff Kirsher 		    mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
3389f7917c00SJeff Kirsher 		    mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
3390f7917c00SJeff Kirsher 		    t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
3391f7917c00SJeff Kirsher 				adapter->params.mc5.nfilters,
3392f7917c00SJeff Kirsher 				adapter->params.mc5.nroutes))
3393f7917c00SJeff Kirsher 			goto out_err;
3394f7917c00SJeff Kirsher 
3395f7917c00SJeff Kirsher 		for (i = 0; i < 32; i++)
3396f7917c00SJeff Kirsher 			if (clear_sge_ctxt(adapter, i, F_CQ))
3397f7917c00SJeff Kirsher 				goto out_err;
3398f7917c00SJeff Kirsher 	}
3399f7917c00SJeff Kirsher 
3400f7917c00SJeff Kirsher 	if (tp_init(adapter, &adapter->params.tp))
3401f7917c00SJeff Kirsher 		goto out_err;
3402f7917c00SJeff Kirsher 
3403f7917c00SJeff Kirsher 	t3_tp_set_coalescing_size(adapter,
3404f7917c00SJeff Kirsher 				  min(adapter->params.sge.max_pkt_size,
3405f7917c00SJeff Kirsher 				      MAX_RX_COALESCING_LEN), 1);
3406f7917c00SJeff Kirsher 	t3_tp_set_max_rxsize(adapter,
3407f7917c00SJeff Kirsher 			     min(adapter->params.sge.max_pkt_size, 16384U));
3408f7917c00SJeff Kirsher 	ulp_config(adapter, &adapter->params.tp);
3409f7917c00SJeff Kirsher 
3410f7917c00SJeff Kirsher 	if (is_pcie(adapter))
3411f7917c00SJeff Kirsher 		config_pcie(adapter);
3412f7917c00SJeff Kirsher 	else
3413f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_PCIX_CFG, 0,
3414f7917c00SJeff Kirsher 				 F_DMASTOPEN | F_CLIDECEN);
3415f7917c00SJeff Kirsher 
3416f7917c00SJeff Kirsher 	if (adapter->params.rev == T3_REV_C)
3417f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0,
3418f7917c00SJeff Kirsher 				 F_CFG_CQE_SOP_MASK);
3419f7917c00SJeff Kirsher 
3420f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
3421f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PM1_RX_MODE, 0);
3422f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PM1_TX_MODE, 0);
3423f7917c00SJeff Kirsher 	chan_init_hw(adapter, adapter->params.chan_map);
3424f7917c00SJeff Kirsher 	t3_sge_init(adapter, &adapter->params.sge);
3425f7917c00SJeff Kirsher 	t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN);
3426f7917c00SJeff Kirsher 
3427f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
3428f7917c00SJeff Kirsher 
3429f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
3430f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_CIM_BOOT_CFG,
3431f7917c00SJeff Kirsher 		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
3432f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_CIM_BOOT_CFG);	/* flush */
3433f7917c00SJeff Kirsher 
3434f7917c00SJeff Kirsher 	attempts = 100;
3435f7917c00SJeff Kirsher 	do {			/* wait for uP to initialize */
3436f7917c00SJeff Kirsher 		msleep(20);
3437f7917c00SJeff Kirsher 	} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
3438f7917c00SJeff Kirsher 	if (!attempts) {
3439f7917c00SJeff Kirsher 		CH_ERR(adapter, "uP initialization timed out\n");
3440f7917c00SJeff Kirsher 		goto out_err;
3441f7917c00SJeff Kirsher 	}
3442f7917c00SJeff Kirsher 
3443f7917c00SJeff Kirsher 	err = 0;
3444f7917c00SJeff Kirsher out_err:
3445f7917c00SJeff Kirsher 	return err;
3446f7917c00SJeff Kirsher }
3447f7917c00SJeff Kirsher 
3448f7917c00SJeff Kirsher /**
3449f7917c00SJeff Kirsher  *	get_pci_mode - determine a card's PCI mode
3450f7917c00SJeff Kirsher  *	@adapter: the adapter
3451f7917c00SJeff Kirsher  *	@p: where to store the PCI settings
3452f7917c00SJeff Kirsher  *
3453f7917c00SJeff Kirsher  *	Determines a card's PCI mode and associated parameters, such as speed
3454f7917c00SJeff Kirsher  *	and width.
3455f7917c00SJeff Kirsher  */
3456f7917c00SJeff Kirsher static void get_pci_mode(struct adapter *adapter, struct pci_params *p)
3457f7917c00SJeff Kirsher {
3458f7917c00SJeff Kirsher 	static unsigned short speed_map[] = { 33, 66, 100, 133 };
3459c772b44eSJiang Liu 	u32 pci_mode;
3460f7917c00SJeff Kirsher 
3461c772b44eSJiang Liu 	if (pci_is_pcie(adapter->pdev)) {
3462f7917c00SJeff Kirsher 		u16 val;
3463f7917c00SJeff Kirsher 
3464f7917c00SJeff Kirsher 		p->variant = PCI_VARIANT_PCIE;
3465c772b44eSJiang Liu 		pcie_capability_read_word(adapter->pdev, PCI_EXP_LNKSTA, &val);
3466f7917c00SJeff Kirsher 		p->width = (val >> 4) & 0x3f;
3467f7917c00SJeff Kirsher 		return;
3468f7917c00SJeff Kirsher 	}
3469f7917c00SJeff Kirsher 
3470f7917c00SJeff Kirsher 	pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
3471f7917c00SJeff Kirsher 	p->speed = speed_map[G_PCLKRANGE(pci_mode)];
3472f7917c00SJeff Kirsher 	p->width = (pci_mode & F_64BIT) ? 64 : 32;
3473f7917c00SJeff Kirsher 	pci_mode = G_PCIXINITPAT(pci_mode);
3474f7917c00SJeff Kirsher 	if (pci_mode == 0)
3475f7917c00SJeff Kirsher 		p->variant = PCI_VARIANT_PCI;
3476f7917c00SJeff Kirsher 	else if (pci_mode < 4)
3477f7917c00SJeff Kirsher 		p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
3478f7917c00SJeff Kirsher 	else if (pci_mode < 8)
3479f7917c00SJeff Kirsher 		p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
3480f7917c00SJeff Kirsher 	else
3481f7917c00SJeff Kirsher 		p->variant = PCI_VARIANT_PCIX_266_MODE2;
3482f7917c00SJeff Kirsher }
3483f7917c00SJeff Kirsher 
3484f7917c00SJeff Kirsher /**
3485f7917c00SJeff Kirsher  *	init_link_config - initialize a link's SW state
3486f7917c00SJeff Kirsher  *	@lc: structure holding the link state
3487d0ea5cbdSJesse Brandeburg  *	@caps: information about the current card
3488f7917c00SJeff Kirsher  *
3489f7917c00SJeff Kirsher  *	Initializes the SW state maintained for each link, including the link's
3490f7917c00SJeff Kirsher  *	capabilities and default speed/duplex/flow-control/autonegotiation
3491f7917c00SJeff Kirsher  *	settings.
3492f7917c00SJeff Kirsher  */
3493f7917c00SJeff Kirsher static void init_link_config(struct link_config *lc, unsigned int caps)
3494f7917c00SJeff Kirsher {
3495f7917c00SJeff Kirsher 	lc->supported = caps;
3496f7917c00SJeff Kirsher 	lc->requested_speed = lc->speed = SPEED_INVALID;
3497f7917c00SJeff Kirsher 	lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
3498f7917c00SJeff Kirsher 	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
3499f7917c00SJeff Kirsher 	if (lc->supported & SUPPORTED_Autoneg) {
3500f7917c00SJeff Kirsher 		lc->advertising = lc->supported;
3501f7917c00SJeff Kirsher 		lc->autoneg = AUTONEG_ENABLE;
3502f7917c00SJeff Kirsher 		lc->requested_fc |= PAUSE_AUTONEG;
3503f7917c00SJeff Kirsher 	} else {
3504f7917c00SJeff Kirsher 		lc->advertising = 0;
3505f7917c00SJeff Kirsher 		lc->autoneg = AUTONEG_DISABLE;
3506f7917c00SJeff Kirsher 	}
3507f7917c00SJeff Kirsher }
3508f7917c00SJeff Kirsher 
3509f7917c00SJeff Kirsher /**
3510f7917c00SJeff Kirsher  *	mc7_calc_size - calculate MC7 memory size
3511f7917c00SJeff Kirsher  *	@cfg: the MC7 configuration
3512f7917c00SJeff Kirsher  *
3513f7917c00SJeff Kirsher  *	Calculates the size of an MC7 memory in bytes from the value of its
3514f7917c00SJeff Kirsher  *	configuration register.
3515f7917c00SJeff Kirsher  */
3516f7917c00SJeff Kirsher static unsigned int mc7_calc_size(u32 cfg)
3517f7917c00SJeff Kirsher {
3518f7917c00SJeff Kirsher 	unsigned int width = G_WIDTH(cfg);
3519f7917c00SJeff Kirsher 	unsigned int banks = !!(cfg & F_BKS) + 1;
3520f7917c00SJeff Kirsher 	unsigned int org = !!(cfg & F_ORG) + 1;
3521f7917c00SJeff Kirsher 	unsigned int density = G_DEN(cfg);
3522f7917c00SJeff Kirsher 	unsigned int MBs = ((256 << density) * banks) / (org << width);
3523f7917c00SJeff Kirsher 
3524f7917c00SJeff Kirsher 	return MBs << 20;
3525f7917c00SJeff Kirsher }
3526f7917c00SJeff Kirsher 
3527f7917c00SJeff Kirsher static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
3528f7917c00SJeff Kirsher 		     unsigned int base_addr, const char *name)
3529f7917c00SJeff Kirsher {
3530f7917c00SJeff Kirsher 	u32 cfg;
3531f7917c00SJeff Kirsher 
3532f7917c00SJeff Kirsher 	mc7->adapter = adapter;
3533f7917c00SJeff Kirsher 	mc7->name = name;
3534f7917c00SJeff Kirsher 	mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
3535f7917c00SJeff Kirsher 	cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
3536f7917c00SJeff Kirsher 	mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
3537f7917c00SJeff Kirsher 	mc7->width = G_WIDTH(cfg);
3538f7917c00SJeff Kirsher }
3539f7917c00SJeff Kirsher 
3540f7917c00SJeff Kirsher static void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
3541f7917c00SJeff Kirsher {
3542f7917c00SJeff Kirsher 	u16 devid;
3543f7917c00SJeff Kirsher 
3544f7917c00SJeff Kirsher 	mac->adapter = adapter;
3545f7917c00SJeff Kirsher 	pci_read_config_word(adapter->pdev, 0x2, &devid);
3546f7917c00SJeff Kirsher 
3547f7917c00SJeff Kirsher 	if (devid == 0x37 && !adapter->params.vpd.xauicfg[1])
3548f7917c00SJeff Kirsher 		index = 0;
3549f7917c00SJeff Kirsher 	mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
3550f7917c00SJeff Kirsher 	mac->nucast = 1;
3551f7917c00SJeff Kirsher 
3552f7917c00SJeff Kirsher 	if (adapter->params.rev == 0 && uses_xaui(adapter)) {
3553f7917c00SJeff Kirsher 		t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
3554f7917c00SJeff Kirsher 			     is_10G(adapter) ? 0x2901c04 : 0x2301c04);
3555f7917c00SJeff Kirsher 		t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
3556f7917c00SJeff Kirsher 				 F_ENRGMII, 0);
3557f7917c00SJeff Kirsher 	}
3558f7917c00SJeff Kirsher }
3559f7917c00SJeff Kirsher 
3560f7917c00SJeff Kirsher static void early_hw_init(struct adapter *adapter,
3561f7917c00SJeff Kirsher 			  const struct adapter_info *ai)
3562f7917c00SJeff Kirsher {
3563f7917c00SJeff Kirsher 	u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
3564f7917c00SJeff Kirsher 
3565f7917c00SJeff Kirsher 	mi1_init(adapter, ai);
3566f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_I2C_CFG,	/* set for 80KHz */
3567f7917c00SJeff Kirsher 		     V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
3568f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_T3DBG_GPIO_EN,
3569f7917c00SJeff Kirsher 		     ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
3570f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
3571f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff));
3572f7917c00SJeff Kirsher 
3573f7917c00SJeff Kirsher 	if (adapter->params.rev == 0 || !uses_xaui(adapter))
3574f7917c00SJeff Kirsher 		val |= F_ENRGMII;
3575f7917c00SJeff Kirsher 
3576f7917c00SJeff Kirsher 	/* Enable MAC clocks so we can access the registers */
3577f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
3578f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_XGM_PORT_CFG);
3579f7917c00SJeff Kirsher 
3580f7917c00SJeff Kirsher 	val |= F_CLKDIVRESET_;
3581f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
3582f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_XGM_PORT_CFG);
3583f7917c00SJeff Kirsher 	t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
3584f7917c00SJeff Kirsher 	t3_read_reg(adapter, A_XGM_PORT_CFG);
3585f7917c00SJeff Kirsher }
3586f7917c00SJeff Kirsher 
3587f7917c00SJeff Kirsher /*
3588f7917c00SJeff Kirsher  * Reset the adapter.
3589f7917c00SJeff Kirsher  * Older PCIe cards lose their config space during reset, PCI-X
3590f7917c00SJeff Kirsher  * ones don't.
3591f7917c00SJeff Kirsher  */
3592f7917c00SJeff Kirsher int t3_reset_adapter(struct adapter *adapter)
3593f7917c00SJeff Kirsher {
3594f7917c00SJeff Kirsher 	int i, save_and_restore_pcie =
3595f7917c00SJeff Kirsher 	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
3596f7917c00SJeff Kirsher 	uint16_t devid = 0;
3597f7917c00SJeff Kirsher 
3598f7917c00SJeff Kirsher 	if (save_and_restore_pcie)
3599f7917c00SJeff Kirsher 		pci_save_state(adapter->pdev);
3600f7917c00SJeff Kirsher 	t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
3601f7917c00SJeff Kirsher 
3602f7917c00SJeff Kirsher 	/*
3603f7917c00SJeff Kirsher 	 * Delay. Give Some time to device to reset fully.
3604f7917c00SJeff Kirsher 	 * XXX The delay time should be modified.
3605f7917c00SJeff Kirsher 	 */
3606f7917c00SJeff Kirsher 	for (i = 0; i < 10; i++) {
3607f7917c00SJeff Kirsher 		msleep(50);
3608f7917c00SJeff Kirsher 		pci_read_config_word(adapter->pdev, 0x00, &devid);
3609f7917c00SJeff Kirsher 		if (devid == 0x1425)
3610f7917c00SJeff Kirsher 			break;
3611f7917c00SJeff Kirsher 	}
3612f7917c00SJeff Kirsher 
3613f7917c00SJeff Kirsher 	if (devid != 0x1425)
3614f7917c00SJeff Kirsher 		return -1;
3615f7917c00SJeff Kirsher 
3616f7917c00SJeff Kirsher 	if (save_and_restore_pcie)
3617f7917c00SJeff Kirsher 		pci_restore_state(adapter->pdev);
3618f7917c00SJeff Kirsher 	return 0;
3619f7917c00SJeff Kirsher }
3620f7917c00SJeff Kirsher 
3621f7917c00SJeff Kirsher static int init_parity(struct adapter *adap)
3622f7917c00SJeff Kirsher {
3623f7917c00SJeff Kirsher 	int i, err, addr;
3624f7917c00SJeff Kirsher 
3625f7917c00SJeff Kirsher 	if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
3626f7917c00SJeff Kirsher 		return -EBUSY;
3627f7917c00SJeff Kirsher 
3628f7917c00SJeff Kirsher 	for (err = i = 0; !err && i < 16; i++)
3629f7917c00SJeff Kirsher 		err = clear_sge_ctxt(adap, i, F_EGRESS);
3630f7917c00SJeff Kirsher 	for (i = 0xfff0; !err && i <= 0xffff; i++)
3631f7917c00SJeff Kirsher 		err = clear_sge_ctxt(adap, i, F_EGRESS);
3632f7917c00SJeff Kirsher 	for (i = 0; !err && i < SGE_QSETS; i++)
3633f7917c00SJeff Kirsher 		err = clear_sge_ctxt(adap, i, F_RESPONSEQ);
3634f7917c00SJeff Kirsher 	if (err)
3635f7917c00SJeff Kirsher 		return err;
3636f7917c00SJeff Kirsher 
3637f7917c00SJeff Kirsher 	t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0);
3638f7917c00SJeff Kirsher 	for (i = 0; i < 4; i++)
3639f7917c00SJeff Kirsher 		for (addr = 0; addr <= M_IBQDBGADDR; addr++) {
3640f7917c00SJeff Kirsher 			t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN |
3641f7917c00SJeff Kirsher 				     F_IBQDBGWR | V_IBQDBGQID(i) |
3642f7917c00SJeff Kirsher 				     V_IBQDBGADDR(addr));
3643f7917c00SJeff Kirsher 			err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG,
3644f7917c00SJeff Kirsher 					      F_IBQDBGBUSY, 0, 2, 1);
3645f7917c00SJeff Kirsher 			if (err)
3646f7917c00SJeff Kirsher 				return err;
3647f7917c00SJeff Kirsher 		}
3648f7917c00SJeff Kirsher 	return 0;
3649f7917c00SJeff Kirsher }
3650f7917c00SJeff Kirsher 
3651f7917c00SJeff Kirsher /*
3652f7917c00SJeff Kirsher  * Initialize adapter SW state for the various HW modules, set initial values
3653f7917c00SJeff Kirsher  * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
3654f7917c00SJeff Kirsher  * interface.
3655f7917c00SJeff Kirsher  */
3656f7917c00SJeff Kirsher int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
3657f7917c00SJeff Kirsher 		    int reset)
3658f7917c00SJeff Kirsher {
3659f7917c00SJeff Kirsher 	int ret;
3660f7917c00SJeff Kirsher 	unsigned int i, j = -1;
3661f7917c00SJeff Kirsher 
3662f7917c00SJeff Kirsher 	get_pci_mode(adapter, &adapter->params.pci);
3663f7917c00SJeff Kirsher 
3664f7917c00SJeff Kirsher 	adapter->params.info = ai;
3665f7917c00SJeff Kirsher 	adapter->params.nports = ai->nports0 + ai->nports1;
3666f7917c00SJeff Kirsher 	adapter->params.chan_map = (!!ai->nports0) | (!!ai->nports1 << 1);
3667f7917c00SJeff Kirsher 	adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
3668f7917c00SJeff Kirsher 	/*
3669f7917c00SJeff Kirsher 	 * We used to only run the "adapter check task" once a second if
3670f7917c00SJeff Kirsher 	 * we had PHYs which didn't support interrupts (we would check
3671f7917c00SJeff Kirsher 	 * their link status once a second).  Now we check other conditions
3672f7917c00SJeff Kirsher 	 * in that routine which could potentially impose a very high
3673f7917c00SJeff Kirsher 	 * interrupt load on the system.  As such, we now always scan the
3674f7917c00SJeff Kirsher 	 * adapter state once a second ...
3675f7917c00SJeff Kirsher 	 */
3676f7917c00SJeff Kirsher 	adapter->params.linkpoll_period = 10;
3677f7917c00SJeff Kirsher 	adapter->params.stats_update_period = is_10G(adapter) ?
3678f7917c00SJeff Kirsher 	    MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
3679f7917c00SJeff Kirsher 	adapter->params.pci.vpd_cap_addr =
3680f7917c00SJeff Kirsher 	    pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
3681f7917c00SJeff Kirsher 	ret = get_vpd_params(adapter, &adapter->params.vpd);
3682f7917c00SJeff Kirsher 	if (ret < 0)
3683f7917c00SJeff Kirsher 		return ret;
3684f7917c00SJeff Kirsher 
3685f7917c00SJeff Kirsher 	if (reset && t3_reset_adapter(adapter))
3686f7917c00SJeff Kirsher 		return -1;
3687f7917c00SJeff Kirsher 
3688f7917c00SJeff Kirsher 	t3_sge_prep(adapter, &adapter->params.sge);
3689f7917c00SJeff Kirsher 
3690f7917c00SJeff Kirsher 	if (adapter->params.vpd.mclk) {
3691f7917c00SJeff Kirsher 		struct tp_params *p = &adapter->params.tp;
3692f7917c00SJeff Kirsher 
3693f7917c00SJeff Kirsher 		mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
3694f7917c00SJeff Kirsher 		mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
3695f7917c00SJeff Kirsher 		mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
3696f7917c00SJeff Kirsher 
3697f7917c00SJeff Kirsher 		p->nchan = adapter->params.chan_map == 3 ? 2 : 1;
3698f7917c00SJeff Kirsher 		p->pmrx_size = t3_mc7_size(&adapter->pmrx);
3699f7917c00SJeff Kirsher 		p->pmtx_size = t3_mc7_size(&adapter->pmtx);
3700f7917c00SJeff Kirsher 		p->cm_size = t3_mc7_size(&adapter->cm);
3701f7917c00SJeff Kirsher 		p->chan_rx_size = p->pmrx_size / 2;	/* only 1 Rx channel */
3702f7917c00SJeff Kirsher 		p->chan_tx_size = p->pmtx_size / p->nchan;
3703f7917c00SJeff Kirsher 		p->rx_pg_size = 64 * 1024;
3704f7917c00SJeff Kirsher 		p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
3705f7917c00SJeff Kirsher 		p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
3706f7917c00SJeff Kirsher 		p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
3707f7917c00SJeff Kirsher 		p->ntimer_qs = p->cm_size >= (128 << 20) ||
3708f7917c00SJeff Kirsher 		    adapter->params.rev > 0 ? 12 : 6;
3709f7917c00SJeff Kirsher 	}
3710f7917c00SJeff Kirsher 
3711f7917c00SJeff Kirsher 	adapter->params.offload = t3_mc7_size(&adapter->pmrx) &&
3712f7917c00SJeff Kirsher 				  t3_mc7_size(&adapter->pmtx) &&
3713f7917c00SJeff Kirsher 				  t3_mc7_size(&adapter->cm);
3714f7917c00SJeff Kirsher 
3715f7917c00SJeff Kirsher 	if (is_offload(adapter)) {
3716f7917c00SJeff Kirsher 		adapter->params.mc5.nservers = DEFAULT_NSERVERS;
3717f7917c00SJeff Kirsher 		adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
3718f7917c00SJeff Kirsher 		    DEFAULT_NFILTERS : 0;
3719f7917c00SJeff Kirsher 		adapter->params.mc5.nroutes = 0;
3720f7917c00SJeff Kirsher 		t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
3721f7917c00SJeff Kirsher 
3722f7917c00SJeff Kirsher 		init_mtus(adapter->params.mtus);
3723f7917c00SJeff Kirsher 		init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
3724f7917c00SJeff Kirsher 	}
3725f7917c00SJeff Kirsher 
3726f7917c00SJeff Kirsher 	early_hw_init(adapter, ai);
3727f7917c00SJeff Kirsher 	ret = init_parity(adapter);
3728f7917c00SJeff Kirsher 	if (ret)
3729f7917c00SJeff Kirsher 		return ret;
3730f7917c00SJeff Kirsher 
3731f7917c00SJeff Kirsher 	for_each_port(adapter, i) {
3732f7917c00SJeff Kirsher 		u8 hw_addr[6];
3733f7917c00SJeff Kirsher 		const struct port_type_info *pti;
3734f7917c00SJeff Kirsher 		struct port_info *p = adap2pinfo(adapter, i);
3735f7917c00SJeff Kirsher 
3736f7917c00SJeff Kirsher 		while (!adapter->params.vpd.port_type[++j])
3737f7917c00SJeff Kirsher 			;
3738f7917c00SJeff Kirsher 
3739f7917c00SJeff Kirsher 		pti = &port_types[adapter->params.vpd.port_type[j]];
3740f7917c00SJeff Kirsher 		if (!pti->phy_prep) {
3741f7917c00SJeff Kirsher 			CH_ALERT(adapter, "Invalid port type index %d\n",
3742f7917c00SJeff Kirsher 				 adapter->params.vpd.port_type[j]);
3743f7917c00SJeff Kirsher 			return -EINVAL;
3744f7917c00SJeff Kirsher 		}
3745f7917c00SJeff Kirsher 
3746f7917c00SJeff Kirsher 		p->phy.mdio.dev = adapter->port[i];
3747f7917c00SJeff Kirsher 		ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
3748f7917c00SJeff Kirsher 				    ai->mdio_ops);
3749f7917c00SJeff Kirsher 		if (ret)
3750f7917c00SJeff Kirsher 			return ret;
3751f7917c00SJeff Kirsher 		mac_prep(&p->mac, adapter, j);
3752f7917c00SJeff Kirsher 
3753f7917c00SJeff Kirsher 		/*
3754f7917c00SJeff Kirsher 		 * The VPD EEPROM stores the base Ethernet address for the
3755f7917c00SJeff Kirsher 		 * card.  A port's address is derived from the base by adding
3756f7917c00SJeff Kirsher 		 * the port's index to the base's low octet.
3757f7917c00SJeff Kirsher 		 */
3758f7917c00SJeff Kirsher 		memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
3759f7917c00SJeff Kirsher 		hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
3760f7917c00SJeff Kirsher 
3761f7917c00SJeff Kirsher 		memcpy(adapter->port[i]->dev_addr, hw_addr,
3762f7917c00SJeff Kirsher 		       ETH_ALEN);
3763f7917c00SJeff Kirsher 		init_link_config(&p->link_config, p->phy.caps);
3764f7917c00SJeff Kirsher 		p->phy.ops->power_down(&p->phy, 1);
3765f7917c00SJeff Kirsher 
3766f7917c00SJeff Kirsher 		/*
3767f7917c00SJeff Kirsher 		 * If the PHY doesn't support interrupts for link status
3768f7917c00SJeff Kirsher 		 * changes, schedule a scan of the adapter links at least
3769f7917c00SJeff Kirsher 		 * once a second.
3770f7917c00SJeff Kirsher 		 */
3771f7917c00SJeff Kirsher 		if (!(p->phy.caps & SUPPORTED_IRQ) &&
3772f7917c00SJeff Kirsher 		    adapter->params.linkpoll_period > 10)
3773f7917c00SJeff Kirsher 			adapter->params.linkpoll_period = 10;
3774f7917c00SJeff Kirsher 	}
3775f7917c00SJeff Kirsher 
3776f7917c00SJeff Kirsher 	return 0;
3777f7917c00SJeff Kirsher }
3778f7917c00SJeff Kirsher 
3779f7917c00SJeff Kirsher void t3_led_ready(struct adapter *adapter)
3780f7917c00SJeff Kirsher {
3781f7917c00SJeff Kirsher 	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
3782f7917c00SJeff Kirsher 			 F_GPIO0_OUT_VAL);
3783f7917c00SJeff Kirsher }
3784f7917c00SJeff Kirsher 
3785f7917c00SJeff Kirsher int t3_replay_prep_adapter(struct adapter *adapter)
3786f7917c00SJeff Kirsher {
3787f7917c00SJeff Kirsher 	const struct adapter_info *ai = adapter->params.info;
3788f7917c00SJeff Kirsher 	unsigned int i, j = -1;
3789f7917c00SJeff Kirsher 	int ret;
3790f7917c00SJeff Kirsher 
3791f7917c00SJeff Kirsher 	early_hw_init(adapter, ai);
3792f7917c00SJeff Kirsher 	ret = init_parity(adapter);
3793f7917c00SJeff Kirsher 	if (ret)
3794f7917c00SJeff Kirsher 		return ret;
3795f7917c00SJeff Kirsher 
3796f7917c00SJeff Kirsher 	for_each_port(adapter, i) {
3797f7917c00SJeff Kirsher 		const struct port_type_info *pti;
3798f7917c00SJeff Kirsher 		struct port_info *p = adap2pinfo(adapter, i);
3799f7917c00SJeff Kirsher 
3800f7917c00SJeff Kirsher 		while (!adapter->params.vpd.port_type[++j])
3801f7917c00SJeff Kirsher 			;
3802f7917c00SJeff Kirsher 
3803f7917c00SJeff Kirsher 		pti = &port_types[adapter->params.vpd.port_type[j]];
3804f7917c00SJeff Kirsher 		ret = pti->phy_prep(&p->phy, adapter, p->phy.mdio.prtad, NULL);
3805f7917c00SJeff Kirsher 		if (ret)
3806f7917c00SJeff Kirsher 			return ret;
3807f7917c00SJeff Kirsher 		p->phy.ops->power_down(&p->phy, 1);
3808f7917c00SJeff Kirsher 	}
3809f7917c00SJeff Kirsher 
3810f7917c00SJeff Kirsher 	return 0;
3811f7917c00SJeff Kirsher }
3812f7917c00SJeff Kirsher 
3813