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