1167514Skmacy/**************************************************************************
2167514Skmacy
3189643SgnnCopyright (c) 2007-2009, Chelsio Inc.
4167514SkmacyAll rights reserved.
5167514Skmacy
6167514SkmacyRedistribution and use in source and binary forms, with or without
7167514Skmacymodification, are permitted provided that the following conditions are met:
8167514Skmacy
9167514Skmacy 1. Redistributions of source code must retain the above copyright notice,
10167514Skmacy    this list of conditions and the following disclaimer.
11167514Skmacy
12170076Skmacy 2. Neither the name of the Chelsio Corporation nor the names of its
13167514Skmacy    contributors may be used to endorse or promote products derived from
14167514Skmacy    this software without specific prior written permission.
15167514Skmacy
16167514SkmacyTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17167514SkmacyAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18167514SkmacyIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19167514SkmacyARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20167514SkmacyLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21167514SkmacyCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22167514SkmacySUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23167514SkmacyINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24167514SkmacyCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25167514SkmacyARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26167514SkmacyPOSSIBILITY OF SUCH DAMAGE.
27167514Skmacy
28167514Skmacy***************************************************************************/
29167514Skmacy
30167514Skmacy#include <sys/cdefs.h>
31172100Skmacy__FBSDID("$FreeBSD$");
32167514Skmacy
33170654Skmacy
34170076Skmacy#include <cxgb_include.h>
35167514Skmacy
36171471Skmacy#undef msleep
37171471Skmacy#define msleep t3_os_sleep
38170654Skmacy
39167514Skmacy/**
40167514Skmacy *	t3_wait_op_done_val - wait until an operation is completed
41167514Skmacy *	@adapter: the adapter performing the operation
42167514Skmacy *	@reg: the register to check for completion
43167514Skmacy *	@mask: a single-bit field within @reg that indicates completion
44167514Skmacy *	@polarity: the value of the field when the operation is completed
45167514Skmacy *	@attempts: number of check iterations
46167514Skmacy *	@delay: delay in usecs between iterations
47167514Skmacy *	@valp: where to store the value of the register at completion time
48167514Skmacy *
49167514Skmacy *	Wait until an operation is completed by checking a bit in a register
50167514Skmacy *	up to @attempts times.  If @valp is not NULL the value of the register
51167514Skmacy *	at the time it indicated completion is stored there.  Returns 0 if the
52167514Skmacy *	operation completes and	-EAGAIN	otherwise.
53167514Skmacy */
54167514Skmacyint t3_wait_op_done_val(adapter_t *adapter, int reg, u32 mask, int polarity,
55167514Skmacy			int attempts, int delay, u32 *valp)
56167514Skmacy{
57167514Skmacy	while (1) {
58167514Skmacy		u32 val = t3_read_reg(adapter, reg);
59167514Skmacy
60167514Skmacy		if (!!(val & mask) == polarity) {
61167514Skmacy			if (valp)
62167514Skmacy				*valp = val;
63167514Skmacy			return 0;
64167514Skmacy		}
65167514Skmacy		if (--attempts == 0)
66167514Skmacy			return -EAGAIN;
67167514Skmacy		if (delay)
68167514Skmacy			udelay(delay);
69167514Skmacy	}
70167514Skmacy}
71167514Skmacy
72167514Skmacy/**
73167514Skmacy *	t3_write_regs - write a bunch of registers
74167514Skmacy *	@adapter: the adapter to program
75167514Skmacy *	@p: an array of register address/register value pairs
76167514Skmacy *	@n: the number of address/value pairs
77167514Skmacy *	@offset: register address offset
78167514Skmacy *
79167514Skmacy *	Takes an array of register address/register value pairs and writes each
80167514Skmacy *	value to the corresponding register.  Register addresses are adjusted
81167514Skmacy *	by the supplied offset.
82167514Skmacy */
83167514Skmacyvoid t3_write_regs(adapter_t *adapter, const struct addr_val_pair *p, int n,
84167514Skmacy		   unsigned int offset)
85167514Skmacy{
86167514Skmacy	while (n--) {
87167514Skmacy		t3_write_reg(adapter, p->reg_addr + offset, p->val);
88167514Skmacy		p++;
89167514Skmacy	}
90167514Skmacy}
91167514Skmacy
92167514Skmacy/**
93167514Skmacy *	t3_set_reg_field - set a register field to a value
94167514Skmacy *	@adapter: the adapter to program
95167514Skmacy *	@addr: the register address
96167514Skmacy *	@mask: specifies the portion of the register to modify
97167514Skmacy *	@val: the new value for the register field
98167514Skmacy *
99167514Skmacy *	Sets a register field specified by the supplied mask to the
100167514Skmacy *	given value.
101167514Skmacy */
102167514Skmacyvoid t3_set_reg_field(adapter_t *adapter, unsigned int addr, u32 mask, u32 val)
103167514Skmacy{
104167514Skmacy	u32 v = t3_read_reg(adapter, addr) & ~mask;
105167514Skmacy
106167514Skmacy	t3_write_reg(adapter, addr, v | val);
107167514Skmacy	(void) t3_read_reg(adapter, addr);      /* flush */
108167514Skmacy}
109167514Skmacy
110167514Skmacy/**
111167514Skmacy *	t3_read_indirect - read indirectly addressed registers
112167514Skmacy *	@adap: the adapter
113167514Skmacy *	@addr_reg: register holding the indirect address
114167514Skmacy *	@data_reg: register holding the value of the indirect register
115167514Skmacy *	@vals: where the read register values are stored
116167514Skmacy *	@start_idx: index of first indirect register to read
117167514Skmacy *	@nregs: how many indirect registers to read
118167514Skmacy *
119167514Skmacy *	Reads registers that are accessed indirectly through an address/data
120167514Skmacy *	register pair.
121167514Skmacy */
122170654Skmacystatic void t3_read_indirect(adapter_t *adap, unsigned int addr_reg,
123167514Skmacy		      unsigned int data_reg, u32 *vals, unsigned int nregs,
124167514Skmacy		      unsigned int start_idx)
125167514Skmacy{
126167514Skmacy	while (nregs--) {
127167514Skmacy		t3_write_reg(adap, addr_reg, start_idx);
128167514Skmacy		*vals++ = t3_read_reg(adap, data_reg);
129167514Skmacy		start_idx++;
130167514Skmacy	}
131167514Skmacy}
132167514Skmacy
133167514Skmacy/**
134167514Skmacy *	t3_mc7_bd_read - read from MC7 through backdoor accesses
135167514Skmacy *	@mc7: identifies MC7 to read from
136167514Skmacy *	@start: index of first 64-bit word to read
137167514Skmacy *	@n: number of 64-bit words to read
138167514Skmacy *	@buf: where to store the read result
139167514Skmacy *
140167514Skmacy *	Read n 64-bit words from MC7 starting at word start, using backdoor
141167514Skmacy *	accesses.
142167514Skmacy */
143167514Skmacyint t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
144167514Skmacy                   u64 *buf)
145167514Skmacy{
146167514Skmacy	static int shift[] = { 0, 0, 16, 24 };
147167514Skmacy	static int step[]  = { 0, 32, 16, 8 };
148167514Skmacy
149167514Skmacy	unsigned int size64 = mc7->size / 8;  /* # of 64-bit words */
150167514Skmacy	adapter_t *adap = mc7->adapter;
151167514Skmacy
152167514Skmacy	if (start >= size64 || start + n > size64)
153167514Skmacy		return -EINVAL;
154167514Skmacy
155167514Skmacy	start *= (8 << mc7->width);
156167514Skmacy	while (n--) {
157167514Skmacy		int i;
158167514Skmacy		u64 val64 = 0;
159167514Skmacy
160167514Skmacy		for (i = (1 << mc7->width) - 1; i >= 0; --i) {
161167514Skmacy			int attempts = 10;
162167514Skmacy			u32 val;
163167514Skmacy
164167514Skmacy			t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR,
165167514Skmacy				       start);
166167514Skmacy			t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
167167514Skmacy			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
168167514Skmacy			while ((val & F_BUSY) && attempts--)
169167514Skmacy				val = t3_read_reg(adap,
170167514Skmacy						  mc7->offset + A_MC7_BD_OP);
171167514Skmacy			if (val & F_BUSY)
172167514Skmacy				return -EIO;
173167514Skmacy
174167514Skmacy			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
175167514Skmacy			if (mc7->width == 0) {
176167514Skmacy				val64 = t3_read_reg(adap,
177167514Skmacy						mc7->offset + A_MC7_BD_DATA0);
178167514Skmacy				val64 |= (u64)val << 32;
179167514Skmacy			} else {
180167514Skmacy				if (mc7->width > 1)
181167514Skmacy					val >>= shift[mc7->width];
182167514Skmacy				val64 |= (u64)val << (step[mc7->width] * i);
183167514Skmacy			}
184167514Skmacy			start += 8;
185167514Skmacy		}
186167514Skmacy		*buf++ = val64;
187167514Skmacy	}
188167514Skmacy	return 0;
189167514Skmacy}
190167514Skmacy
191167514Skmacy/*
192197791Snp * Low-level I2C read and write routines.  These simply read and write a
193197791Snp * single byte with the option of indicating a "continue" if another operation
194197791Snp * is to be chained.  Generally most code will use higher-level routines to
195197791Snp * read and write to I2C Slave Devices.
196197791Snp */
197197791Snp#define I2C_ATTEMPTS 100
198197791Snp
199197791Snp/*
200197791Snp * Read an 8-bit value from the I2C bus.  If the "chained" parameter is
201197791Snp * non-zero then a STOP bit will not be written after the read command.  On
202197791Snp * error (the read timed out, etc.), a negative errno will be returned (e.g.
203197791Snp * -EAGAIN, etc.).  On success, the 8-bit value read from the I2C bus is
204197791Snp * stored into the buffer *valp and the value of the I2C ACK bit is returned
205197791Snp * as a 0/1 value.
206197791Snp */
207197791Snpint t3_i2c_read8(adapter_t *adapter, int chained, u8 *valp)
208197791Snp{
209197791Snp	int ret;
210197791Snp	u32 opval;
211197791Snp	MDIO_LOCK(adapter);
212197791Snp	t3_write_reg(adapter, A_I2C_OP,
213197791Snp		     F_I2C_READ | (chained ? F_I2C_CONT : 0));
214197791Snp	ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0,
215197791Snp				  I2C_ATTEMPTS, 10, &opval);
216197791Snp	if (ret >= 0) {
217197791Snp		ret = ((opval & F_I2C_ACK) == F_I2C_ACK);
218197791Snp		*valp = G_I2C_DATA(t3_read_reg(adapter, A_I2C_DATA));
219197791Snp	}
220197791Snp	MDIO_UNLOCK(adapter);
221197791Snp	return ret;
222197791Snp}
223197791Snp
224197791Snp/*
225197791Snp * Write an 8-bit value to the I2C bus.  If the "chained" parameter is
226197791Snp * non-zero, then a STOP bit will not be written after the write command.  On
227197791Snp * error (the write timed out, etc.), a negative errno will be returned (e.g.
228197791Snp * -EAGAIN, etc.).  On success, the value of the I2C ACK bit is returned as a
229197791Snp * 0/1 value.
230197791Snp */
231197791Snpint t3_i2c_write8(adapter_t *adapter, int chained, u8 val)
232197791Snp{
233197791Snp	int ret;
234197791Snp	u32 opval;
235197791Snp	MDIO_LOCK(adapter);
236197791Snp	t3_write_reg(adapter, A_I2C_DATA, V_I2C_DATA(val));
237197791Snp	t3_write_reg(adapter, A_I2C_OP,
238197791Snp		     F_I2C_WRITE | (chained ? F_I2C_CONT : 0));
239197791Snp	ret = t3_wait_op_done_val(adapter, A_I2C_OP, F_I2C_BUSY, 0,
240197791Snp				  I2C_ATTEMPTS, 10, &opval);
241197791Snp	if (ret >= 0)
242197791Snp		ret = ((opval & F_I2C_ACK) == F_I2C_ACK);
243197791Snp	MDIO_UNLOCK(adapter);
244197791Snp	return ret;
245197791Snp}
246197791Snp
247197791Snp/*
248167514Skmacy * Initialize MI1.
249167514Skmacy */
250167514Skmacystatic void mi1_init(adapter_t *adap, const struct adapter_info *ai)
251167514Skmacy{
252167514Skmacy        u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
253189643Sgnn        u32 val = F_PREEN | V_CLKDIV(clkdiv);
254167514Skmacy
255167514Skmacy        t3_write_reg(adap, A_MI1_CFG, val);
256167514Skmacy}
257167514Skmacy
258170654Skmacy#define MDIO_ATTEMPTS 20
259167514Skmacy
260167514Skmacy/*
261189643Sgnn * MI1 read/write operations for clause 22 PHYs.
262167514Skmacy */
263189643Sgnnint t3_mi1_read(adapter_t *adapter, int phy_addr, int mmd_addr,
264189643Sgnn		int reg_addr, unsigned int *valp)
265167514Skmacy{
266167514Skmacy	int ret;
267167514Skmacy	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
268167514Skmacy
269167514Skmacy	if (mmd_addr)
270167514Skmacy		return -EINVAL;
271167514Skmacy
272167514Skmacy	MDIO_LOCK(adapter);
273189643Sgnn	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
274167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
275167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
276170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
277167514Skmacy	if (!ret)
278167514Skmacy		*valp = t3_read_reg(adapter, A_MI1_DATA);
279167514Skmacy	MDIO_UNLOCK(adapter);
280167514Skmacy	return ret;
281167514Skmacy}
282167514Skmacy
283189643Sgnnint t3_mi1_write(adapter_t *adapter, int phy_addr, int mmd_addr,
284189643Sgnn		 int reg_addr, unsigned int val)
285167514Skmacy{
286167514Skmacy	int ret;
287167514Skmacy	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
288167514Skmacy
289167514Skmacy	if (mmd_addr)
290167514Skmacy		return -EINVAL;
291167514Skmacy
292167514Skmacy	MDIO_LOCK(adapter);
293189643Sgnn	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), V_ST(1));
294167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
295167514Skmacy	t3_write_reg(adapter, A_MI1_DATA, val);
296167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
297170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
298167514Skmacy	MDIO_UNLOCK(adapter);
299167514Skmacy	return ret;
300167514Skmacy}
301167514Skmacy
302167514Skmacystatic struct mdio_ops mi1_mdio_ops = {
303189643Sgnn	t3_mi1_read,
304189643Sgnn	t3_mi1_write
305167514Skmacy};
306167514Skmacy
307167514Skmacy/*
308189643Sgnn * MI1 read/write operations for clause 45 PHYs.
309167514Skmacy */
310167514Skmacystatic int mi1_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr,
311167514Skmacy			int reg_addr, unsigned int *valp)
312167514Skmacy{
313167514Skmacy	int ret;
314167514Skmacy	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
315167514Skmacy
316167514Skmacy	MDIO_LOCK(adapter);
317189643Sgnn	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0);
318167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
319167514Skmacy	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
320167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
321170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
322167514Skmacy	if (!ret) {
323167514Skmacy		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
324167514Skmacy		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
325170654Skmacy				      MDIO_ATTEMPTS, 10);
326167514Skmacy		if (!ret)
327167514Skmacy			*valp = t3_read_reg(adapter, A_MI1_DATA);
328167514Skmacy	}
329167514Skmacy	MDIO_UNLOCK(adapter);
330167514Skmacy	return ret;
331167514Skmacy}
332167514Skmacy
333167514Skmacystatic int mi1_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
334167514Skmacy			 int reg_addr, unsigned int val)
335167514Skmacy{
336167514Skmacy	int ret;
337167514Skmacy	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
338167514Skmacy
339167514Skmacy	MDIO_LOCK(adapter);
340189643Sgnn	t3_set_reg_field(adapter, A_MI1_CFG, V_ST(M_ST), 0);
341167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
342167514Skmacy	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
343167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
344170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
345167514Skmacy	if (!ret) {
346167514Skmacy		t3_write_reg(adapter, A_MI1_DATA, val);
347167514Skmacy		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
348167514Skmacy		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
349170654Skmacy				      MDIO_ATTEMPTS, 10);
350167514Skmacy	}
351167514Skmacy	MDIO_UNLOCK(adapter);
352167514Skmacy	return ret;
353167514Skmacy}
354167514Skmacy
355167514Skmacystatic struct mdio_ops mi1_mdio_ext_ops = {
356167514Skmacy	mi1_ext_read,
357167514Skmacy	mi1_ext_write
358167514Skmacy};
359167514Skmacy
360167514Skmacy/**
361167514Skmacy *	t3_mdio_change_bits - modify the value of a PHY register
362167514Skmacy *	@phy: the PHY to operate on
363167514Skmacy *	@mmd: the device address
364167514Skmacy *	@reg: the register address
365167514Skmacy *	@clear: what part of the register value to mask off
366167514Skmacy *	@set: what part of the register value to set
367167514Skmacy *
368167514Skmacy *	Changes the value of a PHY register by applying a mask to its current
369167514Skmacy *	value and ORing the result with a new value.
370167514Skmacy */
371167514Skmacyint t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
372167514Skmacy			unsigned int set)
373167514Skmacy{
374167514Skmacy	int ret;
375167514Skmacy	unsigned int val;
376167514Skmacy
377167514Skmacy	ret = mdio_read(phy, mmd, reg, &val);
378167514Skmacy	if (!ret) {
379167514Skmacy		val &= ~clear;
380167514Skmacy		ret = mdio_write(phy, mmd, reg, val | set);
381167514Skmacy	}
382167514Skmacy	return ret;
383167514Skmacy}
384167514Skmacy
385167514Skmacy/**
386167514Skmacy *	t3_phy_reset - reset a PHY block
387167514Skmacy *	@phy: the PHY to operate on
388167514Skmacy *	@mmd: the device address of the PHY block to reset
389167514Skmacy *	@wait: how long to wait for the reset to complete in 1ms increments
390167514Skmacy *
391167514Skmacy *	Resets a PHY block and optionally waits for the reset to complete.
392167514Skmacy *	@mmd should be 0 for 10/100/1000 PHYs and the device address to reset
393167514Skmacy *	for 10G PHYs.
394167514Skmacy */
395167514Skmacyint t3_phy_reset(struct cphy *phy, int mmd, int wait)
396167514Skmacy{
397167514Skmacy	int err;
398167514Skmacy	unsigned int ctl;
399167514Skmacy
400167514Skmacy	err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET);
401167514Skmacy	if (err || !wait)
402167514Skmacy		return err;
403167514Skmacy
404167514Skmacy	do {
405167514Skmacy		err = mdio_read(phy, mmd, MII_BMCR, &ctl);
406167514Skmacy		if (err)
407167514Skmacy			return err;
408167514Skmacy		ctl &= BMCR_RESET;
409167514Skmacy		if (ctl)
410171471Skmacy			msleep(1);
411167514Skmacy	} while (ctl && --wait);
412167514Skmacy
413167514Skmacy	return ctl ? -1 : 0;
414167514Skmacy}
415167514Skmacy
416167514Skmacy/**
417167514Skmacy *	t3_phy_advertise - set the PHY advertisement registers for autoneg
418167514Skmacy *	@phy: the PHY to operate on
419167514Skmacy *	@advert: bitmap of capabilities the PHY should advertise
420167514Skmacy *
421167514Skmacy *	Sets a 10/100/1000 PHY's advertisement registers to advertise the
422167514Skmacy *	requested capabilities.
423167514Skmacy */
424167514Skmacyint t3_phy_advertise(struct cphy *phy, unsigned int advert)
425167514Skmacy{
426167514Skmacy	int err;
427167514Skmacy	unsigned int val = 0;
428167514Skmacy
429167514Skmacy	err = mdio_read(phy, 0, MII_CTRL1000, &val);
430167514Skmacy	if (err)
431167514Skmacy		return err;
432167514Skmacy
433167514Skmacy	val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
434167514Skmacy	if (advert & ADVERTISED_1000baseT_Half)
435167514Skmacy		val |= ADVERTISE_1000HALF;
436167514Skmacy	if (advert & ADVERTISED_1000baseT_Full)
437167514Skmacy		val |= ADVERTISE_1000FULL;
438167514Skmacy
439167514Skmacy	err = mdio_write(phy, 0, MII_CTRL1000, val);
440167514Skmacy	if (err)
441167514Skmacy		return err;
442167514Skmacy
443167514Skmacy	val = 1;
444167514Skmacy	if (advert & ADVERTISED_10baseT_Half)
445167514Skmacy		val |= ADVERTISE_10HALF;
446167514Skmacy	if (advert & ADVERTISED_10baseT_Full)
447167514Skmacy		val |= ADVERTISE_10FULL;
448167514Skmacy	if (advert & ADVERTISED_100baseT_Half)
449167514Skmacy		val |= ADVERTISE_100HALF;
450167514Skmacy	if (advert & ADVERTISED_100baseT_Full)
451167514Skmacy		val |= ADVERTISE_100FULL;
452167514Skmacy	if (advert & ADVERTISED_Pause)
453167514Skmacy		val |= ADVERTISE_PAUSE_CAP;
454167514Skmacy	if (advert & ADVERTISED_Asym_Pause)
455167514Skmacy		val |= ADVERTISE_PAUSE_ASYM;
456167514Skmacy	return mdio_write(phy, 0, MII_ADVERTISE, val);
457167514Skmacy}
458167514Skmacy
459167514Skmacy/**
460176472Skmacy *	t3_phy_advertise_fiber - set fiber PHY advertisement register
461176472Skmacy *	@phy: the PHY to operate on
462176472Skmacy *	@advert: bitmap of capabilities the PHY should advertise
463176472Skmacy *
464176472Skmacy *	Sets a fiber PHY's advertisement register to advertise the
465176472Skmacy *	requested capabilities.
466176472Skmacy */
467176472Skmacyint t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert)
468176472Skmacy{
469176472Skmacy	unsigned int val = 0;
470176472Skmacy
471176472Skmacy	if (advert & ADVERTISED_1000baseT_Half)
472176472Skmacy		val |= ADVERTISE_1000XHALF;
473176472Skmacy	if (advert & ADVERTISED_1000baseT_Full)
474176472Skmacy		val |= ADVERTISE_1000XFULL;
475176472Skmacy	if (advert & ADVERTISED_Pause)
476176472Skmacy		val |= ADVERTISE_1000XPAUSE;
477176472Skmacy	if (advert & ADVERTISED_Asym_Pause)
478176472Skmacy		val |= ADVERTISE_1000XPSE_ASYM;
479176472Skmacy	return mdio_write(phy, 0, MII_ADVERTISE, val);
480176472Skmacy}
481176472Skmacy
482176472Skmacy/**
483167514Skmacy *	t3_set_phy_speed_duplex - force PHY speed and duplex
484167514Skmacy *	@phy: the PHY to operate on
485167514Skmacy *	@speed: requested PHY speed
486167514Skmacy *	@duplex: requested PHY duplex
487167514Skmacy *
488167514Skmacy *	Force a 10/100/1000 PHY's speed and duplex.  This also disables
489167514Skmacy *	auto-negotiation except for GigE, where auto-negotiation is mandatory.
490167514Skmacy */
491167514Skmacyint t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
492167514Skmacy{
493167514Skmacy	int err;
494167514Skmacy	unsigned int ctl;
495167514Skmacy
496167514Skmacy	err = mdio_read(phy, 0, MII_BMCR, &ctl);
497167514Skmacy	if (err)
498167514Skmacy		return err;
499167514Skmacy
500167514Skmacy	if (speed >= 0) {
501167514Skmacy		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
502167514Skmacy		if (speed == SPEED_100)
503167514Skmacy			ctl |= BMCR_SPEED100;
504167514Skmacy		else if (speed == SPEED_1000)
505167514Skmacy			ctl |= BMCR_SPEED1000;
506167514Skmacy	}
507167514Skmacy	if (duplex >= 0) {
508167514Skmacy		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
509167514Skmacy		if (duplex == DUPLEX_FULL)
510167514Skmacy			ctl |= BMCR_FULLDPLX;
511167514Skmacy	}
512167514Skmacy	if (ctl & BMCR_SPEED1000)  /* auto-negotiation required for GigE */
513167514Skmacy		ctl |= BMCR_ANENABLE;
514167514Skmacy	return mdio_write(phy, 0, MII_BMCR, ctl);
515167514Skmacy}
516167514Skmacy
517180583Skmacyint t3_phy_lasi_intr_enable(struct cphy *phy)
518180583Skmacy{
519180583Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
520180583Skmacy}
521180583Skmacy
522180583Skmacyint t3_phy_lasi_intr_disable(struct cphy *phy)
523180583Skmacy{
524180583Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
525180583Skmacy}
526180583Skmacy
527180583Skmacyint t3_phy_lasi_intr_clear(struct cphy *phy)
528180583Skmacy{
529180583Skmacy	u32 val;
530180583Skmacy
531180583Skmacy	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
532180583Skmacy}
533180583Skmacy
534180583Skmacyint t3_phy_lasi_intr_handler(struct cphy *phy)
535180583Skmacy{
536180583Skmacy	unsigned int status;
537180583Skmacy	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
538180583Skmacy
539180583Skmacy	if (err)
540180583Skmacy		return err;
541180583Skmacy	return (status & 1) ?  cphy_cause_link_change : 0;
542180583Skmacy}
543180583Skmacy
544167514Skmacystatic struct adapter_info t3_adap_info[] = {
545189643Sgnn	{ 1, 1, 0,
546167514Skmacy	  F_GPIO2_OEN | F_GPIO4_OEN |
547180583Skmacy	  F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
548167514Skmacy	  &mi1_mdio_ops, "Chelsio PE9000" },
549189643Sgnn	{ 1, 1, 0,
550167514Skmacy	  F_GPIO2_OEN | F_GPIO4_OEN |
551180583Skmacy	  F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
552167514Skmacy	  &mi1_mdio_ops, "Chelsio T302" },
553189643Sgnn	{ 1, 0, 0,
554167514Skmacy	  F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
555176472Skmacy	  F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
556180583Skmacy	  { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
557167514Skmacy	  &mi1_mdio_ext_ops, "Chelsio T310" },
558189643Sgnn	{ 1, 1, 0,
559167514Skmacy	  F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
560167514Skmacy	  F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
561180583Skmacy	  F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
562180583Skmacy	  { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
563167514Skmacy	  &mi1_mdio_ext_ops, "Chelsio T320" },
564189643Sgnn	{ 4, 0, 0,
565170654Skmacy	  F_GPIO5_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO5_OUT_VAL |
566170654Skmacy	  F_GPIO6_OUT_VAL | F_GPIO7_OUT_VAL,
567180583Skmacy	  { S_GPIO1, S_GPIO2, S_GPIO3, S_GPIO4 }, SUPPORTED_AUI,
568170654Skmacy	  &mi1_mdio_ops, "Chelsio T304" },
569185662Sgnn	{ 0 },
570189643Sgnn	{ 1, 0, 0,
571185662Sgnn	  F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
572185662Sgnn	  F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
573185662Sgnn	  { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
574197791Snp	  &mi1_mdio_ext_ops, "Chelsio T310" },
575197791Snp	{ 1, 0, 0,
576197791Snp	  F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
577197791Snp	  F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL,
578197791Snp	  { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
579197791Snp	  &mi1_mdio_ext_ops, "Chelsio N320E-G2" },
580167514Skmacy};
581167514Skmacy
582167514Skmacy/*
583167514Skmacy * Return the adapter_info structure with a given index.  Out-of-range indices
584167514Skmacy * return NULL.
585167514Skmacy */
586167514Skmacyconst struct adapter_info *t3_get_adapter_info(unsigned int id)
587167514Skmacy{
588167514Skmacy	return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
589167514Skmacy}
590167514Skmacy
591181614Skmacystruct port_type_info {
592197791Snp	int (*phy_prep)(pinfo_t *pinfo, int phy_addr,
593181614Skmacy			const struct mdio_ops *ops);
594181614Skmacy};
595181614Skmacy
596167514Skmacystatic struct port_type_info port_types[] = {
597171471Skmacy	{ NULL },
598176472Skmacy	{ t3_ael1002_phy_prep },
599176472Skmacy	{ t3_vsc8211_phy_prep },
600176472Skmacy	{ t3_mv88e1xxx_phy_prep },
601176472Skmacy	{ t3_xaui_direct_phy_prep },
602180583Skmacy	{ t3_ael2005_phy_prep },
603176472Skmacy	{ t3_qt2045_phy_prep },
604176472Skmacy	{ t3_ael1006_phy_prep },
605180583Skmacy	{ t3_tn1010_phy_prep },
606197791Snp	{ t3_aq100x_phy_prep },
607197791Snp	{ t3_ael2020_phy_prep },
608167514Skmacy};
609167514Skmacy
610167514Skmacy#define VPD_ENTRY(name, len) \
611176472Skmacy	u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
612167514Skmacy
613167514Skmacy/*
614167514Skmacy * Partial EEPROM Vital Product Data structure.  Includes only the ID and
615167514Skmacy * VPD-R sections.
616167514Skmacy */
617167514Skmacystruct t3_vpd {
618167514Skmacy	u8  id_tag;
619167514Skmacy	u8  id_len[2];
620167514Skmacy	u8  id_data[16];
621167514Skmacy	u8  vpdr_tag;
622167514Skmacy	u8  vpdr_len[2];
623167514Skmacy	VPD_ENTRY(pn, 16);                     /* part number */
624185157Sgnn	VPD_ENTRY(ec, ECNUM_LEN);              /* EC level */
625172096Skmacy	VPD_ENTRY(sn, SERNUM_LEN);             /* serial number */
626167514Skmacy	VPD_ENTRY(na, 12);                     /* MAC address base */
627167514Skmacy	VPD_ENTRY(cclk, 6);                    /* core clock */
628167514Skmacy	VPD_ENTRY(mclk, 6);                    /* mem clock */
629167514Skmacy	VPD_ENTRY(uclk, 6);                    /* uP clk */
630167514Skmacy	VPD_ENTRY(mdc, 6);                     /* MDIO clk */
631167514Skmacy	VPD_ENTRY(mt, 2);                      /* mem timing */
632167514Skmacy	VPD_ENTRY(xaui0cfg, 6);                /* XAUI0 config */
633167514Skmacy	VPD_ENTRY(xaui1cfg, 6);                /* XAUI1 config */
634167514Skmacy	VPD_ENTRY(port0, 2);                   /* PHY0 complex */
635167514Skmacy	VPD_ENTRY(port1, 2);                   /* PHY1 complex */
636167514Skmacy	VPD_ENTRY(port2, 2);                   /* PHY2 complex */
637167514Skmacy	VPD_ENTRY(port3, 2);                   /* PHY3 complex */
638167514Skmacy	VPD_ENTRY(rv, 1);                      /* csum */
639167514Skmacy	u32 pad;                  /* for multiple-of-4 sizing and alignment */
640167514Skmacy};
641167514Skmacy
642181614Skmacy#define EEPROM_MAX_POLL   40
643167514Skmacy#define EEPROM_STAT_ADDR  0x4000
644167514Skmacy#define VPD_BASE          0xc00
645167514Skmacy
646167514Skmacy/**
647167514Skmacy *	t3_seeprom_read - read a VPD EEPROM location
648167514Skmacy *	@adapter: adapter to read
649167514Skmacy *	@addr: EEPROM address
650167514Skmacy *	@data: where to store the read data
651167514Skmacy *
652167514Skmacy *	Read a 32-bit word from a location in VPD EEPROM using the card's PCI
653167514Skmacy *	VPD ROM capability.  A zero is written to the flag bit when the
654167514Skmacy *	addres is written to the control register.  The hardware device will
655167514Skmacy *	set the flag to 1 when 4 bytes have been read into the data register.
656167514Skmacy */
657167514Skmacyint t3_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
658167514Skmacy{
659167514Skmacy	u16 val;
660167514Skmacy	int attempts = EEPROM_MAX_POLL;
661167514Skmacy	unsigned int base = adapter->params.pci.vpd_cap_addr;
662167514Skmacy
663167514Skmacy	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
664167514Skmacy		return -EINVAL;
665167514Skmacy
666167514Skmacy	t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR, (u16)addr);
667167514Skmacy	do {
668167514Skmacy		udelay(10);
669167514Skmacy		t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val);
670167514Skmacy	} while (!(val & PCI_VPD_ADDR_F) && --attempts);
671167514Skmacy
672167514Skmacy	if (!(val & PCI_VPD_ADDR_F)) {
673167514Skmacy		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
674167514Skmacy		return -EIO;
675167514Skmacy	}
676167514Skmacy	t3_os_pci_read_config_4(adapter, base + PCI_VPD_DATA, data);
677167514Skmacy	*data = le32_to_cpu(*data);
678167514Skmacy	return 0;
679167514Skmacy}
680167514Skmacy
681167514Skmacy/**
682167514Skmacy *	t3_seeprom_write - write a VPD EEPROM location
683167514Skmacy *	@adapter: adapter to write
684167514Skmacy *	@addr: EEPROM address
685167514Skmacy *	@data: value to write
686167514Skmacy *
687167514Skmacy *	Write a 32-bit word to a location in VPD EEPROM using the card's PCI
688167514Skmacy *	VPD ROM capability.
689167514Skmacy */
690167514Skmacyint t3_seeprom_write(adapter_t *adapter, u32 addr, u32 data)
691167514Skmacy{
692167514Skmacy	u16 val;
693167514Skmacy	int attempts = EEPROM_MAX_POLL;
694167514Skmacy	unsigned int base = adapter->params.pci.vpd_cap_addr;
695167514Skmacy
696167514Skmacy	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
697167514Skmacy		return -EINVAL;
698167514Skmacy
699167514Skmacy	t3_os_pci_write_config_4(adapter, base + PCI_VPD_DATA,
700167514Skmacy				 cpu_to_le32(data));
701167514Skmacy	t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR,
702167514Skmacy				 (u16)addr | PCI_VPD_ADDR_F);
703167514Skmacy	do {
704171471Skmacy		msleep(1);
705167514Skmacy		t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val);
706167514Skmacy	} while ((val & PCI_VPD_ADDR_F) && --attempts);
707167514Skmacy
708167514Skmacy	if (val & PCI_VPD_ADDR_F) {
709167514Skmacy		CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
710167514Skmacy		return -EIO;
711167514Skmacy	}
712167514Skmacy	return 0;
713167514Skmacy}
714167514Skmacy
715167514Skmacy/**
716167514Skmacy *	t3_seeprom_wp - enable/disable EEPROM write protection
717167514Skmacy *	@adapter: the adapter
718167514Skmacy *	@enable: 1 to enable write protection, 0 to disable it
719167514Skmacy *
720167514Skmacy *	Enables or disables write protection on the serial EEPROM.
721167514Skmacy */
722167514Skmacyint t3_seeprom_wp(adapter_t *adapter, int enable)
723167514Skmacy{
724167514Skmacy	return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
725167514Skmacy}
726167514Skmacy
727167514Skmacy/*
728167514Skmacy * Convert a character holding a hex digit to a number.
729167514Skmacy */
730167514Skmacystatic unsigned int hex2int(unsigned char c)
731167514Skmacy{
732167514Skmacy	return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
733167514Skmacy}
734167514Skmacy
735167514Skmacy/**
736197791Snp * 	get_desc_len - get the length of a vpd descriptor.
737197791Snp *	@adapter: the adapter
738197791Snp *	@offset: first byte offset of the vpd descriptor
739197791Snp *
740197791Snp *	Retrieves the length of the small/large resource
741197791Snp *	data type starting at offset.
742197791Snp */
743197791Snpstatic int get_desc_len(adapter_t *adapter, u32 offset)
744197791Snp{
745197791Snp	u32 read_offset, tmp, shift, len = 0;
746197791Snp	u8 tag, buf[8];
747197791Snp	int ret;
748197791Snp
749197791Snp	read_offset = offset & 0xfffffffc;
750197791Snp	shift = offset & 0x03;
751197791Snp
752197791Snp	ret = t3_seeprom_read(adapter, read_offset, &tmp);
753197791Snp	if (ret < 0)
754197791Snp		return ret;
755197791Snp
756197791Snp	*((u32 *)buf) = cpu_to_le32(tmp);
757197791Snp
758197791Snp	tag = buf[shift];
759197791Snp	if (tag & 0x80) {
760197791Snp		ret = t3_seeprom_read(adapter, read_offset + 4, &tmp);
761197791Snp		if (ret < 0)
762197791Snp			return ret;
763197791Snp
764197791Snp		*((u32 *)(&buf[4])) = cpu_to_le32(tmp);
765197791Snp		len = (buf[shift + 1] & 0xff) +
766197791Snp		      ((buf[shift+2] << 8) & 0xff00) + 3;
767197791Snp	} else
768197791Snp		len = (tag & 0x07) + 1;
769197791Snp
770197791Snp	return len;
771197791Snp}
772197791Snp
773197791Snp/**
774197791Snp *	is_end_tag - Check if a vpd tag is the end tag.
775197791Snp *	@adapter: the adapter
776197791Snp *	@offset: first byte offset of the tag
777197791Snp *
778197791Snp *	Checks if the tag located at offset is the end tag.
779197791Snp */
780197791Snpstatic int is_end_tag(adapter_t * adapter, u32 offset)
781197791Snp{
782197791Snp	u32 read_offset, shift, ret, tmp;
783197791Snp	u8 buf[4];
784197791Snp
785197791Snp	read_offset = offset & 0xfffffffc;
786197791Snp	shift = offset & 0x03;
787197791Snp
788197791Snp	ret = t3_seeprom_read(adapter, read_offset, &tmp);
789197791Snp	if (ret)
790197791Snp		return ret;
791197791Snp	*((u32 *)buf) = cpu_to_le32(tmp);
792197791Snp
793197791Snp	if (buf[shift] == 0x78)
794197791Snp		return 1;
795197791Snp	else
796197791Snp		return 0;
797197791Snp}
798197791Snp
799197791Snp/**
800197791Snp *	t3_get_vpd_len - computes the length of a vpd structure
801197791Snp *	@adapter: the adapter
802197791Snp *	@vpd: contains the offset of first byte of vpd
803197791Snp *
804197791Snp *	Computes the lentgh of the vpd structure starting at vpd->offset.
805197791Snp */
806197791Snp
807197791Snpint t3_get_vpd_len(adapter_t * adapter, struct generic_vpd *vpd)
808197791Snp{
809197791Snp	u32 len=0, offset;
810197791Snp	int inc, ret;
811197791Snp
812197791Snp	offset = vpd->offset;
813197791Snp
814197791Snp	while (offset < (vpd->offset + MAX_VPD_BYTES)) {
815197791Snp		ret = is_end_tag(adapter, offset);
816197791Snp		if (ret < 0)
817197791Snp			return ret;
818197791Snp		else if (ret == 1)
819197791Snp			break;
820197791Snp
821197791Snp		inc = get_desc_len(adapter, offset);
822197791Snp		if (inc < 0)
823197791Snp			return inc;
824197791Snp		len += inc;
825197791Snp		offset += inc;
826197791Snp	}
827197791Snp	return (len + 1);
828197791Snp}
829197791Snp
830197791Snp/**
831197791Snp *	t3_read_vpd - reads the stream of bytes containing a vpd structure
832197791Snp *	@adapter: the adapter
833197791Snp *	@vpd: contains a buffer that would hold the stream of bytes
834197791Snp *
835197791Snp *	Reads the vpd structure starting at vpd->offset into vpd->data,
836197791Snp *	the length of the byte stream to read is vpd->len.
837197791Snp */
838197791Snp
839197791Snpint t3_read_vpd(adapter_t *adapter, struct generic_vpd *vpd)
840197791Snp{
841197791Snp	u32 i, ret;
842197791Snp
843197791Snp	for (i = 0; i < vpd->len; i += 4) {
844197791Snp		ret = t3_seeprom_read(adapter, vpd->offset + i,
845197791Snp				      (u32 *) &(vpd->data[i]));
846197791Snp		if (ret)
847197791Snp			return ret;
848197791Snp	}
849197791Snp
850197791Snp	return 0;
851197791Snp}
852197791Snp
853197791Snp
854197791Snp/**
855167514Skmacy *	get_vpd_params - read VPD parameters from VPD EEPROM
856167514Skmacy *	@adapter: adapter to read
857167514Skmacy *	@p: where to store the parameters
858167514Skmacy *
859167514Skmacy *	Reads card parameters stored in VPD EEPROM.
860167514Skmacy */
861167514Skmacystatic int get_vpd_params(adapter_t *adapter, struct vpd_params *p)
862167514Skmacy{
863167514Skmacy	int i, addr, ret;
864167514Skmacy	struct t3_vpd vpd;
865167514Skmacy
866167514Skmacy	/*
867167514Skmacy	 * Card information is normally at VPD_BASE but some early cards had
868167514Skmacy	 * it at 0.
869167514Skmacy	 */
870167514Skmacy	ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
871167514Skmacy	if (ret)
872167514Skmacy		return ret;
873167514Skmacy	addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
874167514Skmacy
875167514Skmacy	for (i = 0; i < sizeof(vpd); i += 4) {
876167514Skmacy		ret = t3_seeprom_read(adapter, addr + i,
877167514Skmacy				      (u32 *)((u8 *)&vpd + i));
878167514Skmacy		if (ret)
879167514Skmacy			return ret;
880167514Skmacy	}
881167514Skmacy
882167514Skmacy	p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
883167514Skmacy	p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
884167514Skmacy	p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
885167514Skmacy	p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
886167514Skmacy	p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
887172096Skmacy	memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
888185157Sgnn	memcpy(p->ec, vpd.ec_data, ECNUM_LEN);
889167514Skmacy
890167514Skmacy	/* Old eeproms didn't have port information */
891167514Skmacy	if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
892167514Skmacy		p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
893167514Skmacy		p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
894167514Skmacy	} else {
895167514Skmacy		p->port_type[0] = (u8)hex2int(vpd.port0_data[0]);
896167514Skmacy		p->port_type[1] = (u8)hex2int(vpd.port1_data[0]);
897170654Skmacy		p->port_type[2] = (u8)hex2int(vpd.port2_data[0]);
898170654Skmacy		p->port_type[3] = (u8)hex2int(vpd.port3_data[0]);
899167514Skmacy		p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
900167514Skmacy		p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
901167514Skmacy	}
902167514Skmacy
903167514Skmacy	for (i = 0; i < 6; i++)
904167514Skmacy		p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
905167514Skmacy				 hex2int(vpd.na_data[2 * i + 1]);
906167514Skmacy	return 0;
907167514Skmacy}
908167514Skmacy
909176472Skmacy/* BIOS boot header */
910176472Skmacytypedef struct boot_header_s {
911176472Skmacy	u8	signature[2];	/* signature */
912176472Skmacy	u8	length;		/* image length (include header) */
913176472Skmacy	u8	offset[4];	/* initialization vector */
914176472Skmacy	u8	reserved[19];	/* reserved */
915176472Skmacy	u8	exheader[2];	/* offset to expansion header */
916176472Skmacy} boot_header_t;
917176472Skmacy
918167514Skmacy/* serial flash and firmware constants */
919167514Skmacyenum {
920167514Skmacy	SF_ATTEMPTS = 5,           /* max retries for SF1 operations */
921167514Skmacy	SF_SEC_SIZE = 64 * 1024,   /* serial flash sector size */
922167514Skmacy	SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */
923167514Skmacy
924167514Skmacy	/* flash command opcodes */
925167514Skmacy	SF_PROG_PAGE    = 2,       /* program page */
926167514Skmacy	SF_WR_DISABLE   = 4,       /* disable writes */
927167514Skmacy	SF_RD_STATUS    = 5,       /* read status register */
928167514Skmacy	SF_WR_ENABLE    = 6,       /* enable writes */
929167514Skmacy	SF_RD_DATA_FAST = 0xb,     /* read flash */
930167514Skmacy	SF_ERASE_SECTOR = 0xd8,    /* erase sector */
931167514Skmacy
932167514Skmacy	FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */
933184861Skmacy	FW_VERS_ADDR = 0x7fffc,    /* flash address holding FW version */
934189643Sgnn	FW_VERS_ADDR_PRE8 = 0x77ffc,/* flash address holding FW version pre8 */
935176472Skmacy	FW_MIN_SIZE = 8,           /* at least version and csum */
936176472Skmacy	FW_MAX_SIZE = FW_VERS_ADDR - FW_FLASH_BOOT_ADDR,
937189643Sgnn	FW_MAX_SIZE_PRE8 = FW_VERS_ADDR_PRE8 - FW_FLASH_BOOT_ADDR,
938176472Skmacy
939176472Skmacy	BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */
940176472Skmacy	BOOT_SIGNATURE = 0xaa55,   /* signature of BIOS boot ROM */
941176472Skmacy	BOOT_SIZE_INC = 512,       /* image size measured in 512B chunks */
942176472Skmacy	BOOT_MIN_SIZE = sizeof(boot_header_t), /* at least basic header */
943189643Sgnn	BOOT_MAX_SIZE = 1024*BOOT_SIZE_INC /* 1 byte * length increment  */
944167514Skmacy};
945167514Skmacy
946167514Skmacy/**
947167514Skmacy *	sf1_read - read data from the serial flash
948167514Skmacy *	@adapter: the adapter
949167514Skmacy *	@byte_cnt: number of bytes to read
950167514Skmacy *	@cont: whether another operation will be chained
951167514Skmacy *	@valp: where to store the read data
952167514Skmacy *
953167514Skmacy *	Reads up to 4 bytes of data from the serial flash.  The location of
954167514Skmacy *	the read needs to be specified prior to calling this by issuing the
955167514Skmacy *	appropriate commands to the serial flash.
956167514Skmacy */
957167514Skmacystatic int sf1_read(adapter_t *adapter, unsigned int byte_cnt, int cont,
958167514Skmacy		    u32 *valp)
959167514Skmacy{
960167514Skmacy	int ret;
961167514Skmacy
962167514Skmacy	if (!byte_cnt || byte_cnt > 4)
963167514Skmacy		return -EINVAL;
964167514Skmacy	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
965167514Skmacy		return -EBUSY;
966167514Skmacy	t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
967167514Skmacy	ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
968167514Skmacy	if (!ret)
969167514Skmacy		*valp = t3_read_reg(adapter, A_SF_DATA);
970167514Skmacy	return ret;
971167514Skmacy}
972167514Skmacy
973167514Skmacy/**
974167514Skmacy *	sf1_write - write data to the serial flash
975167514Skmacy *	@adapter: the adapter
976167514Skmacy *	@byte_cnt: number of bytes to write
977167514Skmacy *	@cont: whether another operation will be chained
978167514Skmacy *	@val: value to write
979167514Skmacy *
980167514Skmacy *	Writes up to 4 bytes of data to the serial flash.  The location of
981167514Skmacy *	the write needs to be specified prior to calling this by issuing the
982167514Skmacy *	appropriate commands to the serial flash.
983167514Skmacy */
984167514Skmacystatic int sf1_write(adapter_t *adapter, unsigned int byte_cnt, int cont,
985167514Skmacy		     u32 val)
986167514Skmacy{
987167514Skmacy	if (!byte_cnt || byte_cnt > 4)
988167514Skmacy		return -EINVAL;
989167514Skmacy	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
990167514Skmacy		return -EBUSY;
991167514Skmacy	t3_write_reg(adapter, A_SF_DATA, val);
992167514Skmacy	t3_write_reg(adapter, A_SF_OP,
993167514Skmacy		     V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
994167514Skmacy	return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
995167514Skmacy}
996167514Skmacy
997167514Skmacy/**
998167514Skmacy *	flash_wait_op - wait for a flash operation to complete
999167514Skmacy *	@adapter: the adapter
1000167514Skmacy *	@attempts: max number of polls of the status register
1001167514Skmacy *	@delay: delay between polls in ms
1002167514Skmacy *
1003167514Skmacy *	Wait for a flash operation to complete by polling the status register.
1004167514Skmacy */
1005167514Skmacystatic int flash_wait_op(adapter_t *adapter, int attempts, int delay)
1006167514Skmacy{
1007167514Skmacy	int ret;
1008167514Skmacy	u32 status;
1009167514Skmacy
1010167514Skmacy	while (1) {
1011167514Skmacy		if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
1012167514Skmacy		    (ret = sf1_read(adapter, 1, 0, &status)) != 0)
1013167514Skmacy			return ret;
1014167514Skmacy		if (!(status & 1))
1015167514Skmacy			return 0;
1016167514Skmacy		if (--attempts == 0)
1017167514Skmacy			return -EAGAIN;
1018167514Skmacy		if (delay)
1019171471Skmacy			msleep(delay);
1020167514Skmacy	}
1021167514Skmacy}
1022167514Skmacy
1023167514Skmacy/**
1024167514Skmacy *	t3_read_flash - read words from serial flash
1025167514Skmacy *	@adapter: the adapter
1026167514Skmacy *	@addr: the start address for the read
1027167514Skmacy *	@nwords: how many 32-bit words to read
1028167514Skmacy *	@data: where to store the read data
1029167514Skmacy *	@byte_oriented: whether to store data as bytes or as words
1030167514Skmacy *
1031167514Skmacy *	Read the specified number of 32-bit words from the serial flash.
1032167514Skmacy *	If @byte_oriented is set the read data is stored as a byte array
1033167514Skmacy *	(i.e., big-endian), otherwise as 32-bit words in the platform's
1034167514Skmacy *	natural endianess.
1035167514Skmacy */
1036167514Skmacyint t3_read_flash(adapter_t *adapter, unsigned int addr, unsigned int nwords,
1037167514Skmacy		  u32 *data, int byte_oriented)
1038167514Skmacy{
1039167514Skmacy	int ret;
1040167514Skmacy
1041167514Skmacy	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
1042167514Skmacy		return -EINVAL;
1043167514Skmacy
1044167514Skmacy	addr = swab32(addr) | SF_RD_DATA_FAST;
1045167514Skmacy
1046167514Skmacy	if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
1047167514Skmacy	    (ret = sf1_read(adapter, 1, 1, data)) != 0)
1048167514Skmacy		return ret;
1049167514Skmacy
1050167514Skmacy	for ( ; nwords; nwords--, data++) {
1051167514Skmacy		ret = sf1_read(adapter, 4, nwords > 1, data);
1052167514Skmacy		if (ret)
1053167514Skmacy			return ret;
1054167514Skmacy		if (byte_oriented)
1055167514Skmacy			*data = htonl(*data);
1056167514Skmacy	}
1057167514Skmacy	return 0;
1058167514Skmacy}
1059167514Skmacy
1060167514Skmacy/**
1061167514Skmacy *	t3_write_flash - write up to a page of data to the serial flash
1062167514Skmacy *	@adapter: the adapter
1063167514Skmacy *	@addr: the start address to write
1064167514Skmacy *	@n: length of data to write
1065167514Skmacy *	@data: the data to write
1066176472Skmacy *	@byte_oriented: whether to store data as bytes or as words
1067167514Skmacy *
1068167514Skmacy *	Writes up to a page of data (256 bytes) to the serial flash starting
1069167514Skmacy *	at the given address.
1070176472Skmacy *	If @byte_oriented is set the write data is stored as a 32-bit
1071176472Skmacy *	big-endian array, otherwise in the processor's native endianess.
1072189643Sgnn *
1073167514Skmacy */
1074167514Skmacystatic int t3_write_flash(adapter_t *adapter, unsigned int addr,
1075176472Skmacy			  unsigned int n, const u8 *data,
1076176472Skmacy			  int byte_oriented)
1077167514Skmacy{
1078167514Skmacy	int ret;
1079167514Skmacy	u32 buf[64];
1080176472Skmacy	unsigned int c, left, val, offset = addr & 0xff;
1081167514Skmacy
1082167514Skmacy	if (addr + n > SF_SIZE || offset + n > 256)
1083167514Skmacy		return -EINVAL;
1084167514Skmacy
1085167514Skmacy	val = swab32(addr) | SF_PROG_PAGE;
1086167514Skmacy
1087167514Skmacy	if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
1088167514Skmacy	    (ret = sf1_write(adapter, 4, 1, val)) != 0)
1089167514Skmacy		return ret;
1090167514Skmacy
1091167514Skmacy	for (left = n; left; left -= c) {
1092167514Skmacy		c = min(left, 4U);
1093176472Skmacy		val = *(const u32*)data;
1094176472Skmacy		data += c;
1095176472Skmacy		if (byte_oriented)
1096176472Skmacy			val = htonl(val);
1097167514Skmacy
1098167514Skmacy		ret = sf1_write(adapter, c, c != left, val);
1099167514Skmacy		if (ret)
1100167514Skmacy			return ret;
1101167514Skmacy	}
1102167514Skmacy	if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
1103167514Skmacy		return ret;
1104167514Skmacy
1105167514Skmacy	/* Read the page to verify the write succeeded */
1106176472Skmacy	ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf,
1107176472Skmacy			    byte_oriented);
1108167514Skmacy	if (ret)
1109167514Skmacy		return ret;
1110167514Skmacy
1111167514Skmacy	if (memcmp(data - n, (u8 *)buf + offset, n))
1112167514Skmacy		return -EIO;
1113167514Skmacy	return 0;
1114167514Skmacy}
1115167514Skmacy
1116170654Skmacy/**
1117171471Skmacy *	t3_get_tp_version - read the tp sram version
1118171471Skmacy *	@adapter: the adapter
1119171471Skmacy *	@vers: where to place the version
1120171471Skmacy *
1121171471Skmacy *	Reads the protocol sram version from sram.
1122171471Skmacy */
1123171471Skmacyint t3_get_tp_version(adapter_t *adapter, u32 *vers)
1124171471Skmacy{
1125171471Skmacy	int ret;
1126171471Skmacy
1127171471Skmacy	/* Get version loaded in SRAM */
1128171471Skmacy	t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
1129171471Skmacy	ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
1130171471Skmacy			      1, 1, 5, 1);
1131171471Skmacy	if (ret)
1132171471Skmacy		return ret;
1133189643Sgnn
1134171471Skmacy	*vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
1135171471Skmacy
1136171471Skmacy	return 0;
1137171471Skmacy}
1138171471Skmacy
1139171471Skmacy/**
1140170654Skmacy *	t3_check_tpsram_version - read the tp sram version
1141170654Skmacy *	@adapter: the adapter
1142170654Skmacy *
1143170654Skmacy */
1144189643Sgnnint t3_check_tpsram_version(adapter_t *adapter)
1145170654Skmacy{
1146170654Skmacy	int ret;
1147170654Skmacy	u32 vers;
1148170654Skmacy	unsigned int major, minor;
1149170654Skmacy
1150176472Skmacy	if (adapter->params.rev == T3_REV_A)
1151176472Skmacy		return 0;
1152176472Skmacy
1153176472Skmacy
1154176472Skmacy	ret = t3_get_tp_version(adapter, &vers);
1155170654Skmacy	if (ret)
1156170654Skmacy		return ret;
1157189643Sgnn
1158170654Skmacy	vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
1159170654Skmacy
1160170654Skmacy	major = G_TP_VERSION_MAJOR(vers);
1161170654Skmacy	minor = G_TP_VERSION_MINOR(vers);
1162170654Skmacy
1163189643Sgnn	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
1164170654Skmacy		return 0;
1165176472Skmacy	else {
1166176472Skmacy		CH_ERR(adapter, "found wrong TP version (%u.%u), "
1167176472Skmacy		       "driver compiled for version %d.%d\n", major, minor,
1168176472Skmacy		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
1169176472Skmacy	}
1170170654Skmacy	return -EINVAL;
1171170654Skmacy}
1172170654Skmacy
1173170654Skmacy/**
1174189643Sgnn *	t3_check_tpsram - check if provided protocol SRAM
1175170654Skmacy *			  is compatible with this driver
1176170654Skmacy *	@adapter: the adapter
1177170654Skmacy *	@tp_sram: the firmware image to write
1178170654Skmacy *	@size: image size
1179170654Skmacy *
1180170654Skmacy *	Checks if an adapter's tp sram is compatible with the driver.
1181170654Skmacy *	Returns 0 if the versions are compatible, a negative error otherwise.
1182170654Skmacy */
1183171471Skmacyint t3_check_tpsram(adapter_t *adapter, const u8 *tp_sram, unsigned int size)
1184170654Skmacy{
1185170654Skmacy	u32 csum;
1186170654Skmacy	unsigned int i;
1187170654Skmacy	const u32 *p = (const u32 *)tp_sram;
1188170654Skmacy
1189170654Skmacy	/* Verify checksum */
1190170654Skmacy	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1191170654Skmacy		csum += ntohl(p[i]);
1192170654Skmacy	if (csum != 0xffffffff) {
1193170654Skmacy		CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
1194170654Skmacy		       csum);
1195170654Skmacy		return -EINVAL;
1196170654Skmacy	}
1197170654Skmacy
1198170654Skmacy	return 0;
1199170654Skmacy}
1200170654Skmacy
1201167514Skmacyenum fw_version_type {
1202167514Skmacy	FW_VERSION_N3,
1203167514Skmacy	FW_VERSION_T3
1204167514Skmacy};
1205167514Skmacy
1206167514Skmacy/**
1207167514Skmacy *	t3_get_fw_version - read the firmware version
1208167514Skmacy *	@adapter: the adapter
1209167514Skmacy *	@vers: where to place the version
1210167514Skmacy *
1211189643Sgnn *	Reads the FW version from flash. Note that we had to move the version
1212189643Sgnn *	due to FW size. If we don't find a valid FW version in the new location
1213189643Sgnn *	we fall back and read the old location.
1214167514Skmacy */
1215167514Skmacyint t3_get_fw_version(adapter_t *adapter, u32 *vers)
1216167514Skmacy{
1217184861Skmacy	int ret = t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
1218184861Skmacy	if (!ret && *vers != 0xffffffff)
1219184861Skmacy		return 0;
1220184861Skmacy	else
1221189643Sgnn		return t3_read_flash(adapter, FW_VERS_ADDR_PRE8, 1, vers, 0);
1222167514Skmacy}
1223167514Skmacy
1224167514Skmacy/**
1225167514Skmacy *	t3_check_fw_version - check if the FW is compatible with this driver
1226167514Skmacy *	@adapter: the adapter
1227167514Skmacy *
1228167514Skmacy *	Checks if an adapter's FW is compatible with the driver.  Returns 0
1229167514Skmacy *	if the versions are compatible, a negative error otherwise.
1230167514Skmacy */
1231189643Sgnnint t3_check_fw_version(adapter_t *adapter)
1232167514Skmacy{
1233167514Skmacy	int ret;
1234167514Skmacy	u32 vers;
1235167514Skmacy	unsigned int type, major, minor;
1236167514Skmacy
1237167514Skmacy	ret = t3_get_fw_version(adapter, &vers);
1238167514Skmacy	if (ret)
1239167514Skmacy		return ret;
1240167514Skmacy
1241167514Skmacy	type = G_FW_VERSION_TYPE(vers);
1242167514Skmacy	major = G_FW_VERSION_MAJOR(vers);
1243167514Skmacy	minor = G_FW_VERSION_MINOR(vers);
1244167514Skmacy
1245167746Skmacy	if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR &&
1246167746Skmacy	    minor == FW_VERSION_MINOR)
1247167514Skmacy		return 0;
1248167514Skmacy
1249189643Sgnn	else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR)
1250176472Skmacy		CH_WARN(adapter, "found old FW minor version(%u.%u), "
1251176472Skmacy		        "driver compiled for version %u.%u\n", major, minor,
1252176472Skmacy			FW_VERSION_MAJOR, FW_VERSION_MINOR);
1253189643Sgnn	else {
1254176472Skmacy		CH_WARN(adapter, "found newer FW version(%u.%u), "
1255176472Skmacy		        "driver compiled for version %u.%u\n", major, minor,
1256176472Skmacy			FW_VERSION_MAJOR, FW_VERSION_MINOR);
1257176472Skmacy			return 0;
1258176472Skmacy	}
1259167514Skmacy	return -EINVAL;
1260167514Skmacy}
1261167514Skmacy
1262167514Skmacy/**
1263167514Skmacy *	t3_flash_erase_sectors - erase a range of flash sectors
1264167514Skmacy *	@adapter: the adapter
1265167514Skmacy *	@start: the first sector to erase
1266167514Skmacy *	@end: the last sector to erase
1267167514Skmacy *
1268167514Skmacy *	Erases the sectors in the given range.
1269167514Skmacy */
1270167514Skmacystatic int t3_flash_erase_sectors(adapter_t *adapter, int start, int end)
1271167514Skmacy{
1272167514Skmacy	while (start <= end) {
1273167514Skmacy		int ret;
1274167514Skmacy
1275167514Skmacy		if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
1276167514Skmacy		    (ret = sf1_write(adapter, 4, 0,
1277167514Skmacy				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
1278167514Skmacy		    (ret = flash_wait_op(adapter, 5, 500)) != 0)
1279167514Skmacy			return ret;
1280167514Skmacy		start++;
1281167514Skmacy	}
1282167514Skmacy	return 0;
1283167514Skmacy}
1284167514Skmacy
1285167514Skmacy/*
1286167514Skmacy *	t3_load_fw - download firmware
1287167514Skmacy *	@adapter: the adapter
1288170654Skmacy *	@fw_data: the firmware image to write
1289167514Skmacy *	@size: image size
1290167514Skmacy *
1291167514Skmacy *	Write the supplied firmware image to the card's serial flash.
1292167514Skmacy *	The FW image has the following sections: @size - 8 bytes of code and
1293167514Skmacy *	data, followed by 4 bytes of FW version, followed by the 32-bit
1294167514Skmacy *	1's complement checksum of the whole image.
1295167514Skmacy */
1296167514Skmacyint t3_load_fw(adapter_t *adapter, const u8 *fw_data, unsigned int size)
1297167514Skmacy{
1298189643Sgnn	u32 version, csum, fw_version_addr;
1299167514Skmacy	unsigned int i;
1300167514Skmacy	const u32 *p = (const u32 *)fw_data;
1301167514Skmacy	int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
1302167514Skmacy
1303170654Skmacy	if ((size & 3) || size < FW_MIN_SIZE)
1304167514Skmacy		return -EINVAL;
1305176472Skmacy	if (size - 8 > FW_MAX_SIZE)
1306167514Skmacy		return -EFBIG;
1307167514Skmacy
1308189643Sgnn	version = ntohl(*(const u32 *)(fw_data + size - 8));
1309189643Sgnn	if (G_FW_VERSION_MAJOR(version) < 8) {
1310189643Sgnn
1311189643Sgnn		fw_version_addr = FW_VERS_ADDR_PRE8;
1312189643Sgnn
1313189643Sgnn		if (size - 8 > FW_MAX_SIZE_PRE8)
1314189643Sgnn			return -EFBIG;
1315189643Sgnn	} else
1316189643Sgnn		fw_version_addr = FW_VERS_ADDR;
1317189643Sgnn
1318167514Skmacy	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1319167514Skmacy		csum += ntohl(p[i]);
1320167514Skmacy	if (csum != 0xffffffff) {
1321167514Skmacy		CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
1322167514Skmacy		       csum);
1323167514Skmacy		return -EINVAL;
1324167514Skmacy	}
1325167514Skmacy
1326167514Skmacy	ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
1327167514Skmacy	if (ret)
1328167514Skmacy		goto out;
1329167514Skmacy
1330167514Skmacy	size -= 8;  /* trim off version and checksum */
1331167514Skmacy	for (addr = FW_FLASH_BOOT_ADDR; size; ) {
1332167514Skmacy		unsigned int chunk_size = min(size, 256U);
1333167514Skmacy
1334176472Skmacy		ret = t3_write_flash(adapter, addr, chunk_size, fw_data, 1);
1335167514Skmacy		if (ret)
1336167514Skmacy			goto out;
1337167514Skmacy
1338167514Skmacy		addr += chunk_size;
1339167514Skmacy		fw_data += chunk_size;
1340167514Skmacy		size -= chunk_size;
1341167514Skmacy	}
1342167514Skmacy
1343189643Sgnn	ret = t3_write_flash(adapter, fw_version_addr, 4, fw_data, 1);
1344167514Skmacyout:
1345167514Skmacy	if (ret)
1346167514Skmacy		CH_ERR(adapter, "firmware download failed, error %d\n", ret);
1347167514Skmacy	return ret;
1348167514Skmacy}
1349167514Skmacy
1350176472Skmacy/*
1351176472Skmacy *	t3_load_boot - download boot flash
1352176472Skmacy *	@adapter: the adapter
1353176472Skmacy *	@boot_data: the boot image to write
1354176472Skmacy *	@size: image size
1355176472Skmacy *
1356176472Skmacy *	Write the supplied boot image to the card's serial flash.
1357176472Skmacy *	The boot image has the following sections: a 28-byte header and the
1358176472Skmacy *	boot image.
1359176472Skmacy */
1360176472Skmacyint t3_load_boot(adapter_t *adapter, u8 *boot_data, unsigned int size)
1361176472Skmacy{
1362176472Skmacy	boot_header_t *header = (boot_header_t *)boot_data;
1363176472Skmacy	int ret;
1364176472Skmacy	unsigned int addr;
1365176472Skmacy	unsigned int boot_sector = BOOT_FLASH_BOOT_ADDR >> 16;
1366176472Skmacy	unsigned int boot_end = (BOOT_FLASH_BOOT_ADDR + size - 1) >> 16;
1367176472Skmacy
1368176472Skmacy	/*
1369176472Skmacy	 * Perform some primitive sanity testing to avoid accidentally
1370176472Skmacy	 * writing garbage over the boot sectors.  We ought to check for
1371176472Skmacy	 * more but it's not worth it for now ...
1372176472Skmacy	 */
1373176472Skmacy	if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) {
1374176472Skmacy		CH_ERR(adapter, "boot image too small/large\n");
1375176472Skmacy		return -EFBIG;
1376176472Skmacy	}
1377176472Skmacy	if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE) {
1378176472Skmacy		CH_ERR(adapter, "boot image missing signature\n");
1379176472Skmacy		return -EINVAL;
1380176472Skmacy	}
1381176472Skmacy	if (header->length * BOOT_SIZE_INC != size) {
1382176472Skmacy		CH_ERR(adapter, "boot image header length != image length\n");
1383176472Skmacy		return -EINVAL;
1384176472Skmacy	}
1385176472Skmacy
1386176472Skmacy	ret = t3_flash_erase_sectors(adapter, boot_sector, boot_end);
1387176472Skmacy	if (ret)
1388176472Skmacy		goto out;
1389176472Skmacy
1390176472Skmacy	for (addr = BOOT_FLASH_BOOT_ADDR; size; ) {
1391176472Skmacy		unsigned int chunk_size = min(size, 256U);
1392176472Skmacy
1393176472Skmacy		ret = t3_write_flash(adapter, addr, chunk_size, boot_data, 0);
1394176472Skmacy		if (ret)
1395176472Skmacy			goto out;
1396176472Skmacy
1397176472Skmacy		addr += chunk_size;
1398176472Skmacy		boot_data += chunk_size;
1399176472Skmacy		size -= chunk_size;
1400176472Skmacy	}
1401176472Skmacy
1402176472Skmacyout:
1403176472Skmacy	if (ret)
1404176472Skmacy		CH_ERR(adapter, "boot image download failed, error %d\n", ret);
1405176472Skmacy	return ret;
1406176472Skmacy}
1407176472Skmacy
1408167514Skmacy#define CIM_CTL_BASE 0x2000
1409167514Skmacy
1410167514Skmacy/**
1411167514Skmacy *	t3_cim_ctl_blk_read - read a block from CIM control region
1412167514Skmacy *	@adap: the adapter
1413167514Skmacy *	@addr: the start address within the CIM control region
1414167514Skmacy *	@n: number of words to read
1415167514Skmacy *	@valp: where to store the result
1416167514Skmacy *
1417167514Skmacy *	Reads a block of 4-byte words from the CIM control region.
1418167514Skmacy */
1419167514Skmacyint t3_cim_ctl_blk_read(adapter_t *adap, unsigned int addr, unsigned int n,
1420167514Skmacy			unsigned int *valp)
1421167514Skmacy{
1422167514Skmacy	int ret = 0;
1423167514Skmacy
1424167514Skmacy	if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1425167514Skmacy		return -EBUSY;
1426167514Skmacy
1427167514Skmacy	for ( ; !ret && n--; addr += 4) {
1428167514Skmacy		t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
1429167514Skmacy		ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1430167514Skmacy				      0, 5, 2);
1431167514Skmacy		if (!ret)
1432167514Skmacy			*valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
1433167514Skmacy	}
1434167514Skmacy	return ret;
1435167514Skmacy}
1436167514Skmacy
1437189643Sgnnstatic void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg,
1438189643Sgnn			       u32 *rx_hash_high, u32 *rx_hash_low)
1439189643Sgnn{
1440189643Sgnn	/* stop Rx unicast traffic */
1441189643Sgnn	t3_mac_disable_exact_filters(mac);
1442189643Sgnn
1443189643Sgnn	/* stop broadcast, multicast, promiscuous mode traffic */
1444212710Snp	*rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG + mac->offset);
1445212710Snp	t3_set_reg_field(mac->adapter, A_XGM_RX_CFG + mac->offset,
1446189643Sgnn			 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
1447189643Sgnn			 F_DISBCAST);
1448189643Sgnn
1449212710Snp	*rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH +
1450212710Snp	    mac->offset);
1451212710Snp	t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH + mac->offset, 0);
1452189643Sgnn
1453212710Snp	*rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW +
1454212710Snp	    mac->offset);
1455212710Snp	t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW + mac->offset, 0);
1456189643Sgnn
1457189643Sgnn	/* Leave time to drain max RX fifo */
1458189643Sgnn	msleep(1);
1459189643Sgnn}
1460189643Sgnn
1461189643Sgnnstatic void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg,
1462189643Sgnn			       u32 rx_hash_high, u32 rx_hash_low)
1463189643Sgnn{
1464189643Sgnn	t3_mac_enable_exact_filters(mac);
1465212710Snp	t3_set_reg_field(mac->adapter, A_XGM_RX_CFG + mac->offset,
1466189643Sgnn			 F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
1467189643Sgnn			 rx_cfg);
1468212710Snp	t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH + mac->offset,
1469212710Snp	    rx_hash_high);
1470212710Snp	t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW + mac->offset,
1471212710Snp	    rx_hash_low);
1472189643Sgnn}
1473189643Sgnn
1474192540Sgnnstatic int t3_detect_link_fault(adapter_t *adapter, int port_id)
1475192540Sgnn{
1476192540Sgnn	struct port_info *pi = adap2pinfo(adapter, port_id);
1477192540Sgnn	struct cmac *mac = &pi->mac;
1478192540Sgnn	uint32_t rx_cfg, rx_hash_high, rx_hash_low;
1479192540Sgnn	int link_fault;
1480192540Sgnn
1481192540Sgnn	/* stop rx */
1482192540Sgnn	t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
1483192540Sgnn	t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
1484192540Sgnn
1485192540Sgnn	/* clear status and make sure intr is enabled */
1486192540Sgnn	(void) t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
1487192540Sgnn	t3_xgm_intr_enable(adapter, port_id);
1488192540Sgnn
1489192540Sgnn	/* restart rx */
1490192540Sgnn	t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, F_RXEN);
1491192540Sgnn	t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
1492192540Sgnn
1493192540Sgnn	link_fault = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
1494192540Sgnn	return (link_fault & F_LINKFAULTCHANGE ? 1 : 0);
1495192540Sgnn}
1496192540Sgnn
1497192540Sgnnstatic void t3_clear_faults(adapter_t *adapter, int port_id)
1498192540Sgnn{
1499192540Sgnn	struct port_info *pi = adap2pinfo(adapter, port_id);
1500192540Sgnn	struct cmac *mac = &pi->mac;
1501192540Sgnn
1502192540Sgnn	if (adapter->params.nports <= 2) {
1503192540Sgnn		t3_xgm_intr_disable(adapter, pi->port_id);
1504192540Sgnn		t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
1505192540Sgnn		t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, F_XGM_INT);
1506192540Sgnn		t3_set_reg_field(adapter, A_XGM_INT_ENABLE + mac->offset,
1507192540Sgnn				 F_XGM_INT, F_XGM_INT);
1508192540Sgnn		t3_xgm_intr_enable(adapter, pi->port_id);
1509192540Sgnn	}
1510192540Sgnn}
1511192540Sgnn
1512167514Skmacy/**
1513167514Skmacy *	t3_link_changed - handle interface link changes
1514167514Skmacy *	@adapter: the adapter
1515167514Skmacy *	@port_id: the port index that changed link state
1516167514Skmacy *
1517167514Skmacy *	Called when a port's link settings change to propagate the new values
1518167514Skmacy *	to the associated PHY and MAC.  After performing the common tasks it
1519167514Skmacy *	invokes an OS-specific handler.
1520167514Skmacy */
1521167514Skmacyvoid t3_link_changed(adapter_t *adapter, int port_id)
1522167514Skmacy{
1523197791Snp	int link_ok, speed, duplex, fc, link_fault;
1524170654Skmacy	struct port_info *pi = adap2pinfo(adapter, port_id);
1525170654Skmacy	struct cphy *phy = &pi->phy;
1526170654Skmacy	struct cmac *mac = &pi->mac;
1527170654Skmacy	struct link_config *lc = &pi->link_config;
1528167514Skmacy
1529192540Sgnn	link_ok = lc->link_ok;
1530192540Sgnn	speed = lc->speed;
1531192540Sgnn	duplex = lc->duplex;
1532192540Sgnn	fc = lc->fc;
1533192540Sgnn	link_fault = 0;
1534192540Sgnn
1535167514Skmacy	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1536167514Skmacy
1537209841Snp	if (link_ok == 0)
1538209841Snp		pi->link_fault = LF_NO;
1539209841Snp
1540197791Snp	if (lc->requested_fc & PAUSE_AUTONEG)
1541197791Snp		fc &= lc->requested_fc;
1542197791Snp	else
1543197791Snp		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1544197791Snp
1545197791Snp	/* Update mac speed before checking for link fault. */
1546197791Snp	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE &&
1547197791Snp	    (speed != lc->speed || duplex != lc->duplex || fc != lc->fc))
1548197791Snp		t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
1549197791Snp
1550192540Sgnn	/*
1551192540Sgnn	 * Check for link faults if any of these is true:
1552192540Sgnn	 * a) A link fault is suspected, and PHY says link ok
1553192540Sgnn	 * b) PHY link transitioned from down -> up
1554192540Sgnn	 */
1555192540Sgnn	if (adapter->params.nports <= 2 &&
1556192540Sgnn	    ((pi->link_fault && link_ok) || (!lc->link_ok && link_ok))) {
1557189643Sgnn
1558192540Sgnn		link_fault = t3_detect_link_fault(adapter, port_id);
1559192540Sgnn		if (link_fault) {
1560192540Sgnn			if (pi->link_fault != LF_YES) {
1561192540Sgnn				mac->stats.link_faults++;
1562192540Sgnn				pi->link_fault = LF_YES;
1563192540Sgnn			}
1564189643Sgnn
1565211346Snp			if (uses_xaui(adapter)) {
1566211346Snp				if (adapter->params.rev >= T3_REV_C)
1567211346Snp					t3c_pcs_force_los(mac);
1568211346Snp				else
1569211346Snp					t3b_pcs_reset(mac);
1570211346Snp			}
1571211346Snp
1572197791Snp			/* Don't report link up */
1573192540Sgnn			link_ok = 0;
1574192540Sgnn		} else {
1575192540Sgnn			/* clear faults here if this was a false alarm. */
1576192540Sgnn			if (pi->link_fault == LF_MAYBE &&
1577192540Sgnn			    link_ok && lc->link_ok)
1578192540Sgnn				t3_clear_faults(adapter, port_id);
1579189643Sgnn
1580192540Sgnn			pi->link_fault = LF_NO;
1581189643Sgnn		}
1582189643Sgnn	}
1583189643Sgnn
1584180583Skmacy	if (link_ok == lc->link_ok && speed == lc->speed &&
1585180583Skmacy	    duplex == lc->duplex && fc == lc->fc)
1586180583Skmacy		return;                            /* nothing changed */
1587180583Skmacy
1588167514Skmacy	lc->link_ok = (unsigned char)link_ok;
1589167514Skmacy	lc->speed = speed < 0 ? SPEED_INVALID : speed;
1590167514Skmacy	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1591197791Snp	lc->fc = fc;
1592167514Skmacy
1593192540Sgnn	if (link_ok) {
1594167514Skmacy
1595192540Sgnn		/* down -> up, or up -> up with changed settings */
1596167514Skmacy
1597197791Snp		if (adapter->params.rev > 0 && uses_xaui(adapter)) {
1598211346Snp
1599211346Snp			if (adapter->params.rev >= T3_REV_C)
1600211346Snp				t3c_pcs_force_los(mac);
1601211346Snp			else
1602211346Snp				t3b_pcs_reset(mac);
1603211346Snp
1604192540Sgnn			t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
1605192540Sgnn				     F_TXACTENABLE | F_RXEN);
1606192540Sgnn		}
1607189643Sgnn
1608211346Snp		/* disable TX FIFO drain */
1609197791Snp		t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset,
1610197791Snp				 F_ENDROPPKT, 0);
1611211346Snp
1612197791Snp		t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
1613197791Snp		t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset,
1614197791Snp				 F_CLRSTATS, 1);
1615192540Sgnn		t3_clear_faults(adapter, port_id);
1616189643Sgnn
1617192540Sgnn	} else {
1618189643Sgnn
1619192540Sgnn		/* up -> down */
1620189643Sgnn
1621192540Sgnn		if (adapter->params.rev > 0 && uses_xaui(adapter)) {
1622192540Sgnn			t3_write_reg(adapter,
1623192540Sgnn				     A_XGM_XAUI_ACT_CTRL + mac->offset, 0);
1624192540Sgnn		}
1625189643Sgnn
1626192540Sgnn		t3_xgm_intr_disable(adapter, pi->port_id);
1627192540Sgnn		if (adapter->params.nports <= 2) {
1628192540Sgnn			t3_set_reg_field(adapter,
1629192540Sgnn					 A_XGM_INT_ENABLE + mac->offset,
1630192540Sgnn					 F_XGM_INT, 0);
1631189643Sgnn
1632192540Sgnn			t3_mac_disable(mac, MAC_DIRECTION_RX);
1633189643Sgnn
1634211346Snp			/*
1635211346Snp			 * Make sure Tx FIFO continues to drain, even as rxen is
1636211346Snp			 * left high to help detect and indicate remote faults.
1637211346Snp			 */
1638211346Snp			t3_set_reg_field(adapter,
1639211346Snp			    A_XGM_TXFIFO_CFG + mac->offset, 0, F_ENDROPPKT);
1640211346Snp			t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
1641211346Snp			t3_write_reg(adapter,
1642211346Snp			    A_XGM_TX_CTRL + mac->offset, F_TXEN);
1643211346Snp			t3_write_reg(adapter,
1644211346Snp			    A_XGM_RX_CTRL + mac->offset, F_RXEN);
1645211346Snp		}
1646192540Sgnn	}
1647189643Sgnn
1648197791Snp	t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc,
1649197791Snp	    mac->was_reset);
1650197791Snp	mac->was_reset = 0;
1651189643Sgnn}
1652189643Sgnn
1653167514Skmacy/**
1654167514Skmacy *	t3_link_start - apply link configuration to MAC/PHY
1655167514Skmacy *	@phy: the PHY to setup
1656167514Skmacy *	@mac: the MAC to setup
1657167514Skmacy *	@lc: the requested link configuration
1658167514Skmacy *
1659167514Skmacy *	Set up a port's MAC and PHY according to a desired link configuration.
1660167514Skmacy *	- If the PHY can auto-negotiate first decide what to advertise, then
1661167514Skmacy *	  enable/disable auto-negotiation as desired, and reset.
1662167514Skmacy *	- If the PHY does not auto-negotiate just reset it.
1663167514Skmacy *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
1664167514Skmacy *	  otherwise do it later based on the outcome of auto-negotiation.
1665167514Skmacy */
1666167514Skmacyint t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
1667167514Skmacy{
1668167514Skmacy	unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1669167514Skmacy
1670167514Skmacy	lc->link_ok = 0;
1671167514Skmacy	if (lc->supported & SUPPORTED_Autoneg) {
1672167514Skmacy		lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
1673167514Skmacy		if (fc) {
1674167514Skmacy			lc->advertising |= ADVERTISED_Asym_Pause;
1675167514Skmacy			if (fc & PAUSE_RX)
1676167514Skmacy				lc->advertising |= ADVERTISED_Pause;
1677167514Skmacy		}
1678197791Snp
1679167514Skmacy		phy->ops->advertise(phy, lc->advertising);
1680167514Skmacy
1681167514Skmacy		if (lc->autoneg == AUTONEG_DISABLE) {
1682167514Skmacy			lc->speed = lc->requested_speed;
1683167514Skmacy			lc->duplex = lc->requested_duplex;
1684167514Skmacy			lc->fc = (unsigned char)fc;
1685167514Skmacy			t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
1686167514Skmacy						   fc);
1687167514Skmacy			/* Also disables autoneg */
1688167514Skmacy			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
1689189643Sgnn			/* PR 5666. Power phy up when doing an ifup */
1690189643Sgnn			if (!is_10G(phy->adapter))
1691197791Snp				phy->ops->power_down(phy, 0);
1692167514Skmacy		} else
1693167514Skmacy			phy->ops->autoneg_enable(phy);
1694167514Skmacy	} else {
1695167514Skmacy		t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
1696167514Skmacy		lc->fc = (unsigned char)fc;
1697167514Skmacy		phy->ops->reset(phy, 0);
1698167514Skmacy	}
1699167514Skmacy	return 0;
1700167514Skmacy}
1701167514Skmacy
1702167514Skmacy/**
1703167514Skmacy *	t3_set_vlan_accel - control HW VLAN extraction
1704167514Skmacy *	@adapter: the adapter
1705167514Skmacy *	@ports: bitmap of adapter ports to operate on
1706167514Skmacy *	@on: enable (1) or disable (0) HW VLAN extraction
1707167514Skmacy *
1708167514Skmacy *	Enables or disables HW extraction of VLAN tags for the given port.
1709167514Skmacy */
1710167514Skmacyvoid t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on)
1711167514Skmacy{
1712167514Skmacy	t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
1713167514Skmacy			 ports << S_VLANEXTRACTIONENABLE,
1714167514Skmacy			 on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
1715167514Skmacy}
1716167514Skmacy
1717167514Skmacystruct intr_info {
1718167514Skmacy	unsigned int mask;       /* bits to check in interrupt status */
1719167514Skmacy	const char *msg;         /* message to print or NULL */
1720167514Skmacy	short stat_idx;          /* stat counter to increment or -1 */
1721181614Skmacy	unsigned short fatal;    /* whether the condition reported is fatal */
1722167514Skmacy};
1723167514Skmacy
1724167514Skmacy/**
1725167514Skmacy *	t3_handle_intr_status - table driven interrupt handler
1726167514Skmacy *	@adapter: the adapter that generated the interrupt
1727167514Skmacy *	@reg: the interrupt status register to process
1728167514Skmacy *	@mask: a mask to apply to the interrupt status
1729167514Skmacy *	@acts: table of interrupt actions
1730167514Skmacy *	@stats: statistics counters tracking interrupt occurences
1731167514Skmacy *
1732167514Skmacy *	A table driven interrupt handler that applies a set of masks to an
1733167514Skmacy *	interrupt status word and performs the corresponding actions if the
1734167514Skmacy *	interrupts described by the mask have occured.  The actions include
1735167514Skmacy *	optionally printing a warning or alert message, and optionally
1736167514Skmacy *	incrementing a stat counter.  The table is terminated by an entry
1737167514Skmacy *	specifying mask 0.  Returns the number of fatal interrupt conditions.
1738167514Skmacy */
1739167514Skmacystatic int t3_handle_intr_status(adapter_t *adapter, unsigned int reg,
1740167514Skmacy				 unsigned int mask,
1741167514Skmacy				 const struct intr_info *acts,
1742167514Skmacy				 unsigned long *stats)
1743167514Skmacy{
1744167514Skmacy	int fatal = 0;
1745167514Skmacy	unsigned int status = t3_read_reg(adapter, reg) & mask;
1746167514Skmacy
1747167514Skmacy	for ( ; acts->mask; ++acts) {
1748167514Skmacy		if (!(status & acts->mask)) continue;
1749167514Skmacy		if (acts->fatal) {
1750167514Skmacy			fatal++;
1751167514Skmacy			CH_ALERT(adapter, "%s (0x%x)\n",
1752167514Skmacy				 acts->msg, status & acts->mask);
1753219945Snp			status &= ~acts->mask;
1754167514Skmacy		} else if (acts->msg)
1755167514Skmacy			CH_WARN(adapter, "%s (0x%x)\n",
1756167514Skmacy				acts->msg, status & acts->mask);
1757167514Skmacy		if (acts->stat_idx >= 0)
1758167514Skmacy			stats[acts->stat_idx]++;
1759167514Skmacy	}
1760167514Skmacy	if (status)                           /* clear processed interrupts */
1761167514Skmacy		t3_write_reg(adapter, reg, status);
1762167514Skmacy	return fatal;
1763167514Skmacy}
1764167514Skmacy
1765176472Skmacy#define SGE_INTR_MASK (F_RSPQDISABLED | \
1766176472Skmacy		       F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \
1767176472Skmacy		       F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
1768176472Skmacy		       F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
1769176472Skmacy		       V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
1770176472Skmacy		       F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
1771176472Skmacy		       F_HIRCQPARITYERROR)
1772167514Skmacy#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
1773167514Skmacy		       F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
1774167514Skmacy		       F_NFASRCHFAIL)
1775167514Skmacy#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
1776167514Skmacy#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1777167514Skmacy		       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
1778189643Sgnn		       F_TXFIFO_UNDERRUN)
1779167514Skmacy#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
1780167514Skmacy			F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
1781167514Skmacy			F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
1782167514Skmacy			F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
1783167514Skmacy			V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
1784167514Skmacy			V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
1785167514Skmacy#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
1786167514Skmacy			F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
1787167514Skmacy			/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
1788176472Skmacy			F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \
1789176472Skmacy			F_TXPARERR | V_BISTERR(M_BISTERR))
1790176472Skmacy#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \
1791176472Skmacy			 F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \
1792176472Skmacy			 F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0)
1793176472Skmacy#define ULPTX_INTR_MASK 0xfc
1794176472Skmacy#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \
1795167514Skmacy			 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
1796167514Skmacy			 F_ZERO_SWITCH_ERROR)
1797167514Skmacy#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
1798167514Skmacy		       F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
1799167514Skmacy		       F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
1800176472Skmacy	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \
1801176472Skmacy		       F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \
1802176472Skmacy		       F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \
1803176472Skmacy		       F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \
1804176472Skmacy		       F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR)
1805167514Skmacy#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
1806167514Skmacy			V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
1807167514Skmacy			V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
1808167514Skmacy#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
1809167514Skmacy			V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
1810167514Skmacy			V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
1811167514Skmacy#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
1812167514Skmacy		       V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
1813167514Skmacy		       V_RXTPPARERRENB(M_RXTPPARERRENB) | \
1814167514Skmacy		       V_MCAPARERRENB(M_MCAPARERRENB))
1815189643Sgnn#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE)
1816167514Skmacy#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
1817167514Skmacy		      F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
1818167514Skmacy		      F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
1819167514Skmacy		      F_MPS0 | F_CPL_SWITCH)
1820167514Skmacy/*
1821167514Skmacy * Interrupt handler for the PCIX1 module.
1822167514Skmacy */
1823167514Skmacystatic void pci_intr_handler(adapter_t *adapter)
1824167514Skmacy{
1825167514Skmacy	static struct intr_info pcix1_intr_info[] = {
1826167514Skmacy		{ F_MSTDETPARERR, "PCI master detected parity error", -1, 1 },
1827167514Skmacy		{ F_SIGTARABT, "PCI signaled target abort", -1, 1 },
1828167514Skmacy		{ F_RCVTARABT, "PCI received target abort", -1, 1 },
1829167514Skmacy		{ F_RCVMSTABT, "PCI received master abort", -1, 1 },
1830167514Skmacy		{ F_SIGSYSERR, "PCI signaled system error", -1, 1 },
1831167514Skmacy		{ F_DETPARERR, "PCI detected parity error", -1, 1 },
1832167514Skmacy		{ F_SPLCMPDIS, "PCI split completion discarded", -1, 1 },
1833167514Skmacy		{ F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1 },
1834167514Skmacy		{ F_RCVSPLCMPERR, "PCI received split completion error", -1,
1835167514Skmacy		  1 },
1836167514Skmacy		{ F_DETCORECCERR, "PCI correctable ECC error",
1837167514Skmacy		  STAT_PCI_CORR_ECC, 0 },
1838167514Skmacy		{ F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1 },
1839167514Skmacy		{ F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 },
1840167514Skmacy		{ V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
1841167514Skmacy		  1 },
1842167514Skmacy		{ V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
1843167514Skmacy		  1 },
1844167514Skmacy		{ V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
1845167514Skmacy		  1 },
1846167514Skmacy		{ V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
1847167514Skmacy		  "error", -1, 1 },
1848167514Skmacy		{ 0 }
1849167514Skmacy	};
1850167514Skmacy
1851167514Skmacy	if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
1852167514Skmacy				  pcix1_intr_info, adapter->irq_stats))
1853167514Skmacy		t3_fatal_err(adapter);
1854167514Skmacy}
1855167514Skmacy
1856167514Skmacy/*
1857167514Skmacy * Interrupt handler for the PCIE module.
1858167514Skmacy */
1859167514Skmacystatic void pcie_intr_handler(adapter_t *adapter)
1860167514Skmacy{
1861167514Skmacy	static struct intr_info pcie_intr_info[] = {
1862167514Skmacy		{ F_PEXERR, "PCI PEX error", -1, 1 },
1863167514Skmacy		{ F_UNXSPLCPLERRR,
1864167514Skmacy		  "PCI unexpected split completion DMA read error", -1, 1 },
1865167514Skmacy		{ F_UNXSPLCPLERRC,
1866167514Skmacy		  "PCI unexpected split completion DMA command error", -1, 1 },
1867167514Skmacy		{ F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 },
1868167514Skmacy		{ F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1 },
1869167514Skmacy		{ F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1 },
1870167514Skmacy		{ F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1 },
1871167514Skmacy		{ V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
1872167514Skmacy		  "PCI MSI-X table/PBA parity error", -1, 1 },
1873176472Skmacy		{ F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1 },
1874176472Skmacy		{ F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1 },
1875176472Skmacy		{ F_RXPARERR, "PCI Rx parity error", -1, 1 },
1876176472Skmacy		{ F_TXPARERR, "PCI Tx parity error", -1, 1 },
1877167514Skmacy		{ V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1 },
1878167514Skmacy		{ 0 }
1879167514Skmacy	};
1880167514Skmacy
1881172096Skmacy	if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
1882172096Skmacy		CH_ALERT(adapter, "PEX error code 0x%x\n",
1883172096Skmacy			 t3_read_reg(adapter, A_PCIE_PEX_ERR));
1884172096Skmacy
1885167514Skmacy	if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
1886167514Skmacy				  pcie_intr_info, adapter->irq_stats))
1887167514Skmacy		t3_fatal_err(adapter);
1888167514Skmacy}
1889167514Skmacy
1890167514Skmacy/*
1891167514Skmacy * TP interrupt handler.
1892167514Skmacy */
1893167514Skmacystatic void tp_intr_handler(adapter_t *adapter)
1894167514Skmacy{
1895167514Skmacy	static struct intr_info tp_intr_info[] = {
1896167514Skmacy		{ 0xffffff,  "TP parity error", -1, 1 },
1897167514Skmacy		{ 0x1000000, "TP out of Rx pages", -1, 1 },
1898167514Skmacy		{ 0x2000000, "TP out of Tx pages", -1, 1 },
1899167514Skmacy		{ 0 }
1900167514Skmacy	};
1901176472Skmacy	static struct intr_info tp_intr_info_t3c[] = {
1902176472Skmacy		{ 0x1fffffff,  "TP parity error", -1, 1 },
1903176472Skmacy		{ F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1 },
1904176472Skmacy		{ F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
1905176472Skmacy		{ 0 }
1906176472Skmacy	};
1907167514Skmacy
1908167514Skmacy	if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
1909176472Skmacy				  adapter->params.rev < T3_REV_C ?
1910176472Skmacy					tp_intr_info : tp_intr_info_t3c, NULL))
1911167514Skmacy		t3_fatal_err(adapter);
1912167514Skmacy}
1913167514Skmacy
1914167514Skmacy/*
1915167514Skmacy * CIM interrupt handler.
1916167514Skmacy */
1917167514Skmacystatic void cim_intr_handler(adapter_t *adapter)
1918167514Skmacy{
1919167514Skmacy	static struct intr_info cim_intr_info[] = {
1920167514Skmacy		{ F_RSVDSPACEINT, "CIM reserved space write", -1, 1 },
1921167514Skmacy		{ F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1 },
1922167514Skmacy		{ F_FLASHRANGEINT, "CIM flash address out of range", -1, 1 },
1923167514Skmacy		{ F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
1924167514Skmacy		{ F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1 },
1925167514Skmacy		{ F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
1926167514Skmacy		{ F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1 },
1927167514Skmacy		{ F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
1928167514Skmacy		{ F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1 },
1929167514Skmacy		{ F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1 },
1930167514Skmacy		{ F_BLKRDPLINT, "CIM block read from PL space", -1, 1 },
1931167514Skmacy		{ F_BLKWRPLINT, "CIM block write to PL space", -1, 1 },
1932176472Skmacy		{ F_DRAMPARERR, "CIM DRAM parity error", -1, 1 },
1933176472Skmacy		{ F_ICACHEPARERR, "CIM icache parity error", -1, 1 },
1934176472Skmacy		{ F_DCACHEPARERR, "CIM dcache parity error", -1, 1 },
1935176472Skmacy		{ F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1 },
1936176472Skmacy		{ F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1 },
1937176472Skmacy		{ F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1 },
1938176472Skmacy		{ F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1 },
1939176472Skmacy		{ F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1 },
1940176472Skmacy		{ F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1 },
1941176472Skmacy		{ F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1 },
1942176472Skmacy		{ F_ITAGPARERR, "CIM itag parity error", -1, 1 },
1943176472Skmacy		{ F_DTAGPARERR, "CIM dtag parity error", -1, 1 },
1944167514Skmacy		{ 0 }
1945167514Skmacy        };
1946167514Skmacy
1947176472Skmacy	if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, CIM_INTR_MASK,
1948167514Skmacy				  cim_intr_info, NULL))
1949167514Skmacy		t3_fatal_err(adapter);
1950167514Skmacy}
1951167514Skmacy
1952167514Skmacy/*
1953167514Skmacy * ULP RX interrupt handler.
1954167514Skmacy */
1955167514Skmacystatic void ulprx_intr_handler(adapter_t *adapter)
1956167514Skmacy{
1957167514Skmacy	static struct intr_info ulprx_intr_info[] = {
1958176472Skmacy		{ F_PARERRDATA, "ULP RX data parity error", -1, 1 },
1959176472Skmacy		{ F_PARERRPCMD, "ULP RX command parity error", -1, 1 },
1960176472Skmacy		{ F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1 },
1961176472Skmacy		{ F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1 },
1962176472Skmacy		{ F_ARBFPERR, "ULP RX ArbF parity error", -1, 1 },
1963176472Skmacy		{ F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1 },
1964176472Skmacy		{ F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1 },
1965176472Skmacy		{ F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1 },
1966167514Skmacy		{ 0 }
1967167514Skmacy        };
1968167514Skmacy
1969167514Skmacy	if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
1970167514Skmacy				  ulprx_intr_info, NULL))
1971167514Skmacy		t3_fatal_err(adapter);
1972167514Skmacy}
1973167514Skmacy
1974167514Skmacy/*
1975167514Skmacy * ULP TX interrupt handler.
1976167514Skmacy */
1977167514Skmacystatic void ulptx_intr_handler(adapter_t *adapter)
1978167514Skmacy{
1979167514Skmacy	static struct intr_info ulptx_intr_info[] = {
1980167514Skmacy		{ F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
1981167514Skmacy		  STAT_ULP_CH0_PBL_OOB, 0 },
1982167514Skmacy		{ F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
1983167514Skmacy		  STAT_ULP_CH1_PBL_OOB, 0 },
1984176472Skmacy		{ 0xfc, "ULP TX parity error", -1, 1 },
1985167514Skmacy		{ 0 }
1986167514Skmacy        };
1987167514Skmacy
1988167514Skmacy	if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
1989167514Skmacy				  ulptx_intr_info, adapter->irq_stats))
1990167514Skmacy		t3_fatal_err(adapter);
1991167514Skmacy}
1992167514Skmacy
1993167514Skmacy#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
1994167514Skmacy	F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
1995167514Skmacy	F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
1996167514Skmacy	F_ICSPI1_TX_FRAMING_ERROR)
1997167514Skmacy#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
1998167514Skmacy	F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
1999167514Skmacy	F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
2000167514Skmacy	F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
2001167514Skmacy
2002167514Skmacy/*
2003167514Skmacy * PM TX interrupt handler.
2004167514Skmacy */
2005167514Skmacystatic void pmtx_intr_handler(adapter_t *adapter)
2006167514Skmacy{
2007167514Skmacy	static struct intr_info pmtx_intr_info[] = {
2008167514Skmacy		{ F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
2009167514Skmacy		{ ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1 },
2010167514Skmacy		{ OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1 },
2011167514Skmacy		{ V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
2012167514Skmacy		  "PMTX ispi parity error", -1, 1 },
2013167514Skmacy		{ V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
2014167514Skmacy		  "PMTX ospi parity error", -1, 1 },
2015167514Skmacy		{ 0 }
2016167514Skmacy        };
2017167514Skmacy
2018167514Skmacy	if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
2019167514Skmacy				  pmtx_intr_info, NULL))
2020167514Skmacy		t3_fatal_err(adapter);
2021167514Skmacy}
2022167514Skmacy
2023167514Skmacy#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
2024167514Skmacy	F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
2025167514Skmacy	F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
2026167514Skmacy	F_IESPI1_TX_FRAMING_ERROR)
2027167514Skmacy#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
2028167514Skmacy	F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
2029167514Skmacy	F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
2030167514Skmacy	F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
2031167514Skmacy
2032167514Skmacy/*
2033167514Skmacy * PM RX interrupt handler.
2034167514Skmacy */
2035167514Skmacystatic void pmrx_intr_handler(adapter_t *adapter)
2036167514Skmacy{
2037167514Skmacy	static struct intr_info pmrx_intr_info[] = {
2038167514Skmacy		{ F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
2039167514Skmacy		{ IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1 },
2040167514Skmacy		{ OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1 },
2041167514Skmacy		{ V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
2042167514Skmacy		  "PMRX ispi parity error", -1, 1 },
2043167514Skmacy		{ V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
2044167514Skmacy		  "PMRX ospi parity error", -1, 1 },
2045167514Skmacy		{ 0 }
2046167514Skmacy        };
2047167514Skmacy
2048167514Skmacy	if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
2049167514Skmacy				  pmrx_intr_info, NULL))
2050167514Skmacy		t3_fatal_err(adapter);
2051167514Skmacy}
2052167514Skmacy
2053167514Skmacy/*
2054167514Skmacy * CPL switch interrupt handler.
2055167514Skmacy */
2056167514Skmacystatic void cplsw_intr_handler(adapter_t *adapter)
2057167514Skmacy{
2058167514Skmacy	static struct intr_info cplsw_intr_info[] = {
2059176472Skmacy		{ F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1 },
2060176472Skmacy		{ F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 },
2061167514Skmacy		{ F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1 },
2062167514Skmacy		{ F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1 },
2063167514Skmacy		{ F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1 },
2064167514Skmacy		{ F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1 },
2065167514Skmacy		{ 0 }
2066167514Skmacy        };
2067167514Skmacy
2068167514Skmacy	if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
2069167514Skmacy				  cplsw_intr_info, NULL))
2070167514Skmacy		t3_fatal_err(adapter);
2071167514Skmacy}
2072167514Skmacy
2073167514Skmacy/*
2074167514Skmacy * MPS interrupt handler.
2075167514Skmacy */
2076167514Skmacystatic void mps_intr_handler(adapter_t *adapter)
2077167514Skmacy{
2078167514Skmacy	static struct intr_info mps_intr_info[] = {
2079167514Skmacy		{ 0x1ff, "MPS parity error", -1, 1 },
2080167514Skmacy		{ 0 }
2081167514Skmacy	};
2082167514Skmacy
2083167514Skmacy	if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
2084167514Skmacy				  mps_intr_info, NULL))
2085167514Skmacy		t3_fatal_err(adapter);
2086167514Skmacy}
2087167514Skmacy
2088167514Skmacy#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
2089167514Skmacy
2090167514Skmacy/*
2091167514Skmacy * MC7 interrupt handler.
2092167514Skmacy */
2093167514Skmacystatic void mc7_intr_handler(struct mc7 *mc7)
2094167514Skmacy{
2095167514Skmacy	adapter_t *adapter = mc7->adapter;
2096167514Skmacy	u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
2097167514Skmacy
2098167514Skmacy	if (cause & F_CE) {
2099167514Skmacy		mc7->stats.corr_err++;
2100167514Skmacy		CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
2101167514Skmacy			"data 0x%x 0x%x 0x%x\n", mc7->name,
2102167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
2103167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
2104167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
2105167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
2106167514Skmacy	}
2107167514Skmacy
2108167514Skmacy	if (cause & F_UE) {
2109167514Skmacy		mc7->stats.uncorr_err++;
2110167514Skmacy		CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
2111167514Skmacy			 "data 0x%x 0x%x 0x%x\n", mc7->name,
2112167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
2113167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
2114167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
2115167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
2116167514Skmacy	}
2117167514Skmacy
2118167514Skmacy	if (G_PE(cause)) {
2119167514Skmacy		mc7->stats.parity_err++;
2120167514Skmacy		CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
2121167514Skmacy			 mc7->name, G_PE(cause));
2122167514Skmacy	}
2123167514Skmacy
2124167514Skmacy	if (cause & F_AE) {
2125167514Skmacy		u32 addr = 0;
2126167514Skmacy
2127167514Skmacy		if (adapter->params.rev > 0)
2128167514Skmacy			addr = t3_read_reg(adapter,
2129167514Skmacy					   mc7->offset + A_MC7_ERR_ADDR);
2130167514Skmacy		mc7->stats.addr_err++;
2131167514Skmacy		CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
2132167514Skmacy			 mc7->name, addr);
2133167514Skmacy	}
2134167514Skmacy
2135167514Skmacy	if (cause & MC7_INTR_FATAL)
2136167514Skmacy		t3_fatal_err(adapter);
2137167514Skmacy
2138167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
2139167514Skmacy}
2140167514Skmacy
2141167514Skmacy#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
2142167514Skmacy			V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
2143167514Skmacy/*
2144167514Skmacy * XGMAC interrupt handler.
2145167514Skmacy */
2146167514Skmacystatic int mac_intr_handler(adapter_t *adap, unsigned int idx)
2147167514Skmacy{
2148170654Skmacy	u32 cause;
2149192540Sgnn	struct port_info *pi;
2150170654Skmacy	struct cmac *mac;
2151167514Skmacy
2152170654Skmacy	idx = idx == 0 ? 0 : adapter_info(adap)->nports0; /* MAC idx -> port */
2153192540Sgnn	pi = adap2pinfo(adap, idx);
2154192540Sgnn	mac = &pi->mac;
2155170654Skmacy
2156189643Sgnn	/*
2157189643Sgnn	 * We mask out interrupt causes for which we're not taking interrupts.
2158189643Sgnn	 * This allows us to use polling logic to monitor some of the other
2159189643Sgnn	 * conditions when taking interrupts would impose too much load on the
2160189643Sgnn	 * system.
2161189643Sgnn	 */
2162189643Sgnn	cause = (t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset)
2163189643Sgnn		 & ~(F_RXFIFO_OVERFLOW));
2164189643Sgnn
2165167514Skmacy	if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
2166167514Skmacy		mac->stats.tx_fifo_parity_err++;
2167167514Skmacy		CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
2168167514Skmacy	}
2169167514Skmacy	if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
2170167514Skmacy		mac->stats.rx_fifo_parity_err++;
2171167514Skmacy		CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
2172167514Skmacy	}
2173167514Skmacy	if (cause & F_TXFIFO_UNDERRUN)
2174167514Skmacy		mac->stats.tx_fifo_urun++;
2175167514Skmacy	if (cause & F_RXFIFO_OVERFLOW)
2176167514Skmacy		mac->stats.rx_fifo_ovfl++;
2177167514Skmacy	if (cause & V_SERDES_LOS(M_SERDES_LOS))
2178167514Skmacy		mac->stats.serdes_signal_loss++;
2179167514Skmacy	if (cause & F_XAUIPCSCTCERR)
2180167514Skmacy		mac->stats.xaui_pcs_ctc_err++;
2181167514Skmacy	if (cause & F_XAUIPCSALIGNCHANGE)
2182167514Skmacy		mac->stats.xaui_pcs_align_change++;
2183209841Snp	if (cause & F_XGM_INT &
2184209841Snp	    t3_read_reg(adap, A_XGM_INT_ENABLE + mac->offset)) {
2185209841Snp		t3_set_reg_field(adap, A_XGM_INT_ENABLE + mac->offset,
2186209841Snp		    F_XGM_INT, 0);
2187167514Skmacy
2188192540Sgnn		/* link fault suspected */
2189192540Sgnn		pi->link_fault = LF_MAYBE;
2190209841Snp		t3_os_link_intr(pi);
2191189643Sgnn	}
2192189643Sgnn
2193167514Skmacy	if (cause & XGM_INTR_FATAL)
2194167514Skmacy		t3_fatal_err(adap);
2195189643Sgnn
2196219945Snp	t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
2197167514Skmacy	return cause != 0;
2198167514Skmacy}
2199167514Skmacy
2200167514Skmacy/*
2201167514Skmacy * Interrupt handler for PHY events.
2202167514Skmacy */
2203209840Snpstatic int phy_intr_handler(adapter_t *adapter)
2204167514Skmacy{
2205167514Skmacy	u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
2206167514Skmacy
2207167514Skmacy	for_each_port(adapter, i) {
2208170654Skmacy		struct port_info *p = adap2pinfo(adapter, i);
2209167514Skmacy
2210176472Skmacy		if (!(p->phy.caps & SUPPORTED_IRQ))
2211167514Skmacy			continue;
2212167514Skmacy
2213180583Skmacy		if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) {
2214167514Skmacy			int phy_cause = p->phy.ops->intr_handler(&p->phy);
2215167514Skmacy
2216167514Skmacy			if (phy_cause & cphy_cause_link_change)
2217209841Snp				t3_os_link_intr(p);
2218167514Skmacy			if (phy_cause & cphy_cause_fifo_error)
2219167514Skmacy				p->phy.fifo_errors++;
2220181614Skmacy			if (phy_cause & cphy_cause_module_change)
2221181614Skmacy				t3_os_phymod_changed(adapter, i);
2222197791Snp			if (phy_cause & cphy_cause_alarm)
2223197791Snp				CH_WARN(adapter, "Operation affected due to "
2224197791Snp				    "adverse environment.  Check the spec "
2225197791Snp				    "sheet for corrective action.");
2226167514Skmacy		}
2227167514Skmacy	}
2228167514Skmacy
2229167514Skmacy	t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
2230167514Skmacy	return 0;
2231167514Skmacy}
2232167514Skmacy
2233172096Skmacy/**
2234172096Skmacy *	t3_slow_intr_handler - control path interrupt handler
2235172096Skmacy *	@adapter: the adapter
2236172096Skmacy *
2237172096Skmacy *	T3 interrupt handler for non-data interrupt events, e.g., errors.
2238172096Skmacy *	The designation 'slow' is because it involves register reads, while
2239172096Skmacy *	data interrupts typically don't involve any MMIOs.
2240167514Skmacy */
2241167514Skmacyint t3_slow_intr_handler(adapter_t *adapter)
2242167514Skmacy{
2243167514Skmacy	u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
2244167514Skmacy
2245167514Skmacy	cause &= adapter->slow_intr_mask;
2246167514Skmacy	if (!cause)
2247167514Skmacy		return 0;
2248167514Skmacy	if (cause & F_PCIM0) {
2249167514Skmacy		if (is_pcie(adapter))
2250167514Skmacy			pcie_intr_handler(adapter);
2251167514Skmacy		else
2252167514Skmacy			pci_intr_handler(adapter);
2253167514Skmacy	}
2254167514Skmacy	if (cause & F_SGE3)
2255167514Skmacy		t3_sge_err_intr_handler(adapter);
2256167514Skmacy	if (cause & F_MC7_PMRX)
2257167514Skmacy		mc7_intr_handler(&adapter->pmrx);
2258167514Skmacy	if (cause & F_MC7_PMTX)
2259167514Skmacy		mc7_intr_handler(&adapter->pmtx);
2260167514Skmacy	if (cause & F_MC7_CM)
2261167514Skmacy		mc7_intr_handler(&adapter->cm);
2262167514Skmacy	if (cause & F_CIM)
2263167514Skmacy		cim_intr_handler(adapter);
2264167514Skmacy	if (cause & F_TP1)
2265167514Skmacy		tp_intr_handler(adapter);
2266167514Skmacy	if (cause & F_ULP2_RX)
2267167514Skmacy		ulprx_intr_handler(adapter);
2268167514Skmacy	if (cause & F_ULP2_TX)
2269167514Skmacy		ulptx_intr_handler(adapter);
2270167514Skmacy	if (cause & F_PM1_RX)
2271167514Skmacy		pmrx_intr_handler(adapter);
2272167514Skmacy	if (cause & F_PM1_TX)
2273167514Skmacy		pmtx_intr_handler(adapter);
2274167514Skmacy	if (cause & F_CPL_SWITCH)
2275167514Skmacy		cplsw_intr_handler(adapter);
2276167514Skmacy	if (cause & F_MPS0)
2277167514Skmacy		mps_intr_handler(adapter);
2278167514Skmacy	if (cause & F_MC5A)
2279167514Skmacy		t3_mc5_intr_handler(&adapter->mc5);
2280167514Skmacy	if (cause & F_XGMAC0_0)
2281167514Skmacy		mac_intr_handler(adapter, 0);
2282167514Skmacy	if (cause & F_XGMAC0_1)
2283167514Skmacy		mac_intr_handler(adapter, 1);
2284167514Skmacy	if (cause & F_T3DBG)
2285209840Snp		phy_intr_handler(adapter);
2286167514Skmacy
2287167514Skmacy	/* Clear the interrupts just processed. */
2288167514Skmacy	t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
2289167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
2290167514Skmacy	return 1;
2291167514Skmacy}
2292167514Skmacy
2293180583Skmacystatic unsigned int calc_gpio_intr(adapter_t *adap)
2294180583Skmacy{
2295180583Skmacy	unsigned int i, gpi_intr = 0;
2296180583Skmacy
2297180583Skmacy	for_each_port(adap, i)
2298180583Skmacy		if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) &&
2299180583Skmacy		    adapter_info(adap)->gpio_intr[i])
2300180583Skmacy			gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i];
2301180583Skmacy	return gpi_intr;
2302180583Skmacy}
2303180583Skmacy
2304167514Skmacy/**
2305167514Skmacy *	t3_intr_enable - enable interrupts
2306167514Skmacy *	@adapter: the adapter whose interrupts should be enabled
2307167514Skmacy *
2308167514Skmacy *	Enable interrupts by setting the interrupt enable registers of the
2309167514Skmacy *	various HW modules and then enabling the top-level interrupt
2310167514Skmacy *	concentrator.
2311167514Skmacy */
2312167514Skmacyvoid t3_intr_enable(adapter_t *adapter)
2313167514Skmacy{
2314167514Skmacy	static struct addr_val_pair intr_en_avp[] = {
2315167514Skmacy		{ A_MC7_INT_ENABLE, MC7_INTR_MASK },
2316167514Skmacy		{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
2317167514Skmacy			MC7_INTR_MASK },
2318167514Skmacy		{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
2319167514Skmacy			MC7_INTR_MASK },
2320167514Skmacy		{ A_MC5_DB_INT_ENABLE, MC5_INTR_MASK },
2321167514Skmacy		{ A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK },
2322167514Skmacy		{ A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK },
2323167514Skmacy		{ A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK },
2324167514Skmacy		{ A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK },
2325167514Skmacy		{ A_MPS_INT_ENABLE, MPS_INTR_MASK },
2326167514Skmacy	};
2327167514Skmacy
2328167514Skmacy	adapter->slow_intr_mask = PL_INTR_MASK;
2329167514Skmacy
2330167514Skmacy	t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
2331176472Skmacy	t3_write_reg(adapter, A_TP_INT_ENABLE,
2332176472Skmacy		     adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff);
2333189643Sgnn	t3_write_reg(adapter, A_SG_INT_ENABLE, SGE_INTR_MASK);
2334167514Skmacy
2335167514Skmacy	if (adapter->params.rev > 0) {
2336167514Skmacy		t3_write_reg(adapter, A_CPL_INTR_ENABLE,
2337167514Skmacy			     CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
2338167514Skmacy		t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
2339167514Skmacy			     ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
2340167514Skmacy			     F_PBL_BOUND_ERR_CH1);
2341167514Skmacy	} else {
2342167514Skmacy		t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
2343167514Skmacy		t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
2344167514Skmacy	}
2345167514Skmacy
2346180583Skmacy	t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter));
2347180583Skmacy
2348170654Skmacy	if (is_pcie(adapter))
2349167514Skmacy		t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
2350170654Skmacy	else
2351167514Skmacy		t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
2352167514Skmacy	t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
2353167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_ENABLE0);          /* flush */
2354167514Skmacy}
2355167514Skmacy
2356167514Skmacy/**
2357167514Skmacy *	t3_intr_disable - disable a card's interrupts
2358167514Skmacy *	@adapter: the adapter whose interrupts should be disabled
2359167514Skmacy *
2360167514Skmacy *	Disable interrupts.  We only disable the top-level interrupt
2361167514Skmacy *	concentrator and the SGE data interrupts.
2362167514Skmacy */
2363167514Skmacyvoid t3_intr_disable(adapter_t *adapter)
2364167514Skmacy{
2365167514Skmacy	t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
2366167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_ENABLE0);  /* flush */
2367167514Skmacy	adapter->slow_intr_mask = 0;
2368167514Skmacy}
2369167514Skmacy
2370167514Skmacy/**
2371167514Skmacy *	t3_intr_clear - clear all interrupts
2372167514Skmacy *	@adapter: the adapter whose interrupts should be cleared
2373167514Skmacy *
2374167514Skmacy *	Clears all interrupts.
2375167514Skmacy */
2376167514Skmacyvoid t3_intr_clear(adapter_t *adapter)
2377167514Skmacy{
2378167514Skmacy	static const unsigned int cause_reg_addr[] = {
2379167514Skmacy		A_SG_INT_CAUSE,
2380167514Skmacy		A_SG_RSPQ_FL_STATUS,
2381167514Skmacy		A_PCIX_INT_CAUSE,
2382167514Skmacy		A_MC7_INT_CAUSE,
2383167514Skmacy		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
2384167514Skmacy		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
2385167514Skmacy		A_CIM_HOST_INT_CAUSE,
2386167514Skmacy		A_TP_INT_CAUSE,
2387167514Skmacy		A_MC5_DB_INT_CAUSE,
2388167514Skmacy		A_ULPRX_INT_CAUSE,
2389167514Skmacy		A_ULPTX_INT_CAUSE,
2390167514Skmacy		A_CPL_INTR_CAUSE,
2391167514Skmacy		A_PM1_TX_INT_CAUSE,
2392167514Skmacy		A_PM1_RX_INT_CAUSE,
2393167514Skmacy		A_MPS_INT_CAUSE,
2394167514Skmacy		A_T3DBG_INT_CAUSE,
2395167514Skmacy	};
2396167514Skmacy	unsigned int i;
2397167514Skmacy
2398167514Skmacy	/* Clear PHY and MAC interrupts for each port. */
2399167514Skmacy	for_each_port(adapter, i)
2400167514Skmacy		t3_port_intr_clear(adapter, i);
2401167514Skmacy
2402167514Skmacy	for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
2403167514Skmacy		t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
2404167514Skmacy
2405172096Skmacy	if (is_pcie(adapter))
2406172096Skmacy		t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
2407167514Skmacy	t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
2408167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_CAUSE0);          /* flush */
2409167514Skmacy}
2410167514Skmacy
2411189643Sgnnvoid t3_xgm_intr_enable(adapter_t *adapter, int idx)
2412189643Sgnn{
2413189643Sgnn	struct port_info *pi = adap2pinfo(adapter, idx);
2414189643Sgnn
2415189643Sgnn	t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset,
2416189643Sgnn		     XGM_EXTRA_INTR_MASK);
2417189643Sgnn}
2418189643Sgnn
2419189643Sgnnvoid t3_xgm_intr_disable(adapter_t *adapter, int idx)
2420189643Sgnn{
2421189643Sgnn	struct port_info *pi = adap2pinfo(adapter, idx);
2422189643Sgnn
2423189643Sgnn	t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset,
2424189643Sgnn		     0x7ff);
2425189643Sgnn}
2426189643Sgnn
2427167514Skmacy/**
2428167514Skmacy *	t3_port_intr_enable - enable port-specific interrupts
2429167514Skmacy *	@adapter: associated adapter
2430167514Skmacy *	@idx: index of port whose interrupts should be enabled
2431167514Skmacy *
2432167514Skmacy *	Enable port-specific (i.e., MAC and PHY) interrupts for the given
2433167514Skmacy *	adapter port.
2434167514Skmacy */
2435167514Skmacyvoid t3_port_intr_enable(adapter_t *adapter, int idx)
2436167514Skmacy{
2437170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2438170654Skmacy
2439170654Skmacy	t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, XGM_INTR_MASK);
2440170654Skmacy	pi->phy.ops->intr_enable(&pi->phy);
2441167514Skmacy}
2442167514Skmacy
2443167514Skmacy/**
2444167514Skmacy *	t3_port_intr_disable - disable port-specific interrupts
2445167514Skmacy *	@adapter: associated adapter
2446167514Skmacy *	@idx: index of port whose interrupts should be disabled
2447167514Skmacy *
2448167514Skmacy *	Disable port-specific (i.e., MAC and PHY) interrupts for the given
2449167514Skmacy *	adapter port.
2450167514Skmacy */
2451167514Skmacyvoid t3_port_intr_disable(adapter_t *adapter, int idx)
2452167514Skmacy{
2453170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2454170654Skmacy
2455170654Skmacy	t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, 0);
2456170654Skmacy	pi->phy.ops->intr_disable(&pi->phy);
2457167514Skmacy}
2458167514Skmacy
2459167514Skmacy/**
2460167514Skmacy *	t3_port_intr_clear - clear port-specific interrupts
2461167514Skmacy *	@adapter: associated adapter
2462167514Skmacy *	@idx: index of port whose interrupts to clear
2463167514Skmacy *
2464167514Skmacy *	Clear port-specific (i.e., MAC and PHY) interrupts for the given
2465167514Skmacy *	adapter port.
2466167514Skmacy */
2467167514Skmacyvoid t3_port_intr_clear(adapter_t *adapter, int idx)
2468167514Skmacy{
2469170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2470170654Skmacy
2471170654Skmacy	t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 0xffffffff);
2472170654Skmacy	pi->phy.ops->intr_clear(&pi->phy);
2473167514Skmacy}
2474167514Skmacy
2475172096Skmacy#define SG_CONTEXT_CMD_ATTEMPTS 100
2476172096Skmacy
2477167514Skmacy/**
2478167514Skmacy * 	t3_sge_write_context - write an SGE context
2479167514Skmacy * 	@adapter: the adapter
2480167514Skmacy * 	@id: the context id
2481167514Skmacy * 	@type: the context type
2482167514Skmacy *
2483167514Skmacy * 	Program an SGE context with the values already loaded in the
2484167514Skmacy * 	CONTEXT_DATA? registers.
2485167514Skmacy */
2486167514Skmacystatic int t3_sge_write_context(adapter_t *adapter, unsigned int id,
2487167514Skmacy				unsigned int type)
2488167514Skmacy{
2489189643Sgnn	if (type == F_RESPONSEQ) {
2490189643Sgnn		/*
2491189643Sgnn		 * Can't write the Response Queue Context bits for
2492189643Sgnn		 * Interrupt Armed or the Reserve bits after the chip
2493189643Sgnn		 * has been initialized out of reset.  Writing to these
2494189643Sgnn		 * bits can confuse the hardware.
2495189643Sgnn		 */
2496189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
2497189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
2498189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff);
2499189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
2500189643Sgnn	} else {
2501189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
2502189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
2503189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
2504189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
2505189643Sgnn	}
2506167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2507167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
2508167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2509172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2510167514Skmacy}
2511167514Skmacy
2512189643Sgnn/**
2513189643Sgnn *	clear_sge_ctxt - completely clear an SGE context
2514189643Sgnn *	@adapter: the adapter
2515189643Sgnn *	@id: the context id
2516189643Sgnn *	@type: the context type
2517189643Sgnn *
2518189643Sgnn *	Completely clear an SGE context.  Used predominantly at post-reset
2519189643Sgnn *	initialization.  Note in particular that we don't skip writing to any
2520189643Sgnn *	"sensitive bits" in the contexts the way that t3_sge_write_context()
2521189643Sgnn *	does ...
2522189643Sgnn */
2523176472Skmacystatic int clear_sge_ctxt(adapter_t *adap, unsigned int id, unsigned int type)
2524176472Skmacy{
2525176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0);
2526176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0);
2527176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0);
2528176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0);
2529189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff);
2530189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff);
2531189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff);
2532189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff);
2533189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_CMD,
2534189643Sgnn		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
2535189643Sgnn	return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2536189643Sgnn			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2537176472Skmacy}
2538176472Skmacy
2539167514Skmacy/**
2540167514Skmacy *	t3_sge_init_ecntxt - initialize an SGE egress context
2541167514Skmacy *	@adapter: the adapter to configure
2542167514Skmacy *	@id: the context id
2543167514Skmacy *	@gts_enable: whether to enable GTS for the context
2544167514Skmacy *	@type: the egress context type
2545167514Skmacy *	@respq: associated response queue
2546167514Skmacy *	@base_addr: base address of queue
2547167514Skmacy *	@size: number of queue entries
2548167514Skmacy *	@token: uP token
2549167514Skmacy *	@gen: initial generation value for the context
2550167514Skmacy *	@cidx: consumer pointer
2551167514Skmacy *
2552167514Skmacy *	Initialize an SGE egress context and make it ready for use.  If the
2553167514Skmacy *	platform allows concurrent context operations, the caller is
2554167514Skmacy *	responsible for appropriate locking.
2555167514Skmacy */
2556167514Skmacyint t3_sge_init_ecntxt(adapter_t *adapter, unsigned int id, int gts_enable,
2557167514Skmacy		       enum sge_context_type type, int respq, u64 base_addr,
2558167514Skmacy		       unsigned int size, unsigned int token, int gen,
2559167514Skmacy		       unsigned int cidx)
2560167514Skmacy{
2561167514Skmacy	unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
2562167514Skmacy
2563167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2564167514Skmacy		return -EINVAL;
2565167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2566167514Skmacy		return -EBUSY;
2567167514Skmacy
2568167514Skmacy	base_addr >>= 12;
2569167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
2570167514Skmacy		     V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
2571167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
2572167514Skmacy		     V_EC_BASE_LO((u32)base_addr & 0xffff));
2573167514Skmacy	base_addr >>= 16;
2574167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, (u32)base_addr);
2575167514Skmacy	base_addr >>= 32;
2576167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2577167514Skmacy		     V_EC_BASE_HI((u32)base_addr & 0xf) | V_EC_RESPQ(respq) |
2578167514Skmacy		     V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
2579167514Skmacy		     F_EC_VALID);
2580167514Skmacy	return t3_sge_write_context(adapter, id, F_EGRESS);
2581167514Skmacy}
2582167514Skmacy
2583167514Skmacy/**
2584167514Skmacy *	t3_sge_init_flcntxt - initialize an SGE free-buffer list context
2585167514Skmacy *	@adapter: the adapter to configure
2586167514Skmacy *	@id: the context id
2587167514Skmacy *	@gts_enable: whether to enable GTS for the context
2588167514Skmacy *	@base_addr: base address of queue
2589167514Skmacy *	@size: number of queue entries
2590167514Skmacy *	@bsize: size of each buffer for this queue
2591167514Skmacy *	@cong_thres: threshold to signal congestion to upstream producers
2592167514Skmacy *	@gen: initial generation value for the context
2593167514Skmacy *	@cidx: consumer pointer
2594167514Skmacy *
2595167514Skmacy *	Initialize an SGE free list context and make it ready for use.  The
2596167514Skmacy *	caller is responsible for ensuring only one context operation occurs
2597167514Skmacy *	at a time.
2598167514Skmacy */
2599167514Skmacyint t3_sge_init_flcntxt(adapter_t *adapter, unsigned int id, int gts_enable,
2600167514Skmacy			u64 base_addr, unsigned int size, unsigned int bsize,
2601167514Skmacy			unsigned int cong_thres, int gen, unsigned int cidx)
2602167514Skmacy{
2603167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2604167514Skmacy		return -EINVAL;
2605167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2606167514Skmacy		return -EBUSY;
2607167514Skmacy
2608167514Skmacy	base_addr >>= 12;
2609167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, (u32)base_addr);
2610167514Skmacy	base_addr >>= 32;
2611167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
2612167514Skmacy		     V_FL_BASE_HI((u32)base_addr) |
2613167514Skmacy		     V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
2614167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
2615167514Skmacy		     V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
2616167514Skmacy		     V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
2617167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2618167514Skmacy		     V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
2619167514Skmacy		     V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
2620167514Skmacy	return t3_sge_write_context(adapter, id, F_FREELIST);
2621167514Skmacy}
2622167514Skmacy
2623167514Skmacy/**
2624167514Skmacy *	t3_sge_init_rspcntxt - initialize an SGE response queue context
2625167514Skmacy *	@adapter: the adapter to configure
2626167514Skmacy *	@id: the context id
2627167514Skmacy *	@irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
2628167514Skmacy *	@base_addr: base address of queue
2629167514Skmacy *	@size: number of queue entries
2630167514Skmacy *	@fl_thres: threshold for selecting the normal or jumbo free list
2631167514Skmacy *	@gen: initial generation value for the context
2632167514Skmacy *	@cidx: consumer pointer
2633167514Skmacy *
2634167514Skmacy *	Initialize an SGE response queue context and make it ready for use.
2635167514Skmacy *	The caller is responsible for ensuring only one context operation
2636167514Skmacy *	occurs at a time.
2637167514Skmacy */
2638167514Skmacyint t3_sge_init_rspcntxt(adapter_t *adapter, unsigned int id, int irq_vec_idx,
2639167514Skmacy			 u64 base_addr, unsigned int size,
2640167514Skmacy			 unsigned int fl_thres, int gen, unsigned int cidx)
2641167514Skmacy{
2642189643Sgnn	unsigned int ctrl, intr = 0;
2643167514Skmacy
2644167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2645167514Skmacy		return -EINVAL;
2646167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2647167514Skmacy		return -EBUSY;
2648167514Skmacy
2649167514Skmacy	base_addr >>= 12;
2650167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
2651167514Skmacy		     V_CQ_INDEX(cidx));
2652167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr);
2653167514Skmacy	base_addr >>= 32;
2654189643Sgnn        ctrl = t3_read_reg(adapter, A_SG_CONTROL);
2655189643Sgnn        if ((irq_vec_idx > 0) ||
2656189643Sgnn		((irq_vec_idx == 0) && !(ctrl & F_ONEINTMULTQ)))
2657189643Sgnn                	intr = F_RQ_INTR_EN;
2658189643Sgnn        if (irq_vec_idx >= 0)
2659189643Sgnn                intr |= V_RQ_MSI_VEC(irq_vec_idx);
2660167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2661167514Skmacy		     V_CQ_BASE_HI((u32)base_addr) | intr | V_RQ_GEN(gen));
2662167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
2663167514Skmacy	return t3_sge_write_context(adapter, id, F_RESPONSEQ);
2664167514Skmacy}
2665167514Skmacy
2666167514Skmacy/**
2667167514Skmacy *	t3_sge_init_cqcntxt - initialize an SGE completion queue context
2668167514Skmacy *	@adapter: the adapter to configure
2669167514Skmacy *	@id: the context id
2670167514Skmacy *	@base_addr: base address of queue
2671167514Skmacy *	@size: number of queue entries
2672167514Skmacy *	@rspq: response queue for async notifications
2673167514Skmacy *	@ovfl_mode: CQ overflow mode
2674167514Skmacy *	@credits: completion queue credits
2675167514Skmacy *	@credit_thres: the credit threshold
2676167514Skmacy *
2677167514Skmacy *	Initialize an SGE completion queue context and make it ready for use.
2678167514Skmacy *	The caller is responsible for ensuring only one context operation
2679167514Skmacy *	occurs at a time.
2680167514Skmacy */
2681167514Skmacyint t3_sge_init_cqcntxt(adapter_t *adapter, unsigned int id, u64 base_addr,
2682167514Skmacy			unsigned int size, int rspq, int ovfl_mode,
2683167514Skmacy			unsigned int credits, unsigned int credit_thres)
2684167514Skmacy{
2685167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2686167514Skmacy		return -EINVAL;
2687167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2688167514Skmacy		return -EBUSY;
2689167514Skmacy
2690167514Skmacy	base_addr >>= 12;
2691167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
2692167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr);
2693167514Skmacy	base_addr >>= 32;
2694167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2695167514Skmacy		     V_CQ_BASE_HI((u32)base_addr) | V_CQ_RSPQ(rspq) |
2696172096Skmacy		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
2697172096Skmacy		     V_CQ_ERR(ovfl_mode));
2698167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
2699167514Skmacy		     V_CQ_CREDIT_THRES(credit_thres));
2700167514Skmacy	return t3_sge_write_context(adapter, id, F_CQ);
2701167514Skmacy}
2702167514Skmacy
2703167514Skmacy/**
2704167514Skmacy *	t3_sge_enable_ecntxt - enable/disable an SGE egress context
2705167514Skmacy *	@adapter: the adapter
2706167514Skmacy *	@id: the egress context id
2707167514Skmacy *	@enable: enable (1) or disable (0) the context
2708167514Skmacy *
2709167514Skmacy *	Enable or disable an SGE egress context.  The caller is responsible for
2710167514Skmacy *	ensuring only one context operation occurs at a time.
2711167514Skmacy */
2712167514Skmacyint t3_sge_enable_ecntxt(adapter_t *adapter, unsigned int id, int enable)
2713167514Skmacy{
2714167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2715167514Skmacy		return -EBUSY;
2716167514Skmacy
2717167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2718167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2719167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2720167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
2721167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
2722167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2723167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
2724167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2725172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2726167514Skmacy}
2727167514Skmacy
2728167514Skmacy/**
2729167514Skmacy *	t3_sge_disable_fl - disable an SGE free-buffer list
2730167514Skmacy *	@adapter: the adapter
2731167514Skmacy *	@id: the free list context id
2732167514Skmacy *
2733167514Skmacy *	Disable an SGE free-buffer list.  The caller is responsible for
2734167514Skmacy *	ensuring only one context operation occurs at a time.
2735167514Skmacy */
2736167514Skmacyint t3_sge_disable_fl(adapter_t *adapter, unsigned int id)
2737167514Skmacy{
2738167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2739167514Skmacy		return -EBUSY;
2740167514Skmacy
2741167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2742167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2743167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
2744167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2745167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
2746167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2747167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
2748167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2749172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2750167514Skmacy}
2751167514Skmacy
2752167514Skmacy/**
2753167514Skmacy *	t3_sge_disable_rspcntxt - disable an SGE response queue
2754167514Skmacy *	@adapter: the adapter
2755167514Skmacy *	@id: the response queue context id
2756167514Skmacy *
2757167514Skmacy *	Disable an SGE response queue.  The caller is responsible for
2758167514Skmacy *	ensuring only one context operation occurs at a time.
2759167514Skmacy */
2760167514Skmacyint t3_sge_disable_rspcntxt(adapter_t *adapter, unsigned int id)
2761167514Skmacy{
2762167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2763167514Skmacy		return -EBUSY;
2764167514Skmacy
2765167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2766167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2767167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2768167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2769167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2770167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2771167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
2772167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2773172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2774167514Skmacy}
2775167514Skmacy
2776167514Skmacy/**
2777167514Skmacy *	t3_sge_disable_cqcntxt - disable an SGE completion queue
2778167514Skmacy *	@adapter: the adapter
2779167514Skmacy *	@id: the completion queue context id
2780167514Skmacy *
2781167514Skmacy *	Disable an SGE completion queue.  The caller is responsible for
2782167514Skmacy *	ensuring only one context operation occurs at a time.
2783167514Skmacy */
2784167514Skmacyint t3_sge_disable_cqcntxt(adapter_t *adapter, unsigned int id)
2785167514Skmacy{
2786167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2787167514Skmacy		return -EBUSY;
2788167514Skmacy
2789167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2790167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2791167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2792167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2793167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2794167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2795167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
2796167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2797172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2798167514Skmacy}
2799167514Skmacy
2800167514Skmacy/**
2801167514Skmacy *	t3_sge_cqcntxt_op - perform an operation on a completion queue context
2802167514Skmacy *	@adapter: the adapter
2803167514Skmacy *	@id: the context id
2804167514Skmacy *	@op: the operation to perform
2805172096Skmacy *	@credits: credits to return to the CQ
2806167514Skmacy *
2807167514Skmacy *	Perform the selected operation on an SGE completion queue context.
2808167514Skmacy *	The caller is responsible for ensuring only one context operation
2809167514Skmacy *	occurs at a time.
2810172096Skmacy *
2811172096Skmacy *	For most operations the function returns the current HW position in
2812172096Skmacy *	the completion queue.
2813167514Skmacy */
2814167514Skmacyint t3_sge_cqcntxt_op(adapter_t *adapter, unsigned int id, unsigned int op,
2815167514Skmacy		      unsigned int credits)
2816167514Skmacy{
2817167514Skmacy	u32 val;
2818167514Skmacy
2819167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2820167514Skmacy		return -EBUSY;
2821167514Skmacy
2822167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
2823167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
2824167514Skmacy		     V_CONTEXT(id) | F_CQ);
2825167514Skmacy	if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2826172096Skmacy				0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
2827167514Skmacy		return -EIO;
2828167514Skmacy
2829167514Skmacy	if (op >= 2 && op < 7) {
2830167514Skmacy		if (adapter->params.rev > 0)
2831167514Skmacy			return G_CQ_INDEX(val);
2832167514Skmacy
2833167514Skmacy		t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2834167514Skmacy			     V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
2835167514Skmacy		if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
2836172096Skmacy				    F_CONTEXT_CMD_BUSY, 0,
2837172096Skmacy				    SG_CONTEXT_CMD_ATTEMPTS, 1))
2838167514Skmacy			return -EIO;
2839167514Skmacy		return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
2840167514Skmacy	}
2841167514Skmacy	return 0;
2842167514Skmacy}
2843167514Skmacy
2844167514Skmacy/**
2845167514Skmacy * 	t3_sge_read_context - read an SGE context
2846167514Skmacy * 	@type: the context type
2847167514Skmacy * 	@adapter: the adapter
2848167514Skmacy * 	@id: the context id
2849167514Skmacy * 	@data: holds the retrieved context
2850167514Skmacy *
2851167514Skmacy * 	Read an SGE egress context.  The caller is responsible for ensuring
2852167514Skmacy * 	only one context operation occurs at a time.
2853167514Skmacy */
2854167514Skmacystatic int t3_sge_read_context(unsigned int type, adapter_t *adapter,
2855167514Skmacy			       unsigned int id, u32 data[4])
2856167514Skmacy{
2857167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2858167514Skmacy		return -EBUSY;
2859167514Skmacy
2860167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2861167514Skmacy		     V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
2862167514Skmacy	if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
2863172096Skmacy			    SG_CONTEXT_CMD_ATTEMPTS, 1))
2864167514Skmacy		return -EIO;
2865167514Skmacy	data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
2866167514Skmacy	data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
2867167514Skmacy	data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
2868167514Skmacy	data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
2869167514Skmacy	return 0;
2870167514Skmacy}
2871167514Skmacy
2872167514Skmacy/**
2873167514Skmacy * 	t3_sge_read_ecntxt - read an SGE egress context
2874167514Skmacy * 	@adapter: the adapter
2875167514Skmacy * 	@id: the context id
2876167514Skmacy * 	@data: holds the retrieved context
2877167514Skmacy *
2878167514Skmacy * 	Read an SGE egress context.  The caller is responsible for ensuring
2879167514Skmacy * 	only one context operation occurs at a time.
2880167514Skmacy */
2881167514Skmacyint t3_sge_read_ecntxt(adapter_t *adapter, unsigned int id, u32 data[4])
2882167514Skmacy{
2883167514Skmacy	if (id >= 65536)
2884167514Skmacy		return -EINVAL;
2885167514Skmacy	return t3_sge_read_context(F_EGRESS, adapter, id, data);
2886167514Skmacy}
2887167514Skmacy
2888167514Skmacy/**
2889167514Skmacy * 	t3_sge_read_cq - read an SGE CQ context
2890167514Skmacy * 	@adapter: the adapter
2891167514Skmacy * 	@id: the context id
2892167514Skmacy * 	@data: holds the retrieved context
2893167514Skmacy *
2894167514Skmacy * 	Read an SGE CQ context.  The caller is responsible for ensuring
2895167514Skmacy * 	only one context operation occurs at a time.
2896167514Skmacy */
2897167514Skmacyint t3_sge_read_cq(adapter_t *adapter, unsigned int id, u32 data[4])
2898167514Skmacy{
2899167514Skmacy	if (id >= 65536)
2900167514Skmacy		return -EINVAL;
2901167514Skmacy	return t3_sge_read_context(F_CQ, adapter, id, data);
2902167514Skmacy}
2903167514Skmacy
2904167514Skmacy/**
2905167514Skmacy * 	t3_sge_read_fl - read an SGE free-list context
2906167514Skmacy * 	@adapter: the adapter
2907167514Skmacy * 	@id: the context id
2908167514Skmacy * 	@data: holds the retrieved context
2909167514Skmacy *
2910167514Skmacy * 	Read an SGE free-list context.  The caller is responsible for ensuring
2911167514Skmacy * 	only one context operation occurs at a time.
2912167514Skmacy */
2913167514Skmacyint t3_sge_read_fl(adapter_t *adapter, unsigned int id, u32 data[4])
2914167514Skmacy{
2915167514Skmacy	if (id >= SGE_QSETS * 2)
2916167514Skmacy		return -EINVAL;
2917167514Skmacy	return t3_sge_read_context(F_FREELIST, adapter, id, data);
2918167514Skmacy}
2919167514Skmacy
2920167514Skmacy/**
2921167514Skmacy * 	t3_sge_read_rspq - read an SGE response queue context
2922167514Skmacy * 	@adapter: the adapter
2923167514Skmacy * 	@id: the context id
2924167514Skmacy * 	@data: holds the retrieved context
2925167514Skmacy *
2926167514Skmacy * 	Read an SGE response queue context.  The caller is responsible for
2927167514Skmacy * 	ensuring only one context operation occurs at a time.
2928167514Skmacy */
2929167514Skmacyint t3_sge_read_rspq(adapter_t *adapter, unsigned int id, u32 data[4])
2930167514Skmacy{
2931167514Skmacy	if (id >= SGE_QSETS)
2932167514Skmacy		return -EINVAL;
2933167514Skmacy	return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
2934167514Skmacy}
2935167514Skmacy
2936167514Skmacy/**
2937167514Skmacy *	t3_config_rss - configure Rx packet steering
2938167514Skmacy *	@adapter: the adapter
2939167514Skmacy *	@rss_config: RSS settings (written to TP_RSS_CONFIG)
2940167514Skmacy *	@cpus: values for the CPU lookup table (0xff terminated)
2941167514Skmacy *	@rspq: values for the response queue lookup table (0xffff terminated)
2942167514Skmacy *
2943167514Skmacy *	Programs the receive packet steering logic.  @cpus and @rspq provide
2944167514Skmacy *	the values for the CPU and response queue lookup tables.  If they
2945167514Skmacy *	provide fewer values than the size of the tables the supplied values
2946167514Skmacy *	are used repeatedly until the tables are fully populated.
2947167514Skmacy */
2948167514Skmacyvoid t3_config_rss(adapter_t *adapter, unsigned int rss_config, const u8 *cpus,
2949167514Skmacy		   const u16 *rspq)
2950167514Skmacy{
2951167514Skmacy	int i, j, cpu_idx = 0, q_idx = 0;
2952167514Skmacy
2953167514Skmacy	if (cpus)
2954167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2955167514Skmacy			u32 val = i << 16;
2956167514Skmacy
2957167514Skmacy			for (j = 0; j < 2; ++j) {
2958167514Skmacy				val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
2959167514Skmacy				if (cpus[cpu_idx] == 0xff)
2960167514Skmacy					cpu_idx = 0;
2961167514Skmacy			}
2962167514Skmacy			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
2963167514Skmacy		}
2964167514Skmacy
2965167514Skmacy	if (rspq)
2966167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2967167514Skmacy			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
2968167514Skmacy				     (i << 16) | rspq[q_idx++]);
2969167514Skmacy			if (rspq[q_idx] == 0xffff)
2970167514Skmacy				q_idx = 0;
2971167514Skmacy		}
2972167514Skmacy
2973167514Skmacy	t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
2974167514Skmacy}
2975167514Skmacy
2976167514Skmacy/**
2977167514Skmacy *	t3_read_rss - read the contents of the RSS tables
2978167514Skmacy *	@adapter: the adapter
2979167514Skmacy *	@lkup: holds the contents of the RSS lookup table
2980167514Skmacy *	@map: holds the contents of the RSS map table
2981167514Skmacy *
2982167514Skmacy *	Reads the contents of the receive packet steering tables.
2983167514Skmacy */
2984167514Skmacyint t3_read_rss(adapter_t *adapter, u8 *lkup, u16 *map)
2985167514Skmacy{
2986167514Skmacy	int i;
2987167514Skmacy	u32 val;
2988167514Skmacy
2989167514Skmacy	if (lkup)
2990167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2991167514Skmacy			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
2992167514Skmacy				     0xffff0000 | i);
2993167514Skmacy			val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
2994167514Skmacy			if (!(val & 0x80000000))
2995167514Skmacy				return -EAGAIN;
2996167514Skmacy			*lkup++ = (u8)val;
2997167514Skmacy			*lkup++ = (u8)(val >> 8);
2998167514Skmacy		}
2999167514Skmacy
3000167514Skmacy	if (map)
3001167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
3002167514Skmacy			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
3003167514Skmacy				     0xffff0000 | i);
3004167514Skmacy			val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
3005167514Skmacy			if (!(val & 0x80000000))
3006167514Skmacy				return -EAGAIN;
3007167514Skmacy			*map++ = (u16)val;
3008167514Skmacy		}
3009167514Skmacy	return 0;
3010167514Skmacy}
3011167514Skmacy
3012167514Skmacy/**
3013167514Skmacy *	t3_tp_set_offload_mode - put TP in NIC/offload mode
3014167514Skmacy *	@adap: the adapter
3015167514Skmacy *	@enable: 1 to select offload mode, 0 for regular NIC
3016167514Skmacy *
3017167514Skmacy *	Switches TP to NIC/offload mode.
3018167514Skmacy */
3019167514Skmacyvoid t3_tp_set_offload_mode(adapter_t *adap, int enable)
3020167514Skmacy{
3021167514Skmacy	if (is_offload(adap) || !enable)
3022167514Skmacy		t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
3023167514Skmacy				 V_NICMODE(!enable));
3024167514Skmacy}
3025167514Skmacy
3026172096Skmacy/**
3027172096Skmacy *	tp_wr_bits_indirect - set/clear bits in an indirect TP register
3028172096Skmacy *	@adap: the adapter
3029172096Skmacy *	@addr: the indirect TP register address
3030172096Skmacy *	@mask: specifies the field within the register to modify
3031172096Skmacy *	@val: new value for the field
3032172096Skmacy *
3033172096Skmacy *	Sets a field of an indirect TP register to the given value.
3034172096Skmacy */
3035171471Skmacystatic void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr,
3036171471Skmacy				unsigned int mask, unsigned int val)
3037171471Skmacy{
3038171471Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
3039171471Skmacy	val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask;
3040171471Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, val);
3041171471Skmacy}
3042171471Skmacy
3043167514Skmacy/**
3044180583Skmacy *	t3_enable_filters - enable the HW filters
3045180583Skmacy *	@adap: the adapter
3046180583Skmacy *
3047180583Skmacy *	Enables the HW filters for NIC traffic.
3048180583Skmacy */
3049180583Skmacyvoid t3_enable_filters(adapter_t *adap)
3050180583Skmacy{
3051180583Skmacy	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 0);
3052180583Skmacy	t3_set_reg_field(adap, A_MC5_DB_CONFIG, 0, F_FILTEREN);
3053180583Skmacy	t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 0, V_FIVETUPLELOOKUP(3));
3054180583Skmacy	tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, 0, F_LOOKUPEVERYPKT);
3055180583Skmacy}
3056180583Skmacy
3057180583Skmacy/**
3058189643Sgnn *	t3_disable_filters - disable the HW filters
3059189643Sgnn *	@adap: the adapter
3060189643Sgnn *
3061189643Sgnn *	Disables the HW filters for NIC traffic.
3062189643Sgnn */
3063189643Sgnnvoid t3_disable_filters(adapter_t *adap)
3064189643Sgnn{
3065189643Sgnn	/* note that we don't want to revert to NIC-only mode */
3066189643Sgnn	t3_set_reg_field(adap, A_MC5_DB_CONFIG, F_FILTEREN, 0);
3067189643Sgnn	t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG,
3068189643Sgnn			 V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP), 0);
3069189643Sgnn	tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, F_LOOKUPEVERYPKT, 0);
3070189643Sgnn}
3071189643Sgnn
3072189643Sgnn/**
3073167514Skmacy *	pm_num_pages - calculate the number of pages of the payload memory
3074167514Skmacy *	@mem_size: the size of the payload memory
3075167514Skmacy *	@pg_size: the size of each payload memory page
3076167514Skmacy *
3077167514Skmacy *	Calculate the number of pages, each of the given size, that fit in a
3078167514Skmacy *	memory of the specified size, respecting the HW requirement that the
3079167514Skmacy *	number of pages must be a multiple of 24.
3080167514Skmacy */
3081167514Skmacystatic inline unsigned int pm_num_pages(unsigned int mem_size,
3082167514Skmacy					unsigned int pg_size)
3083167514Skmacy{
3084167514Skmacy	unsigned int n = mem_size / pg_size;
3085167514Skmacy
3086167514Skmacy	return n - n % 24;
3087167514Skmacy}
3088167514Skmacy
3089167514Skmacy#define mem_region(adap, start, size, reg) \
3090167514Skmacy	t3_write_reg((adap), A_ ## reg, (start)); \
3091167514Skmacy	start += size
3092167514Skmacy
3093172096Skmacy/**
3094167514Skmacy *	partition_mem - partition memory and configure TP memory settings
3095167514Skmacy *	@adap: the adapter
3096167514Skmacy *	@p: the TP parameters
3097167514Skmacy *
3098167514Skmacy *	Partitions context and payload memory and configures TP's memory
3099167514Skmacy *	registers.
3100167514Skmacy */
3101167514Skmacystatic void partition_mem(adapter_t *adap, const struct tp_params *p)
3102167514Skmacy{
3103167514Skmacy	unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
3104167514Skmacy	unsigned int timers = 0, timers_shift = 22;
3105167514Skmacy
3106167514Skmacy	if (adap->params.rev > 0) {
3107167514Skmacy		if (tids <= 16 * 1024) {
3108167514Skmacy			timers = 1;
3109167514Skmacy			timers_shift = 16;
3110167514Skmacy		} else if (tids <= 64 * 1024) {
3111167514Skmacy			timers = 2;
3112167514Skmacy			timers_shift = 18;
3113167514Skmacy		} else if (tids <= 256 * 1024) {
3114167514Skmacy			timers = 3;
3115167514Skmacy			timers_shift = 20;
3116167514Skmacy		}
3117167514Skmacy	}
3118167514Skmacy
3119167514Skmacy	t3_write_reg(adap, A_TP_PMM_SIZE,
3120167514Skmacy		     p->chan_rx_size | (p->chan_tx_size >> 16));
3121167514Skmacy
3122167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
3123167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
3124167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
3125167514Skmacy	t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
3126167514Skmacy			 V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
3127167514Skmacy
3128167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
3129167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
3130167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
3131167514Skmacy
3132167514Skmacy	pstructs = p->rx_num_pgs + p->tx_num_pgs;
3133167514Skmacy	/* Add a bit of headroom and make multiple of 24 */
3134167514Skmacy	pstructs += 48;
3135167514Skmacy	pstructs -= pstructs % 24;
3136167514Skmacy	t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
3137167514Skmacy
3138167514Skmacy	m = tids * TCB_SIZE;
3139167514Skmacy	mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
3140167514Skmacy	mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
3141167514Skmacy	t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
3142167514Skmacy	m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
3143167514Skmacy	mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
3144167514Skmacy	mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
3145167514Skmacy	mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
3146167514Skmacy	mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
3147167514Skmacy
3148167514Skmacy	m = (m + 4095) & ~0xfff;
3149167514Skmacy	t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
3150167514Skmacy	t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
3151167514Skmacy
3152167514Skmacy	tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
3153167514Skmacy	m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
3154167514Skmacy	    adap->params.mc5.nfilters - adap->params.mc5.nroutes;
3155167514Skmacy	if (tids < m)
3156167514Skmacy		adap->params.mc5.nservers += m - tids;
3157167514Skmacy}
3158167514Skmacy
3159167514Skmacystatic inline void tp_wr_indirect(adapter_t *adap, unsigned int addr, u32 val)
3160167514Skmacy{
3161167514Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
3162167514Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, val);
3163167514Skmacy}
3164167514Skmacy
3165189643Sgnnstatic inline u32 tp_rd_indirect(adapter_t *adap, unsigned int addr)
3166189643Sgnn{
3167189643Sgnn	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
3168189643Sgnn	return t3_read_reg(adap, A_TP_PIO_DATA);
3169189643Sgnn}
3170189643Sgnn
3171167514Skmacystatic void tp_config(adapter_t *adap, const struct tp_params *p)
3172167514Skmacy{
3173167514Skmacy	t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
3174167514Skmacy		     F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
3175167514Skmacy		     F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
3176167514Skmacy	t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
3177167514Skmacy		     F_MTUENABLE | V_WINDOWSCALEMODE(1) |
3178180583Skmacy		     V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
3179167514Skmacy	t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
3180167514Skmacy		     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
3181180583Skmacy		     V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) |
3182167514Skmacy		     F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
3183176472Skmacy	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO,
3184167514Skmacy			 F_IPV6ENABLE | F_NICMODE);
3185167514Skmacy	t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
3186167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
3187170654Skmacy	t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
3188170654Skmacy			 adap->params.rev > 0 ? F_ENABLEESND :
3189170654Skmacy			 			F_T3A_ENABLEESND);
3190167514Skmacy	t3_set_reg_field(adap, A_TP_PC_CONFIG,
3191170654Skmacy			 F_ENABLEEPCMDAFULL,
3192170654Skmacy			 F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
3193170654Skmacy			 F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
3194176472Skmacy	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL,
3195176472Skmacy			 F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN |
3196176472Skmacy			 F_ENABLEARPMISS | F_DISBLEDAPARBIT0);
3197170654Skmacy	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
3198170654Skmacy	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
3199167514Skmacy
3200167514Skmacy	if (adap->params.rev > 0) {
3201167514Skmacy		tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
3202171471Skmacy		t3_set_reg_field(adap, A_TP_PARA_REG3, 0,
3203171471Skmacy				 F_TXPACEAUTO | F_TXPACEAUTOSTRICT);
3204167514Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
3205171471Skmacy		tp_wr_indirect(adap, A_TP_VLAN_PRI_MAP, 0xfa50);
3206171471Skmacy		tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP0, 0xfac688);
3207171471Skmacy		tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP1, 0xfac688);
3208167514Skmacy	} else
3209167514Skmacy		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
3210167514Skmacy
3211176472Skmacy	if (adap->params.rev == T3_REV_C)
3212176472Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG,
3213176472Skmacy				 V_TABLELATENCYDELTA(M_TABLELATENCYDELTA),
3214176472Skmacy				 V_TABLELATENCYDELTA(4));
3215176472Skmacy
3216167746Skmacy	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
3217167746Skmacy	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
3218167746Skmacy	t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
3219170654Skmacy	t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
3220170654Skmacy
3221170654Skmacy	if (adap->params.nports > 2) {
3222170654Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG2, 0,
3223180583Skmacy				 F_ENABLETXPORTFROMDA2 | F_ENABLETXPORTFROMDA |
3224180583Skmacy				 F_ENABLERXPORTFROMADDR);
3225170654Skmacy		tp_wr_bits_indirect(adap, A_TP_QOS_RX_MAP_MODE,
3226170654Skmacy				    V_RXMAPMODE(M_RXMAPMODE), 0);
3227170654Skmacy		tp_wr_indirect(adap, A_TP_INGRESS_CONFIG, V_BITPOS0(48) |
3228170654Skmacy			       V_BITPOS1(49) | V_BITPOS2(50) | V_BITPOS3(51) |
3229170654Skmacy			       F_ENABLEEXTRACT | F_ENABLEEXTRACTIONSFD |
3230170654Skmacy			       F_ENABLEINSERTION | F_ENABLEINSERTIONSFD);
3231170654Skmacy		tp_wr_indirect(adap, A_TP_PREAMBLE_MSB, 0xfb000000);
3232170654Skmacy		tp_wr_indirect(adap, A_TP_PREAMBLE_LSB, 0xd5);
3233170654Skmacy		tp_wr_indirect(adap, A_TP_INTF_FROM_TX_PKT, F_INTFFROMTXPKT);
3234170654Skmacy	}
3235167514Skmacy}
3236167514Skmacy
3237167514Skmacy/* TCP timer values in ms */
3238167514Skmacy#define TP_DACK_TIMER 50
3239167514Skmacy#define TP_RTO_MIN    250
3240167514Skmacy
3241167514Skmacy/**
3242167514Skmacy *	tp_set_timers - set TP timing parameters
3243167514Skmacy *	@adap: the adapter to set
3244167514Skmacy *	@core_clk: the core clock frequency in Hz
3245167514Skmacy *
3246167514Skmacy *	Set TP's timing parameters, such as the various timer resolutions and
3247167514Skmacy *	the TCP timer values.
3248167514Skmacy */
3249167514Skmacystatic void tp_set_timers(adapter_t *adap, unsigned int core_clk)
3250167514Skmacy{
3251170654Skmacy	unsigned int tre = adap->params.tp.tre;
3252167746Skmacy	unsigned int dack_re = adap->params.tp.dack_re;
3253167514Skmacy	unsigned int tstamp_re = fls(core_clk / 1000);     /* 1ms, at least */
3254167514Skmacy	unsigned int tps = core_clk >> tre;
3255167514Skmacy
3256167514Skmacy	t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
3257167514Skmacy		     V_DELAYEDACKRESOLUTION(dack_re) |
3258167514Skmacy		     V_TIMESTAMPRESOLUTION(tstamp_re));
3259167514Skmacy	t3_write_reg(adap, A_TP_DACK_TIMER,
3260167514Skmacy		     (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
3261167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
3262167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
3263167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
3264167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
3265167514Skmacy	t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
3266167514Skmacy		     V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
3267167514Skmacy		     V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
3268167514Skmacy		     V_KEEPALIVEMAX(9));
3269167514Skmacy
3270167514Skmacy#define SECONDS * tps
3271167514Skmacy
3272167514Skmacy	t3_write_reg(adap, A_TP_MSL,
3273167514Skmacy		     adap->params.rev > 0 ? 0 : 2 SECONDS);
3274167514Skmacy	t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
3275167514Skmacy	t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
3276167514Skmacy	t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
3277167514Skmacy	t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
3278167514Skmacy	t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
3279167514Skmacy	t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
3280167514Skmacy	t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
3281167514Skmacy	t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
3282167514Skmacy
3283167514Skmacy#undef SECONDS
3284167514Skmacy}
3285167514Skmacy
3286167514Skmacy/**
3287167514Skmacy *	t3_tp_set_coalescing_size - set receive coalescing size
3288167514Skmacy *	@adap: the adapter
3289167514Skmacy *	@size: the receive coalescing size
3290167514Skmacy *	@psh: whether a set PSH bit should deliver coalesced data
3291167514Skmacy *
3292167514Skmacy *	Set the receive coalescing size and PSH bit handling.
3293167514Skmacy */
3294167514Skmacyint t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh)
3295167514Skmacy{
3296167514Skmacy	u32 val;
3297167514Skmacy
3298167514Skmacy	if (size > MAX_RX_COALESCING_LEN)
3299167514Skmacy		return -EINVAL;
3300167514Skmacy
3301167514Skmacy	val = t3_read_reg(adap, A_TP_PARA_REG3);
3302167514Skmacy	val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
3303167514Skmacy
3304167514Skmacy	if (size) {
3305167514Skmacy		val |= F_RXCOALESCEENABLE;
3306167514Skmacy		if (psh)
3307167514Skmacy			val |= F_RXCOALESCEPSHEN;
3308170654Skmacy		size = min(MAX_RX_COALESCING_LEN, size);
3309167514Skmacy		t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
3310167514Skmacy			     V_MAXRXDATA(MAX_RX_COALESCING_LEN));
3311167514Skmacy	}
3312167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG3, val);
3313167514Skmacy	return 0;
3314167514Skmacy}
3315167514Skmacy
3316167514Skmacy/**
3317167514Skmacy *	t3_tp_set_max_rxsize - set the max receive size
3318167514Skmacy *	@adap: the adapter
3319167514Skmacy *	@size: the max receive size
3320167514Skmacy *
3321167514Skmacy *	Set TP's max receive size.  This is the limit that applies when
3322167514Skmacy *	receive coalescing is disabled.
3323167514Skmacy */
3324167514Skmacyvoid t3_tp_set_max_rxsize(adapter_t *adap, unsigned int size)
3325167514Skmacy{
3326167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG7,
3327167514Skmacy		     V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
3328167514Skmacy}
3329167514Skmacy
3330167514Skmacystatic void __devinit init_mtus(unsigned short mtus[])
3331167514Skmacy{
3332167514Skmacy	/*
3333167514Skmacy	 * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
3334167514Skmacy	 * it can accomodate max size TCP/IP headers when SACK and timestamps
3335167514Skmacy	 * are enabled and still have at least 8 bytes of payload.
3336167514Skmacy	 */
3337167514Skmacy	mtus[0] = 88;
3338170654Skmacy	mtus[1] = 88;
3339167746Skmacy	mtus[2] = 256;
3340167746Skmacy	mtus[3] = 512;
3341167746Skmacy	mtus[4] = 576;
3342167514Skmacy	mtus[5] = 1024;
3343167514Skmacy	mtus[6] = 1280;
3344167514Skmacy	mtus[7] = 1492;
3345167514Skmacy	mtus[8] = 1500;
3346167514Skmacy	mtus[9] = 2002;
3347167514Skmacy	mtus[10] = 2048;
3348167514Skmacy	mtus[11] = 4096;
3349167514Skmacy	mtus[12] = 4352;
3350167514Skmacy	mtus[13] = 8192;
3351167514Skmacy	mtus[14] = 9000;
3352167514Skmacy	mtus[15] = 9600;
3353167514Skmacy}
3354167514Skmacy
3355172096Skmacy/**
3356172096Skmacy *	init_cong_ctrl - initialize congestion control parameters
3357172096Skmacy *	@a: the alpha values for congestion control
3358172096Skmacy *	@b: the beta values for congestion control
3359172096Skmacy *
3360172096Skmacy *	Initialize the congestion control parameters.
3361167514Skmacy */
3362167514Skmacystatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
3363167514Skmacy{
3364167514Skmacy	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
3365167514Skmacy	a[9] = 2;
3366167514Skmacy	a[10] = 3;
3367167514Skmacy	a[11] = 4;
3368167514Skmacy	a[12] = 5;
3369167514Skmacy	a[13] = 6;
3370167514Skmacy	a[14] = 7;
3371167514Skmacy	a[15] = 8;
3372167514Skmacy	a[16] = 9;
3373167514Skmacy	a[17] = 10;
3374167514Skmacy	a[18] = 14;
3375167514Skmacy	a[19] = 17;
3376167514Skmacy	a[20] = 21;
3377167514Skmacy	a[21] = 25;
3378167514Skmacy	a[22] = 30;
3379167514Skmacy	a[23] = 35;
3380167514Skmacy	a[24] = 45;
3381167514Skmacy	a[25] = 60;
3382167514Skmacy	a[26] = 80;
3383167514Skmacy	a[27] = 100;
3384167514Skmacy	a[28] = 200;
3385167514Skmacy	a[29] = 300;
3386167514Skmacy	a[30] = 400;
3387167514Skmacy	a[31] = 500;
3388167514Skmacy
3389167514Skmacy	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
3390167514Skmacy	b[9] = b[10] = 1;
3391167514Skmacy	b[11] = b[12] = 2;
3392167514Skmacy	b[13] = b[14] = b[15] = b[16] = 3;
3393167514Skmacy	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
3394167514Skmacy	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
3395167514Skmacy	b[28] = b[29] = 6;
3396167514Skmacy	b[30] = b[31] = 7;
3397167514Skmacy}
3398167514Skmacy
3399167514Skmacy/* The minimum additive increment value for the congestion control table */
3400167514Skmacy#define CC_MIN_INCR 2U
3401167514Skmacy
3402167514Skmacy/**
3403167514Skmacy *	t3_load_mtus - write the MTU and congestion control HW tables
3404167514Skmacy *	@adap: the adapter
3405167514Skmacy *	@mtus: the unrestricted values for the MTU table
3406172096Skmacy *	@alpha: the values for the congestion control alpha parameter
3407167514Skmacy *	@beta: the values for the congestion control beta parameter
3408167514Skmacy *	@mtu_cap: the maximum permitted effective MTU
3409167514Skmacy *
3410167514Skmacy *	Write the MTU table with the supplied MTUs capping each at &mtu_cap.
3411167514Skmacy *	Update the high-speed congestion control table with the supplied alpha,
3412167514Skmacy * 	beta, and MTUs.
3413167514Skmacy */
3414167514Skmacyvoid t3_load_mtus(adapter_t *adap, unsigned short mtus[NMTUS],
3415167514Skmacy		  unsigned short alpha[NCCTRL_WIN],
3416167514Skmacy		  unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
3417167514Skmacy{
3418167514Skmacy	static const unsigned int avg_pkts[NCCTRL_WIN] = {
3419167514Skmacy		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
3420167514Skmacy		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
3421167514Skmacy		28672, 40960, 57344, 81920, 114688, 163840, 229376 };
3422167514Skmacy
3423167514Skmacy	unsigned int i, w;
3424167514Skmacy
3425167514Skmacy	for (i = 0; i < NMTUS; ++i) {
3426167514Skmacy		unsigned int mtu = min(mtus[i], mtu_cap);
3427167514Skmacy		unsigned int log2 = fls(mtu);
3428167514Skmacy
3429167514Skmacy		if (!(mtu & ((1 << log2) >> 2)))     /* round */
3430167514Skmacy			log2--;
3431167514Skmacy		t3_write_reg(adap, A_TP_MTU_TABLE,
3432167514Skmacy			     (i << 24) | (log2 << 16) | mtu);
3433167514Skmacy
3434167514Skmacy		for (w = 0; w < NCCTRL_WIN; ++w) {
3435167514Skmacy			unsigned int inc;
3436167514Skmacy
3437167514Skmacy			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
3438167514Skmacy				  CC_MIN_INCR);
3439167514Skmacy
3440167514Skmacy			t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
3441167514Skmacy				     (w << 16) | (beta[w] << 13) | inc);
3442167514Skmacy		}
3443167514Skmacy	}
3444167514Skmacy}
3445167514Skmacy
3446167514Skmacy/**
3447167514Skmacy *	t3_read_hw_mtus - returns the values in the HW MTU table
3448167514Skmacy *	@adap: the adapter
3449167514Skmacy *	@mtus: where to store the HW MTU values
3450167514Skmacy *
3451167514Skmacy *	Reads the HW MTU table.
3452167514Skmacy */
3453167514Skmacyvoid t3_read_hw_mtus(adapter_t *adap, unsigned short mtus[NMTUS])
3454167514Skmacy{
3455167514Skmacy	int i;
3456167514Skmacy
3457167514Skmacy	for (i = 0; i < NMTUS; ++i) {
3458167514Skmacy		unsigned int val;
3459167514Skmacy
3460167514Skmacy		t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
3461167514Skmacy		val = t3_read_reg(adap, A_TP_MTU_TABLE);
3462167514Skmacy		mtus[i] = val & 0x3fff;
3463167514Skmacy	}
3464167514Skmacy}
3465167514Skmacy
3466167514Skmacy/**
3467167514Skmacy *	t3_get_cong_cntl_tab - reads the congestion control table
3468167514Skmacy *	@adap: the adapter
3469167514Skmacy *	@incr: where to store the alpha values
3470167514Skmacy *
3471167514Skmacy *	Reads the additive increments programmed into the HW congestion
3472167514Skmacy *	control table.
3473167514Skmacy */
3474167514Skmacyvoid t3_get_cong_cntl_tab(adapter_t *adap,
3475167514Skmacy			  unsigned short incr[NMTUS][NCCTRL_WIN])
3476167514Skmacy{
3477167514Skmacy	unsigned int mtu, w;
3478167514Skmacy
3479167514Skmacy	for (mtu = 0; mtu < NMTUS; ++mtu)
3480167514Skmacy		for (w = 0; w < NCCTRL_WIN; ++w) {
3481167514Skmacy			t3_write_reg(adap, A_TP_CCTRL_TABLE,
3482167514Skmacy				     0xffff0000 | (mtu << 5) | w);
3483167514Skmacy			incr[mtu][w] = (unsigned short)t3_read_reg(adap,
3484167514Skmacy				        A_TP_CCTRL_TABLE) & 0x1fff;
3485167514Skmacy		}
3486167514Skmacy}
3487167514Skmacy
3488167514Skmacy/**
3489167514Skmacy *	t3_tp_get_mib_stats - read TP's MIB counters
3490167514Skmacy *	@adap: the adapter
3491167514Skmacy *	@tps: holds the returned counter values
3492167514Skmacy *
3493167514Skmacy *	Returns the values of TP's MIB counters.
3494167514Skmacy */
3495167514Skmacyvoid t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps)
3496167514Skmacy{
3497167514Skmacy	t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *)tps,
3498167514Skmacy			 sizeof(*tps) / sizeof(u32), 0);
3499167514Skmacy}
3500167514Skmacy
3501167746Skmacy/**
3502167746Skmacy *	t3_read_pace_tbl - read the pace table
3503167746Skmacy *	@adap: the adapter
3504167746Skmacy *	@pace_vals: holds the returned values
3505167746Skmacy *
3506167746Skmacy *	Returns the values of TP's pace table in nanoseconds.
3507167746Skmacy */
3508167746Skmacyvoid t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED])
3509167746Skmacy{
3510167746Skmacy	unsigned int i, tick_ns = dack_ticks_to_usec(adap, 1000);
3511167746Skmacy
3512167746Skmacy	for (i = 0; i < NTX_SCHED; i++) {
3513167746Skmacy		t3_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i);
3514167746Skmacy		pace_vals[i] = t3_read_reg(adap, A_TP_PACE_TABLE) * tick_ns;
3515167746Skmacy	}
3516167746Skmacy}
3517167746Skmacy
3518167746Skmacy/**
3519167746Skmacy *	t3_set_pace_tbl - set the pace table
3520167746Skmacy *	@adap: the adapter
3521167746Skmacy *	@pace_vals: the pace values in nanoseconds
3522167746Skmacy *	@start: index of the first entry in the HW pace table to set
3523167746Skmacy *	@n: how many entries to set
3524167746Skmacy *
3525167746Skmacy *	Sets (a subset of the) HW pace table.
3526167746Skmacy */
3527167746Skmacyvoid t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals,
3528167746Skmacy		     unsigned int start, unsigned int n)
3529167746Skmacy{
3530167746Skmacy	unsigned int tick_ns = dack_ticks_to_usec(adap, 1000);
3531167746Skmacy
3532167746Skmacy	for ( ; n; n--, start++, pace_vals++)
3533167746Skmacy		t3_write_reg(adap, A_TP_PACE_TABLE, (start << 16) |
3534167746Skmacy			     ((*pace_vals + tick_ns / 2) / tick_ns));
3535167746Skmacy}
3536167746Skmacy
3537167514Skmacy#define ulp_region(adap, name, start, len) \
3538167514Skmacy	t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
3539167514Skmacy	t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
3540167514Skmacy		     (start) + (len) - 1); \
3541167514Skmacy	start += len
3542167514Skmacy
3543167514Skmacy#define ulptx_region(adap, name, start, len) \
3544167514Skmacy	t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
3545167514Skmacy	t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
3546167514Skmacy		     (start) + (len) - 1)
3547167514Skmacy
3548167514Skmacystatic void ulp_config(adapter_t *adap, const struct tp_params *p)
3549167514Skmacy{
3550167514Skmacy	unsigned int m = p->chan_rx_size;
3551167514Skmacy
3552167514Skmacy	ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
3553167514Skmacy	ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
3554167514Skmacy	ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
3555167514Skmacy	ulp_region(adap, STAG, m, p->chan_rx_size / 4);
3556167514Skmacy	ulp_region(adap, RQ, m, p->chan_rx_size / 4);
3557167514Skmacy	ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
3558167514Skmacy	ulp_region(adap, PBL, m, p->chan_rx_size / 4);
3559167514Skmacy	t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
3560167514Skmacy}
3561170654Skmacy
3562170654Skmacy
3563170654Skmacy/**
3564170654Skmacy *	t3_set_proto_sram - set the contents of the protocol sram
3565170654Skmacy *	@adapter: the adapter
3566170654Skmacy *	@data: the protocol image
3567170654Skmacy *
3568170654Skmacy *	Write the contents of the protocol SRAM.
3569170654Skmacy */
3570171471Skmacyint t3_set_proto_sram(adapter_t *adap, const u8 *data)
3571170654Skmacy{
3572170654Skmacy	int i;
3573172096Skmacy	const u32 *buf = (const u32 *)data;
3574170654Skmacy
3575170654Skmacy	for (i = 0; i < PROTO_SRAM_LINES; i++) {
3576171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++));
3577171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++));
3578171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++));
3579171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++));
3580171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++));
3581189643Sgnn
3582170654Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
3583170654Skmacy		if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
3584170654Skmacy			return -EIO;
3585170654Skmacy	}
3586170654Skmacy	return 0;
3587170654Skmacy}
3588167514Skmacy
3589172096Skmacy/**
3590172096Skmacy *	t3_config_trace_filter - configure one of the tracing filters
3591172096Skmacy *	@adapter: the adapter
3592172096Skmacy *	@tp: the desired trace filter parameters
3593172096Skmacy *	@filter_index: which filter to configure
3594172096Skmacy *	@invert: if set non-matching packets are traced instead of matching ones
3595172096Skmacy *	@enable: whether to enable or disable the filter
3596172096Skmacy *
3597172096Skmacy *	Configures one of the tracing filters available in HW.
3598172096Skmacy */
3599167514Skmacyvoid t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp,
3600167514Skmacy			    int filter_index, int invert, int enable)
3601167514Skmacy{
3602167514Skmacy	u32 addr, key[4], mask[4];
3603167514Skmacy
3604167514Skmacy	key[0] = tp->sport | (tp->sip << 16);
3605167514Skmacy	key[1] = (tp->sip >> 16) | (tp->dport << 16);
3606167514Skmacy	key[2] = tp->dip;
3607167514Skmacy	key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
3608167514Skmacy
3609167514Skmacy	mask[0] = tp->sport_mask | (tp->sip_mask << 16);
3610167514Skmacy	mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
3611167514Skmacy	mask[2] = tp->dip_mask;
3612167514Skmacy	mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
3613167514Skmacy
3614167514Skmacy	if (invert)
3615167514Skmacy		key[3] |= (1 << 29);
3616167514Skmacy	if (enable)
3617167514Skmacy		key[3] |= (1 << 28);
3618167514Skmacy
3619167514Skmacy	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
3620167514Skmacy	tp_wr_indirect(adapter, addr++, key[0]);
3621167514Skmacy	tp_wr_indirect(adapter, addr++, mask[0]);
3622167514Skmacy	tp_wr_indirect(adapter, addr++, key[1]);
3623167514Skmacy	tp_wr_indirect(adapter, addr++, mask[1]);
3624167514Skmacy	tp_wr_indirect(adapter, addr++, key[2]);
3625167514Skmacy	tp_wr_indirect(adapter, addr++, mask[2]);
3626167514Skmacy	tp_wr_indirect(adapter, addr++, key[3]);
3627167514Skmacy	tp_wr_indirect(adapter, addr,   mask[3]);
3628167514Skmacy	(void) t3_read_reg(adapter, A_TP_PIO_DATA);
3629167514Skmacy}
3630167514Skmacy
3631167514Skmacy/**
3632189643Sgnn *	t3_query_trace_filter - query a tracing filter
3633189643Sgnn *	@adapter: the adapter
3634189643Sgnn *	@tp: the current trace filter parameters
3635189643Sgnn *	@filter_index: which filter to query
3636189643Sgnn *	@inverted: non-zero if the filter is inverted
3637189643Sgnn *	@enabled: non-zero if the filter is enabled
3638189643Sgnn *
3639189643Sgnn *	Returns the current settings of the specified HW tracing filter.
3640189643Sgnn */
3641189643Sgnnvoid t3_query_trace_filter(adapter_t *adapter, struct trace_params *tp,
3642189643Sgnn			   int filter_index, int *inverted, int *enabled)
3643189643Sgnn{
3644189643Sgnn	u32 addr, key[4], mask[4];
3645189643Sgnn
3646189643Sgnn	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
3647189643Sgnn	key[0]  = tp_rd_indirect(adapter, addr++);
3648189643Sgnn	mask[0] = tp_rd_indirect(adapter, addr++);
3649189643Sgnn	key[1]  = tp_rd_indirect(adapter, addr++);
3650189643Sgnn	mask[1] = tp_rd_indirect(adapter, addr++);
3651189643Sgnn	key[2]  = tp_rd_indirect(adapter, addr++);
3652189643Sgnn	mask[2] = tp_rd_indirect(adapter, addr++);
3653189643Sgnn	key[3]  = tp_rd_indirect(adapter, addr++);
3654189643Sgnn	mask[3] = tp_rd_indirect(adapter, addr);
3655189643Sgnn
3656189643Sgnn	tp->sport = key[0] & 0xffff;
3657189643Sgnn	tp->sip   = (key[0] >> 16) | ((key[1] & 0xffff) << 16);
3658189643Sgnn	tp->dport = key[1] >> 16;
3659189643Sgnn	tp->dip   = key[2];
3660189643Sgnn	tp->proto = key[3] & 0xff;
3661189643Sgnn	tp->vlan  = key[3] >> 8;
3662189643Sgnn	tp->intf  = key[3] >> 20;
3663189643Sgnn
3664189643Sgnn	tp->sport_mask = mask[0] & 0xffff;
3665189643Sgnn	tp->sip_mask   = (mask[0] >> 16) | ((mask[1] & 0xffff) << 16);
3666189643Sgnn	tp->dport_mask = mask[1] >> 16;
3667189643Sgnn	tp->dip_mask   = mask[2];
3668189643Sgnn	tp->proto_mask = mask[3] & 0xff;
3669189643Sgnn	tp->vlan_mask  = mask[3] >> 8;
3670189643Sgnn	tp->intf_mask  = mask[3] >> 20;
3671189643Sgnn
3672189643Sgnn	*inverted = key[3] & (1 << 29);
3673189643Sgnn	*enabled  = key[3] & (1 << 28);
3674189643Sgnn}
3675189643Sgnn
3676189643Sgnn/**
3677167514Skmacy *	t3_config_sched - configure a HW traffic scheduler
3678167514Skmacy *	@adap: the adapter
3679167514Skmacy *	@kbps: target rate in Kbps
3680167514Skmacy *	@sched: the scheduler index
3681167514Skmacy *
3682167746Skmacy *	Configure a Tx HW scheduler for the target rate.
3683167514Skmacy */
3684167514Skmacyint t3_config_sched(adapter_t *adap, unsigned int kbps, int sched)
3685167514Skmacy{
3686167514Skmacy	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
3687167514Skmacy	unsigned int clk = adap->params.vpd.cclk * 1000;
3688167514Skmacy	unsigned int selected_cpt = 0, selected_bpt = 0;
3689167514Skmacy
3690167514Skmacy	if (kbps > 0) {
3691167514Skmacy		kbps *= 125;     /* -> bytes */
3692167514Skmacy		for (cpt = 1; cpt <= 255; cpt++) {
3693167514Skmacy			tps = clk / cpt;
3694167514Skmacy			bpt = (kbps + tps / 2) / tps;
3695167514Skmacy			if (bpt > 0 && bpt <= 255) {
3696167514Skmacy				v = bpt * tps;
3697167514Skmacy				delta = v >= kbps ? v - kbps : kbps - v;
3698176472Skmacy				if (delta < mindelta) {
3699167514Skmacy					mindelta = delta;
3700167514Skmacy					selected_cpt = cpt;
3701167514Skmacy					selected_bpt = bpt;
3702167514Skmacy				}
3703167514Skmacy			} else if (selected_cpt)
3704167514Skmacy				break;
3705167514Skmacy		}
3706167514Skmacy		if (!selected_cpt)
3707167514Skmacy			return -EINVAL;
3708167514Skmacy	}
3709167514Skmacy	t3_write_reg(adap, A_TP_TM_PIO_ADDR,
3710167514Skmacy		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
3711167514Skmacy	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3712167514Skmacy	if (sched & 1)
3713167514Skmacy		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
3714167514Skmacy	else
3715167514Skmacy		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
3716167514Skmacy	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
3717167514Skmacy	return 0;
3718167514Skmacy}
3719167514Skmacy
3720167746Skmacy/**
3721167746Skmacy *	t3_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler
3722167746Skmacy *	@adap: the adapter
3723167746Skmacy *	@sched: the scheduler index
3724167746Skmacy *	@ipg: the interpacket delay in tenths of nanoseconds
3725167746Skmacy *
3726167746Skmacy *	Set the interpacket delay for a HW packet rate scheduler.
3727167746Skmacy */
3728167746Skmacyint t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg)
3729167746Skmacy{
3730167746Skmacy	unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3731167746Skmacy
3732167746Skmacy	/* convert ipg to nearest number of core clocks */
3733167746Skmacy	ipg *= core_ticks_per_usec(adap);
3734167746Skmacy	ipg = (ipg + 5000) / 10000;
3735167746Skmacy	if (ipg > 0xffff)
3736167746Skmacy		return -EINVAL;
3737167746Skmacy
3738167746Skmacy	t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3739167746Skmacy	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3740167746Skmacy	if (sched & 1)
3741167746Skmacy		v = (v & 0xffff) | (ipg << 16);
3742167746Skmacy	else
3743167746Skmacy		v = (v & 0xffff0000) | ipg;
3744167746Skmacy	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
3745167746Skmacy	t3_read_reg(adap, A_TP_TM_PIO_DATA);
3746167746Skmacy	return 0;
3747167746Skmacy}
3748167746Skmacy
3749167746Skmacy/**
3750167746Skmacy *	t3_get_tx_sched - get the configuration of a Tx HW traffic scheduler
3751167746Skmacy *	@adap: the adapter
3752167746Skmacy *	@sched: the scheduler index
3753167746Skmacy *	@kbps: the byte rate in Kbps
3754167746Skmacy *	@ipg: the interpacket delay in tenths of nanoseconds
3755167746Skmacy *
3756167746Skmacy *	Return the current configuration of a HW Tx scheduler.
3757167746Skmacy */
3758167746Skmacyvoid t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps,
3759167746Skmacy		     unsigned int *ipg)
3760167746Skmacy{
3761167746Skmacy	unsigned int v, addr, bpt, cpt;
3762167746Skmacy
3763167746Skmacy	if (kbps) {
3764167746Skmacy		addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
3765167746Skmacy		t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3766167746Skmacy		v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3767167746Skmacy		if (sched & 1)
3768167746Skmacy			v >>= 16;
3769167746Skmacy		bpt = (v >> 8) & 0xff;
3770167746Skmacy		cpt = v & 0xff;
3771167746Skmacy		if (!cpt)
3772167746Skmacy			*kbps = 0;        /* scheduler disabled */
3773167746Skmacy		else {
3774167746Skmacy			v = (adap->params.vpd.cclk * 1000) / cpt;
3775167746Skmacy			*kbps = (v * bpt) / 125;
3776167746Skmacy		}
3777167746Skmacy	}
3778167746Skmacy	if (ipg) {
3779167746Skmacy		addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3780167746Skmacy		t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3781167746Skmacy		v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3782167746Skmacy		if (sched & 1)
3783167746Skmacy			v >>= 16;
3784167746Skmacy		v &= 0xffff;
3785167746Skmacy		*ipg = (10000 * v) / core_ticks_per_usec(adap);
3786167746Skmacy	}
3787167746Skmacy}
3788167746Skmacy
3789172096Skmacy/**
3790172096Skmacy *	tp_init - configure TP
3791172096Skmacy *	@adap: the adapter
3792172096Skmacy *	@p: TP configuration parameters
3793172096Skmacy *
3794172096Skmacy *	Initializes the TP HW module.
3795172096Skmacy */
3796167514Skmacystatic int tp_init(adapter_t *adap, const struct tp_params *p)
3797167514Skmacy{
3798167514Skmacy	int busy = 0;
3799167514Skmacy
3800167514Skmacy	tp_config(adap, p);
3801167514Skmacy	t3_set_vlan_accel(adap, 3, 0);
3802167514Skmacy
3803167514Skmacy	if (is_offload(adap)) {
3804167514Skmacy		tp_set_timers(adap, adap->params.vpd.cclk * 1000);
3805167514Skmacy		t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
3806167514Skmacy		busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
3807167514Skmacy				       0, 1000, 5);
3808167514Skmacy		if (busy)
3809167514Skmacy			CH_ERR(adap, "TP initialization timed out\n");
3810167514Skmacy	}
3811167514Skmacy
3812167514Skmacy	if (!busy)
3813167514Skmacy		t3_write_reg(adap, A_TP_RESET, F_TPRESET);
3814167514Skmacy	return busy;
3815167514Skmacy}
3816167514Skmacy
3817172096Skmacy/**
3818172096Skmacy *	t3_mps_set_active_ports - configure port failover
3819172096Skmacy *	@adap: the adapter
3820172096Skmacy *	@port_mask: bitmap of active ports
3821172096Skmacy *
3822172096Skmacy *	Sets the active ports according to the supplied bitmap.
3823172096Skmacy */
3824167514Skmacyint t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask)
3825167514Skmacy{
3826167514Skmacy	if (port_mask & ~((1 << adap->params.nports) - 1))
3827167514Skmacy		return -EINVAL;
3828167514Skmacy	t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
3829167514Skmacy			 port_mask << S_PORT0ACTIVE);
3830167514Skmacy	return 0;
3831167514Skmacy}
3832167514Skmacy
3833172096Skmacy/**
3834172096Skmacy * 	chan_init_hw - channel-dependent HW initialization
3835172096Skmacy *	@adap: the adapter
3836172096Skmacy *	@chan_map: bitmap of Tx channels being used
3837172096Skmacy *
3838172096Skmacy *	Perform the bits of HW initialization that are dependent on the Tx
3839172096Skmacy *	channels being used.
3840167514Skmacy */
3841170654Skmacystatic void chan_init_hw(adapter_t *adap, unsigned int chan_map)
3842167514Skmacy{
3843167514Skmacy	int i;
3844167514Skmacy
3845170654Skmacy	if (chan_map != 3) {                                 /* one channel */
3846167514Skmacy		t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
3847167514Skmacy		t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
3848170654Skmacy		t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT |
3849170654Skmacy			     (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE :
3850170654Skmacy					      F_TPTXPORT1EN | F_PORT1ACTIVE));
3851170654Skmacy		t3_write_reg(adap, A_PM1_TX_CFG,
3852170654Skmacy			     chan_map == 1 ? 0xffffffff : 0);
3853172096Skmacy		if (chan_map == 2)
3854172096Skmacy			t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3855172096Skmacy				     V_TX_MOD_QUEUE_REQ_MAP(0xff));
3856172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xd9c8);
3857172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfbea);
3858170654Skmacy	} else {                                             /* two channels */
3859167514Skmacy		t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
3860167514Skmacy		t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
3861167514Skmacy		t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
3862167514Skmacy			     V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
3863167514Skmacy		t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
3864167514Skmacy			     F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
3865167514Skmacy			     F_ENFORCEPKT);
3866167514Skmacy		t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
3867167514Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
3868167514Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3869167514Skmacy			     V_TX_MOD_QUEUE_REQ_MAP(0xaa));
3870167514Skmacy		for (i = 0; i < 16; i++)
3871167514Skmacy			t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
3872167514Skmacy				     (i << 16) | 0x1010);
3873172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xba98);
3874172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfedc);
3875167514Skmacy	}
3876167514Skmacy}
3877167514Skmacy
3878167514Skmacystatic int calibrate_xgm(adapter_t *adapter)
3879167514Skmacy{
3880167514Skmacy	if (uses_xaui(adapter)) {
3881167514Skmacy		unsigned int v, i;
3882167514Skmacy
3883167514Skmacy		for (i = 0; i < 5; ++i) {
3884167514Skmacy			t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
3885167514Skmacy			(void) t3_read_reg(adapter, A_XGM_XAUI_IMP);
3886171471Skmacy			msleep(1);
3887167514Skmacy			v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
3888167514Skmacy			if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
3889167514Skmacy				t3_write_reg(adapter, A_XGM_XAUI_IMP,
3890167514Skmacy					     V_XAUIIMP(G_CALIMP(v) >> 2));
3891167514Skmacy				return 0;
3892167514Skmacy			}
3893167514Skmacy		}
3894167514Skmacy		CH_ERR(adapter, "MAC calibration failed\n");
3895167514Skmacy		return -1;
3896167514Skmacy	} else {
3897167514Skmacy		t3_write_reg(adapter, A_XGM_RGMII_IMP,
3898167514Skmacy			     V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3899167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3900167514Skmacy				 F_XGM_IMPSETUPDATE);
3901167514Skmacy	}
3902167514Skmacy	return 0;
3903167514Skmacy}
3904167514Skmacy
3905167514Skmacystatic void calibrate_xgm_t3b(adapter_t *adapter)
3906167514Skmacy{
3907167514Skmacy	if (!uses_xaui(adapter)) {
3908167514Skmacy		t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
3909167514Skmacy			     F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3910167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
3911167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
3912167514Skmacy				 F_XGM_IMPSETUPDATE);
3913167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3914167514Skmacy				 0);
3915167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
3916167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
3917167514Skmacy	}
3918167514Skmacy}
3919167514Skmacy
3920167514Skmacystruct mc7_timing_params {
3921167514Skmacy	unsigned char ActToPreDly;
3922167514Skmacy	unsigned char ActToRdWrDly;
3923167514Skmacy	unsigned char PreCyc;
3924167514Skmacy	unsigned char RefCyc[5];
3925167514Skmacy	unsigned char BkCyc;
3926167514Skmacy	unsigned char WrToRdDly;
3927167514Skmacy	unsigned char RdToWrDly;
3928167514Skmacy};
3929167514Skmacy
3930167514Skmacy/*
3931167514Skmacy * Write a value to a register and check that the write completed.  These
3932167514Skmacy * writes normally complete in a cycle or two, so one read should suffice.
3933167514Skmacy * The very first read exists to flush the posted write to the device.
3934167514Skmacy */
3935167514Skmacystatic int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val)
3936167514Skmacy{
3937167514Skmacy	t3_write_reg(adapter,	addr, val);
3938167514Skmacy	(void) t3_read_reg(adapter, addr);                   /* flush */
3939167514Skmacy	if (!(t3_read_reg(adapter, addr) & F_BUSY))
3940167514Skmacy		return 0;
3941167514Skmacy	CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
3942167514Skmacy	return -EIO;
3943167514Skmacy}
3944167514Skmacy
3945167514Skmacystatic int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
3946167514Skmacy{
3947167514Skmacy	static const unsigned int mc7_mode[] = {
3948167514Skmacy		0x632, 0x642, 0x652, 0x432, 0x442
3949167514Skmacy	};
3950167514Skmacy	static const struct mc7_timing_params mc7_timings[] = {
3951167514Skmacy		{ 12, 3, 4, { 20, 28, 34, 52, 0 }, 15, 6, 4 },
3952167514Skmacy		{ 12, 4, 5, { 20, 28, 34, 52, 0 }, 16, 7, 4 },
3953167514Skmacy		{ 12, 5, 6, { 20, 28, 34, 52, 0 }, 17, 8, 4 },
3954167514Skmacy		{ 9,  3, 4, { 15, 21, 26, 39, 0 }, 12, 6, 4 },
3955167514Skmacy		{ 9,  4, 5, { 15, 21, 26, 39, 0 }, 13, 7, 4 }
3956167514Skmacy	};
3957167514Skmacy
3958167514Skmacy	u32 val;
3959167514Skmacy	unsigned int width, density, slow, attempts;
3960167514Skmacy	adapter_t *adapter = mc7->adapter;
3961167514Skmacy	const struct mc7_timing_params *p = &mc7_timings[mem_type];
3962167514Skmacy
3963170654Skmacy	if (!mc7->size)
3964169978Skmacy		return 0;
3965170654Skmacy
3966167514Skmacy	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
3967167514Skmacy	slow = val & F_SLOW;
3968167514Skmacy	width = G_WIDTH(val);
3969167514Skmacy	density = G_DEN(val);
3970167514Skmacy
3971167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
3972167514Skmacy	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);  /* flush */
3973171471Skmacy	msleep(1);
3974167514Skmacy
3975167514Skmacy	if (!slow) {
3976167514Skmacy		t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
3977167514Skmacy		(void) t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
3978171471Skmacy		msleep(1);
3979167514Skmacy		if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
3980167514Skmacy		    (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
3981167514Skmacy			CH_ERR(adapter, "%s MC7 calibration timed out\n",
3982167514Skmacy			       mc7->name);
3983167514Skmacy			goto out_fail;
3984167514Skmacy		}
3985167514Skmacy	}
3986167514Skmacy
3987167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
3988167514Skmacy		     V_ACTTOPREDLY(p->ActToPreDly) |
3989167514Skmacy		     V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
3990167514Skmacy		     V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
3991167514Skmacy		     V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
3992167514Skmacy
3993167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
3994167514Skmacy		     val | F_CLKEN | F_TERM150);
3995167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
3996167514Skmacy
3997167514Skmacy	if (!slow)
3998167514Skmacy		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
3999167514Skmacy				 F_DLLENB);
4000167514Skmacy	udelay(1);
4001167514Skmacy
4002167514Skmacy	val = slow ? 3 : 6;
4003167514Skmacy	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
4004167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
4005167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
4006167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
4007167514Skmacy		goto out_fail;
4008167514Skmacy
4009167514Skmacy	if (!slow) {
4010167514Skmacy		t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
4011167514Skmacy		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL,
4012167514Skmacy				 F_DLLRST, 0);
4013167514Skmacy		udelay(5);
4014167514Skmacy	}
4015167514Skmacy
4016167514Skmacy	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
4017167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
4018167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
4019167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
4020167514Skmacy		       mc7_mode[mem_type]) ||
4021167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
4022167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
4023167514Skmacy		goto out_fail;
4024167514Skmacy
4025167514Skmacy	/* clock value is in KHz */
4026167514Skmacy	mc7_clock = mc7_clock * 7812 + mc7_clock / 2;  /* ns */
4027167514Skmacy	mc7_clock /= 1000000;                          /* KHz->MHz, ns->us */
4028167514Skmacy
4029167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_REF,
4030167514Skmacy		     F_PERREFEN | V_PREREFDIV(mc7_clock));
4031167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */
4032167514Skmacy
4033167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_ECC,
4034167514Skmacy		     F_ECCGENEN | F_ECCCHKEN);
4035167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
4036167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
4037167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
4038167514Skmacy		     (mc7->size << width) - 1);
4039167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
4040167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */
4041167514Skmacy
4042167514Skmacy	attempts = 50;
4043167514Skmacy	do {
4044171471Skmacy		msleep(250);
4045167514Skmacy		val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
4046167514Skmacy	} while ((val & F_BUSY) && --attempts);
4047167514Skmacy	if (val & F_BUSY) {
4048167514Skmacy		CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
4049167514Skmacy		goto out_fail;
4050167514Skmacy	}
4051167514Skmacy
4052167514Skmacy	/* Enable normal memory accesses. */
4053167514Skmacy	t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
4054167514Skmacy	return 0;
4055167514Skmacy
4056167514Skmacy out_fail:
4057167514Skmacy	return -1;
4058167514Skmacy}
4059167514Skmacy
4060167514Skmacystatic void config_pcie(adapter_t *adap)
4061167514Skmacy{
4062167514Skmacy	static const u16 ack_lat[4][6] = {
4063167514Skmacy		{ 237, 416, 559, 1071, 2095, 4143 },
4064167514Skmacy		{ 128, 217, 289, 545, 1057, 2081 },
4065167514Skmacy		{ 73, 118, 154, 282, 538, 1050 },
4066167514Skmacy		{ 67, 107, 86, 150, 278, 534 }
4067167514Skmacy	};
4068167514Skmacy	static const u16 rpl_tmr[4][6] = {
4069167514Skmacy		{ 711, 1248, 1677, 3213, 6285, 12429 },
4070167514Skmacy		{ 384, 651, 867, 1635, 3171, 6243 },
4071167514Skmacy		{ 219, 354, 462, 846, 1614, 3150 },
4072167514Skmacy		{ 201, 321, 258, 450, 834, 1602 }
4073167514Skmacy	};
4074167514Skmacy
4075197791Snp	u16 val, devid;
4076167514Skmacy	unsigned int log2_width, pldsize;
4077167514Skmacy	unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
4078167514Skmacy
4079167514Skmacy	t3_os_pci_read_config_2(adap,
4080167514Skmacy				adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
4081167514Skmacy				&val);
4082167514Skmacy	pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
4083167514Skmacy
4084197791Snp	/*
4085197791Snp	 * Gen2 adapter pcie bridge compatibility requires minimum
4086197791Snp	 * Max_Read_Request_size
4087197791Snp	 */
4088197791Snp	t3_os_pci_read_config_2(adap, 0x2, &devid);
4089197791Snp	if (devid == 0x37) {
4090197791Snp		t3_os_pci_write_config_2(adap,
4091197791Snp		    adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
4092197791Snp		    val & ~PCI_EXP_DEVCTL_READRQ & ~PCI_EXP_DEVCTL_PAYLOAD);
4093197791Snp		pldsize = 0;
4094197791Snp	}
4095197791Snp
4096167514Skmacy	t3_os_pci_read_config_2(adap,
4097167514Skmacy				adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
4098167514Skmacy			       	&val);
4099167514Skmacy
4100167514Skmacy	fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
4101167514Skmacy	fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
4102167514Skmacy			G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
4103167514Skmacy	log2_width = fls(adap->params.pci.width) - 1;
4104167514Skmacy	acklat = ack_lat[log2_width][pldsize];
4105167514Skmacy	if (val & 1)                            /* check LOsEnable */
4106167514Skmacy		acklat += fst_trn_tx * 4;
4107167514Skmacy	rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
4108167514Skmacy
4109167514Skmacy	if (adap->params.rev == 0)
4110167514Skmacy		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
4111167514Skmacy				 V_T3A_ACKLAT(M_T3A_ACKLAT),
4112167514Skmacy				 V_T3A_ACKLAT(acklat));
4113167514Skmacy	else
4114167514Skmacy		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
4115167514Skmacy				 V_ACKLAT(acklat));
4116167514Skmacy
4117167514Skmacy	t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
4118167514Skmacy			 V_REPLAYLMT(rpllmt));
4119167514Skmacy
4120167514Skmacy	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
4121176472Skmacy	t3_set_reg_field(adap, A_PCIE_CFG, 0,
4122189643Sgnn			 F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST |
4123176472Skmacy			 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
4124167514Skmacy}
4125167514Skmacy
4126172096Skmacy/**
4127172096Skmacy * 	t3_init_hw - initialize and configure T3 HW modules
4128172096Skmacy * 	@adapter: the adapter
4129172096Skmacy * 	@fw_params: initial parameters to pass to firmware (optional)
4130167514Skmacy *
4131172096Skmacy *	Initialize and configure T3 HW modules.  This performs the
4132172096Skmacy *	initialization steps that need to be done once after a card is reset.
4133172096Skmacy *	MAC and PHY initialization is handled separarely whenever a port is
4134172096Skmacy *	enabled.
4135172096Skmacy *
4136172096Skmacy *	@fw_params are passed to FW and their value is platform dependent.
4137172096Skmacy *	Only the top 8 bits are available for use, the rest must be 0.
4138167514Skmacy */
4139167514Skmacyint t3_init_hw(adapter_t *adapter, u32 fw_params)
4140167514Skmacy{
4141176472Skmacy	int err = -EIO, attempts, i;
4142167514Skmacy	const struct vpd_params *vpd = &adapter->params.vpd;
4143167514Skmacy
4144167514Skmacy	if (adapter->params.rev > 0)
4145167514Skmacy		calibrate_xgm_t3b(adapter);
4146167514Skmacy	else if (calibrate_xgm(adapter))
4147167514Skmacy		goto out_err;
4148167514Skmacy
4149171471Skmacy	if (adapter->params.nports > 2)
4150197791Snp		t3_mac_init(&adap2pinfo(adapter, 0)->mac);
4151170654Skmacy
4152167514Skmacy	if (vpd->mclk) {
4153167514Skmacy		partition_mem(adapter, &adapter->params.tp);
4154167514Skmacy
4155167514Skmacy		if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
4156167514Skmacy		    mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
4157167514Skmacy		    mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
4158167514Skmacy		    t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
4159167514Skmacy			        adapter->params.mc5.nfilters,
4160167514Skmacy			       	adapter->params.mc5.nroutes))
4161167514Skmacy			goto out_err;
4162176472Skmacy
4163176472Skmacy		for (i = 0; i < 32; i++)
4164176472Skmacy			if (clear_sge_ctxt(adapter, i, F_CQ))
4165176472Skmacy				goto out_err;
4166167514Skmacy	}
4167167514Skmacy
4168167514Skmacy	if (tp_init(adapter, &adapter->params.tp))
4169167514Skmacy		goto out_err;
4170167514Skmacy
4171167514Skmacy	t3_tp_set_coalescing_size(adapter,
4172167514Skmacy				  min(adapter->params.sge.max_pkt_size,
4173167514Skmacy				      MAX_RX_COALESCING_LEN), 1);
4174167514Skmacy	t3_tp_set_max_rxsize(adapter,
4175167514Skmacy			     min(adapter->params.sge.max_pkt_size, 16384U));
4176167514Skmacy	ulp_config(adapter, &adapter->params.tp);
4177167514Skmacy	if (is_pcie(adapter))
4178167514Skmacy		config_pcie(adapter);
4179167514Skmacy	else
4180176472Skmacy		t3_set_reg_field(adapter, A_PCIX_CFG, 0,
4181176472Skmacy				 F_DMASTOPEN | F_CLIDECEN);
4182167514Skmacy
4183176472Skmacy	if (adapter->params.rev == T3_REV_C)
4184176472Skmacy		t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0,
4185176472Skmacy				 F_CFG_CQE_SOP_MASK);
4186176472Skmacy
4187170654Skmacy	t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
4188172096Skmacy	t3_write_reg(adapter, A_PM1_RX_MODE, 0);
4189172096Skmacy	t3_write_reg(adapter, A_PM1_TX_MODE, 0);
4190170654Skmacy	chan_init_hw(adapter, adapter->params.chan_map);
4191167514Skmacy	t3_sge_init(adapter, &adapter->params.sge);
4192219945Snp	t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN);
4193167514Skmacy
4194180583Skmacy	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
4195180583Skmacy
4196167514Skmacy	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
4197167514Skmacy	t3_write_reg(adapter, A_CIM_BOOT_CFG,
4198167514Skmacy		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
4199167514Skmacy	(void) t3_read_reg(adapter, A_CIM_BOOT_CFG);    /* flush */
4200167514Skmacy
4201176472Skmacy	attempts = 100;
4202167514Skmacy	do {                          /* wait for uP to initialize */
4203171471Skmacy		msleep(20);
4204167514Skmacy	} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
4205169978Skmacy	if (!attempts) {
4206169978Skmacy		CH_ERR(adapter, "uP initialization timed out\n");
4207167514Skmacy		goto out_err;
4208169978Skmacy	}
4209170654Skmacy
4210167514Skmacy	err = 0;
4211167514Skmacy out_err:
4212167514Skmacy	return err;
4213167514Skmacy}
4214167514Skmacy
4215167514Skmacy/**
4216167514Skmacy *	get_pci_mode - determine a card's PCI mode
4217167514Skmacy *	@adapter: the adapter
4218167514Skmacy *	@p: where to store the PCI settings
4219167514Skmacy *
4220167514Skmacy *	Determines a card's PCI mode and associated parameters, such as speed
4221167514Skmacy *	and width.
4222167514Skmacy */
4223167514Skmacystatic void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p)
4224167514Skmacy{
4225167514Skmacy	static unsigned short speed_map[] = { 33, 66, 100, 133 };
4226167514Skmacy	u32 pci_mode, pcie_cap;
4227167514Skmacy
4228167514Skmacy	pcie_cap = t3_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
4229167514Skmacy	if (pcie_cap) {
4230167514Skmacy		u16 val;
4231167514Skmacy
4232167514Skmacy		p->variant = PCI_VARIANT_PCIE;
4233167514Skmacy		p->pcie_cap_addr = pcie_cap;
4234167514Skmacy		t3_os_pci_read_config_2(adapter, pcie_cap + PCI_EXP_LNKSTA,
4235167514Skmacy					&val);
4236167514Skmacy		p->width = (val >> 4) & 0x3f;
4237167514Skmacy		return;
4238167514Skmacy	}
4239167514Skmacy
4240167514Skmacy	pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
4241167514Skmacy	p->speed = speed_map[G_PCLKRANGE(pci_mode)];
4242167514Skmacy	p->width = (pci_mode & F_64BIT) ? 64 : 32;
4243167514Skmacy	pci_mode = G_PCIXINITPAT(pci_mode);
4244167514Skmacy	if (pci_mode == 0)
4245167514Skmacy		p->variant = PCI_VARIANT_PCI;
4246167514Skmacy	else if (pci_mode < 4)
4247167514Skmacy		p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
4248167514Skmacy	else if (pci_mode < 8)
4249167514Skmacy		p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
4250167514Skmacy	else
4251167514Skmacy		p->variant = PCI_VARIANT_PCIX_266_MODE2;
4252167514Skmacy}
4253167514Skmacy
4254167514Skmacy/**
4255167514Skmacy *	init_link_config - initialize a link's SW state
4256167514Skmacy *	@lc: structure holding the link state
4257172096Skmacy *	@caps: link capabilities
4258167514Skmacy *
4259167514Skmacy *	Initializes the SW state maintained for each link, including the link's
4260167514Skmacy *	capabilities and default speed/duplex/flow-control/autonegotiation
4261167514Skmacy *	settings.
4262167514Skmacy */
4263167514Skmacystatic void __devinit init_link_config(struct link_config *lc,
4264167514Skmacy				       unsigned int caps)
4265167514Skmacy{
4266167514Skmacy	lc->supported = caps;
4267167514Skmacy	lc->requested_speed = lc->speed = SPEED_INVALID;
4268167514Skmacy	lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
4269167514Skmacy	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
4270167514Skmacy	if (lc->supported & SUPPORTED_Autoneg) {
4271167514Skmacy		lc->advertising = lc->supported;
4272167514Skmacy		lc->autoneg = AUTONEG_ENABLE;
4273167514Skmacy		lc->requested_fc |= PAUSE_AUTONEG;
4274167514Skmacy	} else {
4275167514Skmacy		lc->advertising = 0;
4276167514Skmacy		lc->autoneg = AUTONEG_DISABLE;
4277167514Skmacy	}
4278167514Skmacy}
4279167514Skmacy
4280167514Skmacy/**
4281167514Skmacy *	mc7_calc_size - calculate MC7 memory size
4282167514Skmacy *	@cfg: the MC7 configuration
4283167514Skmacy *
4284167514Skmacy *	Calculates the size of an MC7 memory in bytes from the value of its
4285167514Skmacy *	configuration register.
4286167514Skmacy */
4287167514Skmacystatic unsigned int __devinit mc7_calc_size(u32 cfg)
4288167514Skmacy{
4289167514Skmacy	unsigned int width = G_WIDTH(cfg);
4290167514Skmacy	unsigned int banks = !!(cfg & F_BKS) + 1;
4291167514Skmacy	unsigned int org = !!(cfg & F_ORG) + 1;
4292167514Skmacy	unsigned int density = G_DEN(cfg);
4293167514Skmacy	unsigned int MBs = ((256 << density) * banks) / (org << width);
4294167514Skmacy
4295167514Skmacy	return MBs << 20;
4296167514Skmacy}
4297167514Skmacy
4298167514Skmacystatic void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7,
4299167514Skmacy			       unsigned int base_addr, const char *name)
4300167514Skmacy{
4301167514Skmacy	u32 cfg;
4302167514Skmacy
4303167514Skmacy	mc7->adapter = adapter;
4304167514Skmacy	mc7->name = name;
4305167514Skmacy	mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
4306167514Skmacy	cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
4307169978Skmacy	mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
4308167514Skmacy	mc7->width = G_WIDTH(cfg);
4309167514Skmacy}
4310167514Skmacy
4311167514Skmacyvoid mac_prep(struct cmac *mac, adapter_t *adapter, int index)
4312167514Skmacy{
4313197791Snp	u16 devid;
4314197791Snp
4315167514Skmacy	mac->adapter = adapter;
4316170654Skmacy	mac->multiport = adapter->params.nports > 2;
4317170654Skmacy	if (mac->multiport) {
4318170654Skmacy		mac->ext_port = (unsigned char)index;
4319170654Skmacy		mac->nucast = 8;
4320170654Skmacy	} else
4321170654Skmacy		mac->nucast = 1;
4322170654Skmacy
4323197791Snp	/* Gen2 adapter uses VPD xauicfg[] to notify driver which MAC
4324197791Snp	   is connected to each port, its suppose to be using xgmac0 for both ports
4325197791Snp	 */
4326197791Snp	t3_os_pci_read_config_2(adapter, 0x2, &devid);
4327197791Snp
4328197791Snp	if (mac->multiport ||
4329197791Snp		(!adapter->params.vpd.xauicfg[1] && (devid==0x37)))
4330197791Snp			index  = 0;
4331197791Snp
4332167514Skmacy	mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
4333167514Skmacy
4334167514Skmacy	if (adapter->params.rev == 0 && uses_xaui(adapter)) {
4335167514Skmacy		t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
4336167514Skmacy			     is_10G(adapter) ? 0x2901c04 : 0x2301c04);
4337167514Skmacy		t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
4338167514Skmacy				 F_ENRGMII, 0);
4339167514Skmacy	}
4340167514Skmacy}
4341167514Skmacy
4342172096Skmacy/**
4343172096Skmacy *	early_hw_init - HW initialization done at card detection time
4344172096Skmacy *	@adapter: the adapter
4345172096Skmacy *	@ai: contains information about the adapter type and properties
4346172096Skmacy *
4347172096Skmacy *	Perfoms the part of HW initialization that is done early on when the
4348172096Skmacy *	driver first detecs the card.  Most of the HW state is initialized
4349172096Skmacy *	lazily later on when a port or an offload function are first used.
4350172096Skmacy */
4351167514Skmacyvoid early_hw_init(adapter_t *adapter, const struct adapter_info *ai)
4352167514Skmacy{
4353170654Skmacy	u32 val = V_PORTSPEED(is_10G(adapter) || adapter->params.nports > 2 ?
4354170654Skmacy			      3 : 2);
4355189643Sgnn	u32 gpio_out = ai->gpio_out;
4356167514Skmacy
4357167514Skmacy	mi1_init(adapter, ai);
4358167514Skmacy	t3_write_reg(adapter, A_I2C_CFG,                  /* set for 80KHz */
4359167514Skmacy		     V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
4360167514Skmacy	t3_write_reg(adapter, A_T3DBG_GPIO_EN,
4361189643Sgnn		     gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
4362169978Skmacy	t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
4363176472Skmacy	t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff));
4364170654Skmacy
4365167514Skmacy	if (adapter->params.rev == 0 || !uses_xaui(adapter))
4366167514Skmacy		val |= F_ENRGMII;
4367167514Skmacy
4368167514Skmacy	/* Enable MAC clocks so we can access the registers */
4369167514Skmacy	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
4370167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
4371167514Skmacy
4372167514Skmacy	val |= F_CLKDIVRESET_;
4373167514Skmacy	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
4374167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
4375167514Skmacy	t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
4376167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
4377167514Skmacy}
4378167514Skmacy
4379172096Skmacy/**
4380172096Skmacy *	t3_reset_adapter - reset the adapter
4381172096Skmacy *	@adapter: the adapter
4382172096Skmacy *
4383172096Skmacy * 	Reset the adapter.
4384167514Skmacy */
4385189643Sgnnint t3_reset_adapter(adapter_t *adapter)
4386167514Skmacy{
4387189643Sgnn	int i, save_and_restore_pcie =
4388167746Skmacy	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
4389167746Skmacy	uint16_t devid = 0;
4390167514Skmacy
4391167746Skmacy	if (save_and_restore_pcie)
4392167514Skmacy		t3_os_pci_save_state(adapter);
4393167514Skmacy	t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
4394167514Skmacy
4395167514Skmacy 	/*
4396167514Skmacy	 * Delay. Give Some time to device to reset fully.
4397167514Skmacy	 * XXX The delay time should be modified.
4398167514Skmacy	 */
4399167514Skmacy	for (i = 0; i < 10; i++) {
4400171471Skmacy		msleep(50);
4401167514Skmacy		t3_os_pci_read_config_2(adapter, 0x00, &devid);
4402167514Skmacy		if (devid == 0x1425)
4403167514Skmacy			break;
4404167514Skmacy	}
4405167514Skmacy
4406167514Skmacy	if (devid != 0x1425)
4407167514Skmacy		return -1;
4408167514Skmacy
4409167746Skmacy	if (save_and_restore_pcie)
4410167514Skmacy		t3_os_pci_restore_state(adapter);
4411167514Skmacy	return 0;
4412167514Skmacy}
4413167514Skmacy
4414181614Skmacystatic int init_parity(adapter_t *adap)
4415176472Skmacy{
4416176472Skmacy	int i, err, addr;
4417176472Skmacy
4418176472Skmacy	if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
4419176472Skmacy		return -EBUSY;
4420176472Skmacy
4421176472Skmacy	for (err = i = 0; !err && i < 16; i++)
4422176472Skmacy		err = clear_sge_ctxt(adap, i, F_EGRESS);
4423176472Skmacy	for (i = 0xfff0; !err && i <= 0xffff; i++)
4424176472Skmacy		err = clear_sge_ctxt(adap, i, F_EGRESS);
4425176472Skmacy	for (i = 0; !err && i < SGE_QSETS; i++)
4426176472Skmacy		err = clear_sge_ctxt(adap, i, F_RESPONSEQ);
4427176472Skmacy	if (err)
4428176472Skmacy		return err;
4429176472Skmacy
4430176472Skmacy	t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0);
4431176472Skmacy	for (i = 0; i < 4; i++)
4432176472Skmacy		for (addr = 0; addr <= M_IBQDBGADDR; addr++) {
4433176472Skmacy			t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN |
4434176472Skmacy				     F_IBQDBGWR | V_IBQDBGQID(i) |
4435176472Skmacy				     V_IBQDBGADDR(addr));
4436176472Skmacy			err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG,
4437176472Skmacy					      F_IBQDBGBUSY, 0, 2, 1);
4438176472Skmacy			if (err)
4439176472Skmacy				return err;
4440176472Skmacy		}
4441176472Skmacy	return 0;
4442176472Skmacy}
4443176472Skmacy
4444172096Skmacy/**
4445172096Skmacy *	t3_prep_adapter - prepare SW and HW for operation
4446172096Skmacy *	@adapter: the adapter
4447172096Skmacy *	@ai: contains information about the adapter type and properties
4448172096Skmacy *
4449172096Skmacy *	Initialize adapter SW state for the various HW modules, set initial
4450172096Skmacy *	values for some adapter tunables, take PHYs out of reset, and
4451172096Skmacy *	initialize the MDIO interface.
4452167514Skmacy */
4453167514Skmacyint __devinit t3_prep_adapter(adapter_t *adapter,
4454167514Skmacy			      const struct adapter_info *ai, int reset)
4455167514Skmacy{
4456167514Skmacy	int ret;
4457167514Skmacy	unsigned int i, j = 0;
4458167514Skmacy
4459167514Skmacy	get_pci_mode(adapter, &adapter->params.pci);
4460167514Skmacy
4461167514Skmacy	adapter->params.info = ai;
4462170654Skmacy	adapter->params.nports = ai->nports0 + ai->nports1;
4463201907Snp	adapter->params.chan_map = (!!ai->nports0) | (!!ai->nports1 << 1);
4464167514Skmacy	adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
4465189643Sgnn
4466189643Sgnn	/*
4467189643Sgnn	 * We used to only run the "adapter check task" once a second if
4468189643Sgnn	 * we had PHYs which didn't support interrupts (we would check
4469189643Sgnn	 * their link status once a second).  Now we check other conditions
4470189643Sgnn	 * in that routine which would [potentially] impose a very high
4471189643Sgnn	 * interrupt load on the system.  As such, we now always scan the
4472189643Sgnn	 * adapter state once a second ...
4473189643Sgnn	 */
4474189643Sgnn	adapter->params.linkpoll_period = 10;
4475189643Sgnn
4476171471Skmacy	if (adapter->params.nports > 2)
4477171471Skmacy		adapter->params.stats_update_period = VSC_STATS_ACCUM_SECS;
4478171471Skmacy	else
4479171471Skmacy		adapter->params.stats_update_period = is_10G(adapter) ?
4480171471Skmacy			MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
4481167514Skmacy	adapter->params.pci.vpd_cap_addr =
4482167514Skmacy		t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD);
4483167514Skmacy
4484167514Skmacy	ret = get_vpd_params(adapter, &adapter->params.vpd);
4485171471Skmacy	if (ret < 0)
4486167514Skmacy		return ret;
4487171471Skmacy
4488167514Skmacy	if (reset && t3_reset_adapter(adapter))
4489167514Skmacy		return -1;
4490167514Skmacy
4491167514Skmacy	if (adapter->params.vpd.mclk) {
4492167514Skmacy		struct tp_params *p = &adapter->params.tp;
4493167514Skmacy
4494167514Skmacy		mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
4495167514Skmacy		mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
4496167514Skmacy		mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
4497167514Skmacy
4498170654Skmacy		p->nchan = adapter->params.chan_map == 3 ? 2 : 1;
4499167514Skmacy		p->pmrx_size = t3_mc7_size(&adapter->pmrx);
4500167514Skmacy		p->pmtx_size = t3_mc7_size(&adapter->pmtx);
4501167514Skmacy		p->cm_size = t3_mc7_size(&adapter->cm);
4502167514Skmacy		p->chan_rx_size = p->pmrx_size / 2;     /* only 1 Rx channel */
4503167514Skmacy		p->chan_tx_size = p->pmtx_size / p->nchan;
4504167514Skmacy		p->rx_pg_size = 64 * 1024;
4505167514Skmacy		p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
4506167514Skmacy		p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
4507167514Skmacy		p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
4508167514Skmacy		p->ntimer_qs = p->cm_size >= (128 << 20) ||
4509167514Skmacy			       adapter->params.rev > 0 ? 12 : 6;
4510170654Skmacy		p->tre = fls(adapter->params.vpd.cclk / (1000 / TP_TMR_RES)) -
4511170654Skmacy			 1;
4512167746Skmacy		p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */
4513169978Skmacy	}
4514170654Skmacy
4515169978Skmacy	adapter->params.offload = t3_mc7_size(&adapter->pmrx) &&
4516170654Skmacy				  t3_mc7_size(&adapter->pmtx) &&
4517170654Skmacy				  t3_mc7_size(&adapter->cm);
4518167514Skmacy
4519205950Snp	t3_sge_prep(adapter, &adapter->params.sge);
4520205950Snp
4521169978Skmacy	if (is_offload(adapter)) {
4522167514Skmacy		adapter->params.mc5.nservers = DEFAULT_NSERVERS;
4523189643Sgnn		/* PR 6487. TOE and filtering are mutually exclusive */
4524189643Sgnn		adapter->params.mc5.nfilters = 0;
4525167514Skmacy		adapter->params.mc5.nroutes = 0;
4526167514Skmacy		t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
4527167514Skmacy
4528167514Skmacy		init_mtus(adapter->params.mtus);
4529167514Skmacy		init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
4530167514Skmacy	}
4531167514Skmacy
4532167514Skmacy	early_hw_init(adapter, ai);
4533176472Skmacy	ret = init_parity(adapter);
4534176472Skmacy	if (ret)
4535176472Skmacy		return ret;
4536167514Skmacy
4537171471Skmacy	if (adapter->params.nports > 2 &&
4538171471Skmacy	    (ret = t3_vsc7323_init(adapter, adapter->params.nports)))
4539171471Skmacy		return ret;
4540171471Skmacy
4541167514Skmacy	for_each_port(adapter, i) {
4542167514Skmacy		u8 hw_addr[6];
4543176472Skmacy		const struct port_type_info *pti;
4544170654Skmacy		struct port_info *p = adap2pinfo(adapter, i);
4545167514Skmacy
4546189643Sgnn		for (;;) {
4547189643Sgnn			unsigned port_type = adapter->params.vpd.port_type[j];
4548189643Sgnn			if (port_type) {
4549189643Sgnn				if (port_type < ARRAY_SIZE(port_types)) {
4550189643Sgnn					pti = &port_types[port_type];
4551189643Sgnn					break;
4552189643Sgnn				} else
4553189643Sgnn					return -EINVAL;
4554189643Sgnn			}
4555189643Sgnn			j++;
4556189643Sgnn			if (j >= ARRAY_SIZE(adapter->params.vpd.port_type))
4557189643Sgnn				return -EINVAL;
4558189643Sgnn		}
4559197791Snp		ret = pti->phy_prep(p, ai->phy_base_addr + j,
4560176472Skmacy				    ai->mdio_ops);
4561176472Skmacy		if (ret)
4562176472Skmacy			return ret;
4563167514Skmacy		mac_prep(&p->mac, adapter, j);
4564167514Skmacy		++j;
4565167514Skmacy
4566167514Skmacy		/*
4567167514Skmacy		 * The VPD EEPROM stores the base Ethernet address for the
4568167514Skmacy		 * card.  A port's address is derived from the base by adding
4569167514Skmacy		 * the port's index to the base's low octet.
4570167514Skmacy		 */
4571167514Skmacy		memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
4572167514Skmacy		hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
4573167514Skmacy
4574167514Skmacy		t3_os_set_hw_addr(adapter, i, hw_addr);
4575176472Skmacy		init_link_config(&p->link_config, p->phy.caps);
4576167514Skmacy		p->phy.ops->power_down(&p->phy, 1);
4577189643Sgnn
4578189643Sgnn		/*
4579189643Sgnn		 * If the PHY doesn't support interrupts for link status
4580189643Sgnn		 * changes, schedule a scan of the adapter links at least
4581189643Sgnn		 * once a second.
4582189643Sgnn		 */
4583189643Sgnn		if (!(p->phy.caps & SUPPORTED_IRQ) &&
4584189643Sgnn		    adapter->params.linkpoll_period > 10)
4585167514Skmacy			adapter->params.linkpoll_period = 10;
4586167514Skmacy	}
4587167514Skmacy
4588167514Skmacy	return 0;
4589167514Skmacy}
4590167514Skmacy
4591181614Skmacy/**
4592181614Skmacy *	t3_reinit_adapter - prepare HW for operation again
4593181614Skmacy *	@adapter: the adapter
4594181614Skmacy *
4595181614Skmacy *	Put HW in the same state as @t3_prep_adapter without any changes to
4596181614Skmacy *	SW state.  This is a cut down version of @t3_prep_adapter intended
4597181614Skmacy *	to be used after events that wipe out HW state but preserve SW state,
4598181614Skmacy *	e.g., EEH.  The device must be reset before calling this.
4599181614Skmacy */
4600181614Skmacyint t3_reinit_adapter(adapter_t *adap)
4601181614Skmacy{
4602181614Skmacy	unsigned int i;
4603189643Sgnn	int ret, j = 0;
4604181614Skmacy
4605181614Skmacy	early_hw_init(adap, adap->params.info);
4606181614Skmacy	ret = init_parity(adap);
4607181614Skmacy	if (ret)
4608181614Skmacy		return ret;
4609181614Skmacy
4610181614Skmacy	if (adap->params.nports > 2 &&
4611181614Skmacy	    (ret = t3_vsc7323_init(adap, adap->params.nports)))
4612181614Skmacy		return ret;
4613181614Skmacy
4614181614Skmacy	for_each_port(adap, i) {
4615181614Skmacy		const struct port_type_info *pti;
4616181614Skmacy		struct port_info *p = adap2pinfo(adap, i);
4617181614Skmacy
4618189643Sgnn		for (;;) {
4619189643Sgnn			unsigned port_type = adap->params.vpd.port_type[j];
4620189643Sgnn			if (port_type) {
4621189643Sgnn				if (port_type < ARRAY_SIZE(port_types)) {
4622189643Sgnn					pti = &port_types[port_type];
4623189643Sgnn					break;
4624189643Sgnn				} else
4625189643Sgnn					return -EINVAL;
4626189643Sgnn			}
4627189643Sgnn			j++;
4628189643Sgnn			if (j >= ARRAY_SIZE(adap->params.vpd.port_type))
4629189643Sgnn				return -EINVAL;
4630189643Sgnn		}
4631197791Snp		ret = pti->phy_prep(p, p->phy.addr, NULL);
4632181614Skmacy		if (ret)
4633181614Skmacy			return ret;
4634181614Skmacy		p->phy.ops->power_down(&p->phy, 1);
4635181614Skmacy	}
4636181614Skmacy	return 0;
4637181614Skmacy}
4638181614Skmacy
4639167514Skmacyvoid t3_led_ready(adapter_t *adapter)
4640167514Skmacy{
4641167514Skmacy	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
4642167514Skmacy			 F_GPIO0_OUT_VAL);
4643167514Skmacy}
4644167514Skmacy
4645167514Skmacyvoid t3_port_failover(adapter_t *adapter, int port)
4646167514Skmacy{
4647167514Skmacy	u32 val;
4648167514Skmacy
4649167514Skmacy	val = port ? F_PORT1ACTIVE : F_PORT0ACTIVE;
4650167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4651167514Skmacy			 val);
4652167514Skmacy}
4653167514Skmacy
4654167514Skmacyvoid t3_failover_done(adapter_t *adapter, int port)
4655167514Skmacy{
4656167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4657167514Skmacy			 F_PORT0ACTIVE | F_PORT1ACTIVE);
4658167514Skmacy}
4659167514Skmacy
4660167514Skmacyvoid t3_failover_clear(adapter_t *adapter)
4661167514Skmacy{
4662167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4663167514Skmacy			 F_PORT0ACTIVE | F_PORT1ACTIVE);
4664167514Skmacy}
4665189643Sgnn
4666189643Sgnnstatic int t3_cim_hac_read(adapter_t *adapter, u32 addr, u32 *val)
4667189643Sgnn{
4668189643Sgnn	u32 v;
4669189643Sgnn
4670189643Sgnn	t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr);
4671189643Sgnn	if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL,
4672189643Sgnn				F_HOSTBUSY, 0, 10, 10, &v))
4673189643Sgnn		return -EIO;
4674189643Sgnn
4675189643Sgnn	*val = t3_read_reg(adapter, A_CIM_HOST_ACC_DATA);
4676189643Sgnn
4677189643Sgnn	return 0;
4678189643Sgnn}
4679189643Sgnn
4680189643Sgnnstatic int t3_cim_hac_write(adapter_t *adapter, u32 addr, u32 val)
4681189643Sgnn{
4682189643Sgnn	u32 v;
4683189643Sgnn
4684189643Sgnn	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, val);
4685189643Sgnn
4686189643Sgnn	addr |= F_HOSTWRITE;
4687189643Sgnn	t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr);
4688189643Sgnn
4689189643Sgnn	if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL,
4690189643Sgnn				F_HOSTBUSY, 0, 10, 5, &v))
4691189643Sgnn		return -EIO;
4692189643Sgnn	return 0;
4693189643Sgnn}
4694189643Sgnn
4695189643Sgnnint t3_get_up_la(adapter_t *adapter, u32 *stopped, u32 *index,
4696189643Sgnn		 u32 *size, void *data)
4697189643Sgnn{
4698189643Sgnn	u32 v, *buf = data;
4699189643Sgnn	int i, cnt,  ret;
4700189643Sgnn
4701189643Sgnn	if (*size < LA_ENTRIES * 4)
4702189643Sgnn		return -EINVAL;
4703189643Sgnn
4704189643Sgnn	ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4705189643Sgnn	if (ret)
4706189643Sgnn		goto out;
4707189643Sgnn
4708189643Sgnn	*stopped = !(v & 1);
4709189643Sgnn
4710189643Sgnn	/* Freeze LA */
4711189643Sgnn	if (!*stopped) {
4712189643Sgnn		ret = t3_cim_hac_write(adapter, LA_CTRL, 0);
4713189643Sgnn		if (ret)
4714189643Sgnn			goto out;
4715189643Sgnn	}
4716189643Sgnn
4717189643Sgnn	for (i = 0; i < LA_ENTRIES; i++) {
4718189643Sgnn		v = (i << 2) | (1 << 1);
4719189643Sgnn		ret = t3_cim_hac_write(adapter, LA_CTRL, v);
4720189643Sgnn		if (ret)
4721189643Sgnn			goto out;
4722189643Sgnn
4723189643Sgnn		ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4724189643Sgnn		if (ret)
4725189643Sgnn			goto out;
4726189643Sgnn
4727189643Sgnn		cnt = 20;
4728189643Sgnn		while ((v & (1 << 1)) && cnt) {
4729189643Sgnn			udelay(5);
4730189643Sgnn			--cnt;
4731189643Sgnn			ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4732189643Sgnn			if (ret)
4733189643Sgnn				goto out;
4734189643Sgnn		}
4735189643Sgnn
4736189643Sgnn		if (v & (1 << 1))
4737189643Sgnn			return -EIO;
4738189643Sgnn
4739189643Sgnn		ret = t3_cim_hac_read(adapter, LA_DATA, &v);
4740189643Sgnn		if (ret)
4741189643Sgnn			goto out;
4742189643Sgnn
4743189643Sgnn		*buf++ = v;
4744189643Sgnn	}
4745189643Sgnn
4746189643Sgnn	ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4747189643Sgnn	if (ret)
4748189643Sgnn		goto out;
4749189643Sgnn
4750189643Sgnn	*index = (v >> 16) + 4;
4751189643Sgnn	*size = LA_ENTRIES * 4;
4752189643Sgnnout:
4753189643Sgnn	/* Unfreeze LA */
4754189643Sgnn	t3_cim_hac_write(adapter, LA_CTRL, 1);
4755189643Sgnn	return ret;
4756189643Sgnn}
4757189643Sgnn
4758189643Sgnnint t3_get_up_ioqs(adapter_t *adapter, u32 *size, void *data)
4759189643Sgnn{
4760189643Sgnn	u32 v, *buf = data;
4761189643Sgnn	int i, j, ret;
4762189643Sgnn
4763189643Sgnn	if (*size < IOQ_ENTRIES * sizeof(struct t3_ioq_entry))
4764189643Sgnn		return -EINVAL;
4765189643Sgnn
4766189643Sgnn	for (i = 0; i < 4; i++) {
4767189643Sgnn		ret = t3_cim_hac_read(adapter, (4 * i), &v);
4768189643Sgnn		if (ret)
4769189643Sgnn			goto out;
4770189643Sgnn
4771189643Sgnn		*buf++ = v;
4772189643Sgnn	}
4773189643Sgnn
4774189643Sgnn	for (i = 0; i < IOQ_ENTRIES; i++) {
4775189643Sgnn		u32 base_addr = 0x10 * (i + 1);
4776189643Sgnn
4777189643Sgnn		for (j = 0; j < 4; j++) {
4778189643Sgnn			ret = t3_cim_hac_read(adapter, base_addr + 4 * j, &v);
4779189643Sgnn			if (ret)
4780189643Sgnn				goto out;
4781189643Sgnn
4782189643Sgnn			*buf++ = v;
4783189643Sgnn		}
4784189643Sgnn	}
4785189643Sgnn
4786189643Sgnn	*size = IOQ_ENTRIES * sizeof(struct t3_ioq_entry);
4787189643Sgnn
4788189643Sgnnout:
4789189643Sgnn	return ret;
4790189643Sgnn}
4791189643Sgnn
4792