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
654298955Spfg *	address 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
1034298955Spfg *	natural endianness.
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
1071298955Spfg *	big-endian array, otherwise in the processor's native endianness.
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{
1523276959Snp	int link_ok, speed, duplex, fc, link_fault, link_state;
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
1535276959Snp	phy->ops->get_link_status(phy, &link_state, &speed, &duplex, &fc);
1536276959Snp	link_ok = (link_state == PHY_LINK_UP);
1537276959Snp	if (link_state != PHY_LINK_PARTIAL)
1538276959Snp		phy->rst = 0;
1539276959Snp	else if (++phy->rst == 3) {
1540276959Snp		phy->ops->reset(phy, 0);
1541276959Snp		phy->rst = 0;
1542276959Snp	}
1543167514Skmacy
1544209841Snp	if (link_ok == 0)
1545209841Snp		pi->link_fault = LF_NO;
1546209841Snp
1547197791Snp	if (lc->requested_fc & PAUSE_AUTONEG)
1548197791Snp		fc &= lc->requested_fc;
1549197791Snp	else
1550197791Snp		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1551197791Snp
1552197791Snp	/* Update mac speed before checking for link fault. */
1553197791Snp	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE &&
1554197791Snp	    (speed != lc->speed || duplex != lc->duplex || fc != lc->fc))
1555197791Snp		t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
1556197791Snp
1557192540Sgnn	/*
1558192540Sgnn	 * Check for link faults if any of these is true:
1559192540Sgnn	 * a) A link fault is suspected, and PHY says link ok
1560192540Sgnn	 * b) PHY link transitioned from down -> up
1561192540Sgnn	 */
1562192540Sgnn	if (adapter->params.nports <= 2 &&
1563192540Sgnn	    ((pi->link_fault && link_ok) || (!lc->link_ok && link_ok))) {
1564189643Sgnn
1565192540Sgnn		link_fault = t3_detect_link_fault(adapter, port_id);
1566192540Sgnn		if (link_fault) {
1567192540Sgnn			if (pi->link_fault != LF_YES) {
1568192540Sgnn				mac->stats.link_faults++;
1569192540Sgnn				pi->link_fault = LF_YES;
1570192540Sgnn			}
1571189643Sgnn
1572211346Snp			if (uses_xaui(adapter)) {
1573211346Snp				if (adapter->params.rev >= T3_REV_C)
1574211346Snp					t3c_pcs_force_los(mac);
1575211346Snp				else
1576211346Snp					t3b_pcs_reset(mac);
1577211346Snp			}
1578211346Snp
1579197791Snp			/* Don't report link up */
1580192540Sgnn			link_ok = 0;
1581192540Sgnn		} else {
1582192540Sgnn			/* clear faults here if this was a false alarm. */
1583192540Sgnn			if (pi->link_fault == LF_MAYBE &&
1584192540Sgnn			    link_ok && lc->link_ok)
1585192540Sgnn				t3_clear_faults(adapter, port_id);
1586189643Sgnn
1587192540Sgnn			pi->link_fault = LF_NO;
1588189643Sgnn		}
1589189643Sgnn	}
1590189643Sgnn
1591180583Skmacy	if (link_ok == lc->link_ok && speed == lc->speed &&
1592180583Skmacy	    duplex == lc->duplex && fc == lc->fc)
1593180583Skmacy		return;                            /* nothing changed */
1594180583Skmacy
1595167514Skmacy	lc->link_ok = (unsigned char)link_ok;
1596167514Skmacy	lc->speed = speed < 0 ? SPEED_INVALID : speed;
1597167514Skmacy	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1598197791Snp	lc->fc = fc;
1599167514Skmacy
1600192540Sgnn	if (link_ok) {
1601167514Skmacy
1602192540Sgnn		/* down -> up, or up -> up with changed settings */
1603167514Skmacy
1604197791Snp		if (adapter->params.rev > 0 && uses_xaui(adapter)) {
1605211346Snp
1606211346Snp			if (adapter->params.rev >= T3_REV_C)
1607211346Snp				t3c_pcs_force_los(mac);
1608211346Snp			else
1609211346Snp				t3b_pcs_reset(mac);
1610211346Snp
1611192540Sgnn			t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
1612192540Sgnn				     F_TXACTENABLE | F_RXEN);
1613192540Sgnn		}
1614189643Sgnn
1615211346Snp		/* disable TX FIFO drain */
1616197791Snp		t3_set_reg_field(adapter, A_XGM_TXFIFO_CFG + mac->offset,
1617197791Snp				 F_ENDROPPKT, 0);
1618211346Snp
1619197791Snp		t3_mac_enable(mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX);
1620197791Snp		t3_set_reg_field(adapter, A_XGM_STAT_CTRL + mac->offset,
1621197791Snp				 F_CLRSTATS, 1);
1622192540Sgnn		t3_clear_faults(adapter, port_id);
1623189643Sgnn
1624192540Sgnn	} else {
1625189643Sgnn
1626192540Sgnn		/* up -> down */
1627189643Sgnn
1628192540Sgnn		if (adapter->params.rev > 0 && uses_xaui(adapter)) {
1629192540Sgnn			t3_write_reg(adapter,
1630192540Sgnn				     A_XGM_XAUI_ACT_CTRL + mac->offset, 0);
1631192540Sgnn		}
1632189643Sgnn
1633192540Sgnn		t3_xgm_intr_disable(adapter, pi->port_id);
1634192540Sgnn		if (adapter->params.nports <= 2) {
1635192540Sgnn			t3_set_reg_field(adapter,
1636192540Sgnn					 A_XGM_INT_ENABLE + mac->offset,
1637192540Sgnn					 F_XGM_INT, 0);
1638189643Sgnn
1639192540Sgnn			t3_mac_disable(mac, MAC_DIRECTION_RX);
1640189643Sgnn
1641211346Snp			/*
1642211346Snp			 * Make sure Tx FIFO continues to drain, even as rxen is
1643211346Snp			 * left high to help detect and indicate remote faults.
1644211346Snp			 */
1645211346Snp			t3_set_reg_field(adapter,
1646211346Snp			    A_XGM_TXFIFO_CFG + mac->offset, 0, F_ENDROPPKT);
1647211346Snp			t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
1648211346Snp			t3_write_reg(adapter,
1649211346Snp			    A_XGM_TX_CTRL + mac->offset, F_TXEN);
1650211346Snp			t3_write_reg(adapter,
1651211346Snp			    A_XGM_RX_CTRL + mac->offset, F_RXEN);
1652211346Snp		}
1653192540Sgnn	}
1654189643Sgnn
1655197791Snp	t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc,
1656197791Snp	    mac->was_reset);
1657197791Snp	mac->was_reset = 0;
1658189643Sgnn}
1659189643Sgnn
1660167514Skmacy/**
1661167514Skmacy *	t3_link_start - apply link configuration to MAC/PHY
1662167514Skmacy *	@phy: the PHY to setup
1663167514Skmacy *	@mac: the MAC to setup
1664167514Skmacy *	@lc: the requested link configuration
1665167514Skmacy *
1666167514Skmacy *	Set up a port's MAC and PHY according to a desired link configuration.
1667167514Skmacy *	- If the PHY can auto-negotiate first decide what to advertise, then
1668167514Skmacy *	  enable/disable auto-negotiation as desired, and reset.
1669167514Skmacy *	- If the PHY does not auto-negotiate just reset it.
1670167514Skmacy *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
1671167514Skmacy *	  otherwise do it later based on the outcome of auto-negotiation.
1672167514Skmacy */
1673167514Skmacyint t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
1674167514Skmacy{
1675167514Skmacy	unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1676167514Skmacy
1677167514Skmacy	lc->link_ok = 0;
1678167514Skmacy	if (lc->supported & SUPPORTED_Autoneg) {
1679167514Skmacy		lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
1680167514Skmacy		if (fc) {
1681167514Skmacy			lc->advertising |= ADVERTISED_Asym_Pause;
1682167514Skmacy			if (fc & PAUSE_RX)
1683167514Skmacy				lc->advertising |= ADVERTISED_Pause;
1684167514Skmacy		}
1685197791Snp
1686167514Skmacy		phy->ops->advertise(phy, lc->advertising);
1687167514Skmacy
1688167514Skmacy		if (lc->autoneg == AUTONEG_DISABLE) {
1689167514Skmacy			lc->speed = lc->requested_speed;
1690167514Skmacy			lc->duplex = lc->requested_duplex;
1691167514Skmacy			lc->fc = (unsigned char)fc;
1692167514Skmacy			t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
1693167514Skmacy						   fc);
1694167514Skmacy			/* Also disables autoneg */
1695167514Skmacy			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
1696189643Sgnn			/* PR 5666. Power phy up when doing an ifup */
1697189643Sgnn			if (!is_10G(phy->adapter))
1698197791Snp				phy->ops->power_down(phy, 0);
1699167514Skmacy		} else
1700167514Skmacy			phy->ops->autoneg_enable(phy);
1701167514Skmacy	} else {
1702167514Skmacy		t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
1703167514Skmacy		lc->fc = (unsigned char)fc;
1704167514Skmacy		phy->ops->reset(phy, 0);
1705167514Skmacy	}
1706167514Skmacy	return 0;
1707167514Skmacy}
1708167514Skmacy
1709167514Skmacy/**
1710167514Skmacy *	t3_set_vlan_accel - control HW VLAN extraction
1711167514Skmacy *	@adapter: the adapter
1712167514Skmacy *	@ports: bitmap of adapter ports to operate on
1713167514Skmacy *	@on: enable (1) or disable (0) HW VLAN extraction
1714167514Skmacy *
1715167514Skmacy *	Enables or disables HW extraction of VLAN tags for the given port.
1716167514Skmacy */
1717167514Skmacyvoid t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on)
1718167514Skmacy{
1719167514Skmacy	t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
1720167514Skmacy			 ports << S_VLANEXTRACTIONENABLE,
1721167514Skmacy			 on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
1722167514Skmacy}
1723167514Skmacy
1724167514Skmacystruct intr_info {
1725167514Skmacy	unsigned int mask;       /* bits to check in interrupt status */
1726167514Skmacy	const char *msg;         /* message to print or NULL */
1727167514Skmacy	short stat_idx;          /* stat counter to increment or -1 */
1728181614Skmacy	unsigned short fatal;    /* whether the condition reported is fatal */
1729167514Skmacy};
1730167514Skmacy
1731167514Skmacy/**
1732167514Skmacy *	t3_handle_intr_status - table driven interrupt handler
1733167514Skmacy *	@adapter: the adapter that generated the interrupt
1734167514Skmacy *	@reg: the interrupt status register to process
1735167514Skmacy *	@mask: a mask to apply to the interrupt status
1736167514Skmacy *	@acts: table of interrupt actions
1737249582Sgabor *	@stats: statistics counters tracking interrupt occurrences
1738167514Skmacy *
1739167514Skmacy *	A table driven interrupt handler that applies a set of masks to an
1740167514Skmacy *	interrupt status word and performs the corresponding actions if the
1741298955Spfg *	interrupts described by the mask have occurred.  The actions include
1742167514Skmacy *	optionally printing a warning or alert message, and optionally
1743167514Skmacy *	incrementing a stat counter.  The table is terminated by an entry
1744167514Skmacy *	specifying mask 0.  Returns the number of fatal interrupt conditions.
1745167514Skmacy */
1746167514Skmacystatic int t3_handle_intr_status(adapter_t *adapter, unsigned int reg,
1747167514Skmacy				 unsigned int mask,
1748167514Skmacy				 const struct intr_info *acts,
1749167514Skmacy				 unsigned long *stats)
1750167514Skmacy{
1751167514Skmacy	int fatal = 0;
1752167514Skmacy	unsigned int status = t3_read_reg(adapter, reg) & mask;
1753167514Skmacy
1754167514Skmacy	for ( ; acts->mask; ++acts) {
1755167514Skmacy		if (!(status & acts->mask)) continue;
1756167514Skmacy		if (acts->fatal) {
1757167514Skmacy			fatal++;
1758167514Skmacy			CH_ALERT(adapter, "%s (0x%x)\n",
1759167514Skmacy				 acts->msg, status & acts->mask);
1760219945Snp			status &= ~acts->mask;
1761167514Skmacy		} else if (acts->msg)
1762167514Skmacy			CH_WARN(adapter, "%s (0x%x)\n",
1763167514Skmacy				acts->msg, status & acts->mask);
1764167514Skmacy		if (acts->stat_idx >= 0)
1765167514Skmacy			stats[acts->stat_idx]++;
1766167514Skmacy	}
1767167514Skmacy	if (status)                           /* clear processed interrupts */
1768167514Skmacy		t3_write_reg(adapter, reg, status);
1769167514Skmacy	return fatal;
1770167514Skmacy}
1771167514Skmacy
1772176472Skmacy#define SGE_INTR_MASK (F_RSPQDISABLED | \
1773176472Skmacy		       F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \
1774176472Skmacy		       F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
1775176472Skmacy		       F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
1776176472Skmacy		       V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
1777176472Skmacy		       F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
1778176472Skmacy		       F_HIRCQPARITYERROR)
1779167514Skmacy#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
1780167514Skmacy		       F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
1781167514Skmacy		       F_NFASRCHFAIL)
1782167514Skmacy#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
1783167514Skmacy#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1784167514Skmacy		       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
1785189643Sgnn		       F_TXFIFO_UNDERRUN)
1786167514Skmacy#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
1787167514Skmacy			F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
1788167514Skmacy			F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
1789167514Skmacy			F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
1790167514Skmacy			V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
1791167514Skmacy			V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
1792167514Skmacy#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
1793167514Skmacy			F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
1794167514Skmacy			/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
1795176472Skmacy			F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \
1796176472Skmacy			F_TXPARERR | V_BISTERR(M_BISTERR))
1797176472Skmacy#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \
1798176472Skmacy			 F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \
1799176472Skmacy			 F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0)
1800176472Skmacy#define ULPTX_INTR_MASK 0xfc
1801176472Skmacy#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \
1802167514Skmacy			 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
1803167514Skmacy			 F_ZERO_SWITCH_ERROR)
1804167514Skmacy#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
1805167514Skmacy		       F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
1806167514Skmacy		       F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
1807176472Skmacy	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \
1808176472Skmacy		       F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \
1809176472Skmacy		       F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \
1810176472Skmacy		       F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \
1811176472Skmacy		       F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR)
1812167514Skmacy#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
1813167514Skmacy			V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
1814167514Skmacy			V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
1815167514Skmacy#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
1816167514Skmacy			V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
1817167514Skmacy			V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
1818167514Skmacy#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
1819167514Skmacy		       V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
1820167514Skmacy		       V_RXTPPARERRENB(M_RXTPPARERRENB) | \
1821167514Skmacy		       V_MCAPARERRENB(M_MCAPARERRENB))
1822189643Sgnn#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE)
1823167514Skmacy#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
1824167514Skmacy		      F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
1825167514Skmacy		      F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
1826167514Skmacy		      F_MPS0 | F_CPL_SWITCH)
1827167514Skmacy/*
1828167514Skmacy * Interrupt handler for the PCIX1 module.
1829167514Skmacy */
1830167514Skmacystatic void pci_intr_handler(adapter_t *adapter)
1831167514Skmacy{
1832167514Skmacy	static struct intr_info pcix1_intr_info[] = {
1833167514Skmacy		{ F_MSTDETPARERR, "PCI master detected parity error", -1, 1 },
1834167514Skmacy		{ F_SIGTARABT, "PCI signaled target abort", -1, 1 },
1835167514Skmacy		{ F_RCVTARABT, "PCI received target abort", -1, 1 },
1836167514Skmacy		{ F_RCVMSTABT, "PCI received master abort", -1, 1 },
1837167514Skmacy		{ F_SIGSYSERR, "PCI signaled system error", -1, 1 },
1838167514Skmacy		{ F_DETPARERR, "PCI detected parity error", -1, 1 },
1839167514Skmacy		{ F_SPLCMPDIS, "PCI split completion discarded", -1, 1 },
1840167514Skmacy		{ F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1 },
1841167514Skmacy		{ F_RCVSPLCMPERR, "PCI received split completion error", -1,
1842167514Skmacy		  1 },
1843167514Skmacy		{ F_DETCORECCERR, "PCI correctable ECC error",
1844167514Skmacy		  STAT_PCI_CORR_ECC, 0 },
1845167514Skmacy		{ F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1 },
1846167514Skmacy		{ F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 },
1847167514Skmacy		{ V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
1848167514Skmacy		  1 },
1849167514Skmacy		{ V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
1850167514Skmacy		  1 },
1851167514Skmacy		{ V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
1852167514Skmacy		  1 },
1853167514Skmacy		{ V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
1854167514Skmacy		  "error", -1, 1 },
1855167514Skmacy		{ 0 }
1856167514Skmacy	};
1857167514Skmacy
1858167514Skmacy	if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
1859167514Skmacy				  pcix1_intr_info, adapter->irq_stats))
1860167514Skmacy		t3_fatal_err(adapter);
1861167514Skmacy}
1862167514Skmacy
1863167514Skmacy/*
1864167514Skmacy * Interrupt handler for the PCIE module.
1865167514Skmacy */
1866167514Skmacystatic void pcie_intr_handler(adapter_t *adapter)
1867167514Skmacy{
1868167514Skmacy	static struct intr_info pcie_intr_info[] = {
1869167514Skmacy		{ F_PEXERR, "PCI PEX error", -1, 1 },
1870167514Skmacy		{ F_UNXSPLCPLERRR,
1871167514Skmacy		  "PCI unexpected split completion DMA read error", -1, 1 },
1872167514Skmacy		{ F_UNXSPLCPLERRC,
1873167514Skmacy		  "PCI unexpected split completion DMA command error", -1, 1 },
1874167514Skmacy		{ F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 },
1875167514Skmacy		{ F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1 },
1876167514Skmacy		{ F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1 },
1877167514Skmacy		{ F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1 },
1878167514Skmacy		{ V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
1879167514Skmacy		  "PCI MSI-X table/PBA parity error", -1, 1 },
1880176472Skmacy		{ F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1 },
1881176472Skmacy		{ F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1 },
1882176472Skmacy		{ F_RXPARERR, "PCI Rx parity error", -1, 1 },
1883176472Skmacy		{ F_TXPARERR, "PCI Tx parity error", -1, 1 },
1884167514Skmacy		{ V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1 },
1885167514Skmacy		{ 0 }
1886167514Skmacy	};
1887167514Skmacy
1888172096Skmacy	if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
1889172096Skmacy		CH_ALERT(adapter, "PEX error code 0x%x\n",
1890172096Skmacy			 t3_read_reg(adapter, A_PCIE_PEX_ERR));
1891172096Skmacy
1892167514Skmacy	if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
1893167514Skmacy				  pcie_intr_info, adapter->irq_stats))
1894167514Skmacy		t3_fatal_err(adapter);
1895167514Skmacy}
1896167514Skmacy
1897167514Skmacy/*
1898167514Skmacy * TP interrupt handler.
1899167514Skmacy */
1900167514Skmacystatic void tp_intr_handler(adapter_t *adapter)
1901167514Skmacy{
1902167514Skmacy	static struct intr_info tp_intr_info[] = {
1903167514Skmacy		{ 0xffffff,  "TP parity error", -1, 1 },
1904167514Skmacy		{ 0x1000000, "TP out of Rx pages", -1, 1 },
1905167514Skmacy		{ 0x2000000, "TP out of Tx pages", -1, 1 },
1906167514Skmacy		{ 0 }
1907167514Skmacy	};
1908176472Skmacy	static struct intr_info tp_intr_info_t3c[] = {
1909176472Skmacy		{ 0x1fffffff,  "TP parity error", -1, 1 },
1910176472Skmacy		{ F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1 },
1911176472Skmacy		{ F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
1912176472Skmacy		{ 0 }
1913176472Skmacy	};
1914167514Skmacy
1915167514Skmacy	if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
1916176472Skmacy				  adapter->params.rev < T3_REV_C ?
1917176472Skmacy					tp_intr_info : tp_intr_info_t3c, NULL))
1918167514Skmacy		t3_fatal_err(adapter);
1919167514Skmacy}
1920167514Skmacy
1921167514Skmacy/*
1922167514Skmacy * CIM interrupt handler.
1923167514Skmacy */
1924167514Skmacystatic void cim_intr_handler(adapter_t *adapter)
1925167514Skmacy{
1926167514Skmacy	static struct intr_info cim_intr_info[] = {
1927167514Skmacy		{ F_RSVDSPACEINT, "CIM reserved space write", -1, 1 },
1928167514Skmacy		{ F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1 },
1929167514Skmacy		{ F_FLASHRANGEINT, "CIM flash address out of range", -1, 1 },
1930167514Skmacy		{ F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
1931167514Skmacy		{ F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1 },
1932167514Skmacy		{ F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
1933167514Skmacy		{ F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1 },
1934167514Skmacy		{ F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
1935167514Skmacy		{ F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1 },
1936167514Skmacy		{ F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1 },
1937167514Skmacy		{ F_BLKRDPLINT, "CIM block read from PL space", -1, 1 },
1938167514Skmacy		{ F_BLKWRPLINT, "CIM block write to PL space", -1, 1 },
1939176472Skmacy		{ F_DRAMPARERR, "CIM DRAM parity error", -1, 1 },
1940176472Skmacy		{ F_ICACHEPARERR, "CIM icache parity error", -1, 1 },
1941176472Skmacy		{ F_DCACHEPARERR, "CIM dcache parity error", -1, 1 },
1942176472Skmacy		{ F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1 },
1943176472Skmacy		{ F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1 },
1944176472Skmacy		{ F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1 },
1945176472Skmacy		{ F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1 },
1946176472Skmacy		{ F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1 },
1947176472Skmacy		{ F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1 },
1948176472Skmacy		{ F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1 },
1949176472Skmacy		{ F_ITAGPARERR, "CIM itag parity error", -1, 1 },
1950176472Skmacy		{ F_DTAGPARERR, "CIM dtag parity error", -1, 1 },
1951167514Skmacy		{ 0 }
1952167514Skmacy        };
1953167514Skmacy
1954176472Skmacy	if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, CIM_INTR_MASK,
1955167514Skmacy				  cim_intr_info, NULL))
1956167514Skmacy		t3_fatal_err(adapter);
1957167514Skmacy}
1958167514Skmacy
1959167514Skmacy/*
1960167514Skmacy * ULP RX interrupt handler.
1961167514Skmacy */
1962167514Skmacystatic void ulprx_intr_handler(adapter_t *adapter)
1963167514Skmacy{
1964167514Skmacy	static struct intr_info ulprx_intr_info[] = {
1965176472Skmacy		{ F_PARERRDATA, "ULP RX data parity error", -1, 1 },
1966176472Skmacy		{ F_PARERRPCMD, "ULP RX command parity error", -1, 1 },
1967176472Skmacy		{ F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1 },
1968176472Skmacy		{ F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1 },
1969176472Skmacy		{ F_ARBFPERR, "ULP RX ArbF parity error", -1, 1 },
1970176472Skmacy		{ F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1 },
1971176472Skmacy		{ F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1 },
1972176472Skmacy		{ F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1 },
1973167514Skmacy		{ 0 }
1974167514Skmacy        };
1975167514Skmacy
1976167514Skmacy	if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
1977167514Skmacy				  ulprx_intr_info, NULL))
1978167514Skmacy		t3_fatal_err(adapter);
1979167514Skmacy}
1980167514Skmacy
1981167514Skmacy/*
1982167514Skmacy * ULP TX interrupt handler.
1983167514Skmacy */
1984167514Skmacystatic void ulptx_intr_handler(adapter_t *adapter)
1985167514Skmacy{
1986167514Skmacy	static struct intr_info ulptx_intr_info[] = {
1987167514Skmacy		{ F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
1988167514Skmacy		  STAT_ULP_CH0_PBL_OOB, 0 },
1989167514Skmacy		{ F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
1990167514Skmacy		  STAT_ULP_CH1_PBL_OOB, 0 },
1991176472Skmacy		{ 0xfc, "ULP TX parity error", -1, 1 },
1992167514Skmacy		{ 0 }
1993167514Skmacy        };
1994167514Skmacy
1995167514Skmacy	if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
1996167514Skmacy				  ulptx_intr_info, adapter->irq_stats))
1997167514Skmacy		t3_fatal_err(adapter);
1998167514Skmacy}
1999167514Skmacy
2000167514Skmacy#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
2001167514Skmacy	F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
2002167514Skmacy	F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
2003167514Skmacy	F_ICSPI1_TX_FRAMING_ERROR)
2004167514Skmacy#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
2005167514Skmacy	F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
2006167514Skmacy	F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
2007167514Skmacy	F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
2008167514Skmacy
2009167514Skmacy/*
2010167514Skmacy * PM TX interrupt handler.
2011167514Skmacy */
2012167514Skmacystatic void pmtx_intr_handler(adapter_t *adapter)
2013167514Skmacy{
2014167514Skmacy	static struct intr_info pmtx_intr_info[] = {
2015167514Skmacy		{ F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
2016167514Skmacy		{ ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1 },
2017167514Skmacy		{ OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1 },
2018167514Skmacy		{ V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
2019167514Skmacy		  "PMTX ispi parity error", -1, 1 },
2020167514Skmacy		{ V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
2021167514Skmacy		  "PMTX ospi parity error", -1, 1 },
2022167514Skmacy		{ 0 }
2023167514Skmacy        };
2024167514Skmacy
2025167514Skmacy	if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
2026167514Skmacy				  pmtx_intr_info, NULL))
2027167514Skmacy		t3_fatal_err(adapter);
2028167514Skmacy}
2029167514Skmacy
2030167514Skmacy#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
2031167514Skmacy	F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
2032167514Skmacy	F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
2033167514Skmacy	F_IESPI1_TX_FRAMING_ERROR)
2034167514Skmacy#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
2035167514Skmacy	F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
2036167514Skmacy	F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
2037167514Skmacy	F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
2038167514Skmacy
2039167514Skmacy/*
2040167514Skmacy * PM RX interrupt handler.
2041167514Skmacy */
2042167514Skmacystatic void pmrx_intr_handler(adapter_t *adapter)
2043167514Skmacy{
2044167514Skmacy	static struct intr_info pmrx_intr_info[] = {
2045167514Skmacy		{ F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
2046167514Skmacy		{ IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1 },
2047167514Skmacy		{ OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1 },
2048167514Skmacy		{ V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
2049167514Skmacy		  "PMRX ispi parity error", -1, 1 },
2050167514Skmacy		{ V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
2051167514Skmacy		  "PMRX ospi parity error", -1, 1 },
2052167514Skmacy		{ 0 }
2053167514Skmacy        };
2054167514Skmacy
2055167514Skmacy	if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
2056167514Skmacy				  pmrx_intr_info, NULL))
2057167514Skmacy		t3_fatal_err(adapter);
2058167514Skmacy}
2059167514Skmacy
2060167514Skmacy/*
2061167514Skmacy * CPL switch interrupt handler.
2062167514Skmacy */
2063167514Skmacystatic void cplsw_intr_handler(adapter_t *adapter)
2064167514Skmacy{
2065167514Skmacy	static struct intr_info cplsw_intr_info[] = {
2066176472Skmacy		{ F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1 },
2067176472Skmacy		{ F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 },
2068167514Skmacy		{ F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1 },
2069167514Skmacy		{ F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1 },
2070167514Skmacy		{ F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1 },
2071167514Skmacy		{ F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1 },
2072167514Skmacy		{ 0 }
2073167514Skmacy        };
2074167514Skmacy
2075167514Skmacy	if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
2076167514Skmacy				  cplsw_intr_info, NULL))
2077167514Skmacy		t3_fatal_err(adapter);
2078167514Skmacy}
2079167514Skmacy
2080167514Skmacy/*
2081167514Skmacy * MPS interrupt handler.
2082167514Skmacy */
2083167514Skmacystatic void mps_intr_handler(adapter_t *adapter)
2084167514Skmacy{
2085167514Skmacy	static struct intr_info mps_intr_info[] = {
2086167514Skmacy		{ 0x1ff, "MPS parity error", -1, 1 },
2087167514Skmacy		{ 0 }
2088167514Skmacy	};
2089167514Skmacy
2090167514Skmacy	if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
2091167514Skmacy				  mps_intr_info, NULL))
2092167514Skmacy		t3_fatal_err(adapter);
2093167514Skmacy}
2094167514Skmacy
2095167514Skmacy#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
2096167514Skmacy
2097167514Skmacy/*
2098167514Skmacy * MC7 interrupt handler.
2099167514Skmacy */
2100167514Skmacystatic void mc7_intr_handler(struct mc7 *mc7)
2101167514Skmacy{
2102167514Skmacy	adapter_t *adapter = mc7->adapter;
2103167514Skmacy	u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
2104167514Skmacy
2105167514Skmacy	if (cause & F_CE) {
2106167514Skmacy		mc7->stats.corr_err++;
2107167514Skmacy		CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
2108167514Skmacy			"data 0x%x 0x%x 0x%x\n", mc7->name,
2109167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
2110167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
2111167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
2112167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
2113167514Skmacy	}
2114167514Skmacy
2115167514Skmacy	if (cause & F_UE) {
2116167514Skmacy		mc7->stats.uncorr_err++;
2117167514Skmacy		CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
2118167514Skmacy			 "data 0x%x 0x%x 0x%x\n", mc7->name,
2119167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
2120167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
2121167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
2122167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
2123167514Skmacy	}
2124167514Skmacy
2125167514Skmacy	if (G_PE(cause)) {
2126167514Skmacy		mc7->stats.parity_err++;
2127167514Skmacy		CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
2128167514Skmacy			 mc7->name, G_PE(cause));
2129167514Skmacy	}
2130167514Skmacy
2131167514Skmacy	if (cause & F_AE) {
2132167514Skmacy		u32 addr = 0;
2133167514Skmacy
2134167514Skmacy		if (adapter->params.rev > 0)
2135167514Skmacy			addr = t3_read_reg(adapter,
2136167514Skmacy					   mc7->offset + A_MC7_ERR_ADDR);
2137167514Skmacy		mc7->stats.addr_err++;
2138167514Skmacy		CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
2139167514Skmacy			 mc7->name, addr);
2140167514Skmacy	}
2141167514Skmacy
2142167514Skmacy	if (cause & MC7_INTR_FATAL)
2143167514Skmacy		t3_fatal_err(adapter);
2144167514Skmacy
2145167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
2146167514Skmacy}
2147167514Skmacy
2148167514Skmacy#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
2149167514Skmacy			V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
2150167514Skmacy/*
2151167514Skmacy * XGMAC interrupt handler.
2152167514Skmacy */
2153167514Skmacystatic int mac_intr_handler(adapter_t *adap, unsigned int idx)
2154167514Skmacy{
2155170654Skmacy	u32 cause;
2156192540Sgnn	struct port_info *pi;
2157170654Skmacy	struct cmac *mac;
2158167514Skmacy
2159170654Skmacy	idx = idx == 0 ? 0 : adapter_info(adap)->nports0; /* MAC idx -> port */
2160192540Sgnn	pi = adap2pinfo(adap, idx);
2161192540Sgnn	mac = &pi->mac;
2162170654Skmacy
2163189643Sgnn	/*
2164189643Sgnn	 * We mask out interrupt causes for which we're not taking interrupts.
2165189643Sgnn	 * This allows us to use polling logic to monitor some of the other
2166189643Sgnn	 * conditions when taking interrupts would impose too much load on the
2167189643Sgnn	 * system.
2168189643Sgnn	 */
2169189643Sgnn	cause = (t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset)
2170189643Sgnn		 & ~(F_RXFIFO_OVERFLOW));
2171189643Sgnn
2172167514Skmacy	if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
2173167514Skmacy		mac->stats.tx_fifo_parity_err++;
2174167514Skmacy		CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
2175167514Skmacy	}
2176167514Skmacy	if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
2177167514Skmacy		mac->stats.rx_fifo_parity_err++;
2178167514Skmacy		CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
2179167514Skmacy	}
2180167514Skmacy	if (cause & F_TXFIFO_UNDERRUN)
2181167514Skmacy		mac->stats.tx_fifo_urun++;
2182167514Skmacy	if (cause & F_RXFIFO_OVERFLOW)
2183167514Skmacy		mac->stats.rx_fifo_ovfl++;
2184167514Skmacy	if (cause & V_SERDES_LOS(M_SERDES_LOS))
2185167514Skmacy		mac->stats.serdes_signal_loss++;
2186167514Skmacy	if (cause & F_XAUIPCSCTCERR)
2187167514Skmacy		mac->stats.xaui_pcs_ctc_err++;
2188167514Skmacy	if (cause & F_XAUIPCSALIGNCHANGE)
2189167514Skmacy		mac->stats.xaui_pcs_align_change++;
2190209841Snp	if (cause & F_XGM_INT &
2191209841Snp	    t3_read_reg(adap, A_XGM_INT_ENABLE + mac->offset)) {
2192209841Snp		t3_set_reg_field(adap, A_XGM_INT_ENABLE + mac->offset,
2193209841Snp		    F_XGM_INT, 0);
2194167514Skmacy
2195192540Sgnn		/* link fault suspected */
2196192540Sgnn		pi->link_fault = LF_MAYBE;
2197209841Snp		t3_os_link_intr(pi);
2198189643Sgnn	}
2199189643Sgnn
2200167514Skmacy	if (cause & XGM_INTR_FATAL)
2201167514Skmacy		t3_fatal_err(adap);
2202189643Sgnn
2203219945Snp	t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
2204167514Skmacy	return cause != 0;
2205167514Skmacy}
2206167514Skmacy
2207167514Skmacy/*
2208167514Skmacy * Interrupt handler for PHY events.
2209167514Skmacy */
2210209840Snpstatic int phy_intr_handler(adapter_t *adapter)
2211167514Skmacy{
2212167514Skmacy	u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
2213167514Skmacy
2214167514Skmacy	for_each_port(adapter, i) {
2215170654Skmacy		struct port_info *p = adap2pinfo(adapter, i);
2216167514Skmacy
2217176472Skmacy		if (!(p->phy.caps & SUPPORTED_IRQ))
2218167514Skmacy			continue;
2219167514Skmacy
2220180583Skmacy		if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) {
2221167514Skmacy			int phy_cause = p->phy.ops->intr_handler(&p->phy);
2222167514Skmacy
2223167514Skmacy			if (phy_cause & cphy_cause_link_change)
2224209841Snp				t3_os_link_intr(p);
2225167514Skmacy			if (phy_cause & cphy_cause_fifo_error)
2226167514Skmacy				p->phy.fifo_errors++;
2227181614Skmacy			if (phy_cause & cphy_cause_module_change)
2228181614Skmacy				t3_os_phymod_changed(adapter, i);
2229197791Snp			if (phy_cause & cphy_cause_alarm)
2230197791Snp				CH_WARN(adapter, "Operation affected due to "
2231197791Snp				    "adverse environment.  Check the spec "
2232197791Snp				    "sheet for corrective action.");
2233167514Skmacy		}
2234167514Skmacy	}
2235167514Skmacy
2236167514Skmacy	t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
2237167514Skmacy	return 0;
2238167514Skmacy}
2239167514Skmacy
2240172096Skmacy/**
2241172096Skmacy *	t3_slow_intr_handler - control path interrupt handler
2242172096Skmacy *	@adapter: the adapter
2243172096Skmacy *
2244172096Skmacy *	T3 interrupt handler for non-data interrupt events, e.g., errors.
2245172096Skmacy *	The designation 'slow' is because it involves register reads, while
2246172096Skmacy *	data interrupts typically don't involve any MMIOs.
2247167514Skmacy */
2248167514Skmacyint t3_slow_intr_handler(adapter_t *adapter)
2249167514Skmacy{
2250167514Skmacy	u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
2251167514Skmacy
2252167514Skmacy	cause &= adapter->slow_intr_mask;
2253167514Skmacy	if (!cause)
2254167514Skmacy		return 0;
2255167514Skmacy	if (cause & F_PCIM0) {
2256167514Skmacy		if (is_pcie(adapter))
2257167514Skmacy			pcie_intr_handler(adapter);
2258167514Skmacy		else
2259167514Skmacy			pci_intr_handler(adapter);
2260167514Skmacy	}
2261167514Skmacy	if (cause & F_SGE3)
2262167514Skmacy		t3_sge_err_intr_handler(adapter);
2263167514Skmacy	if (cause & F_MC7_PMRX)
2264167514Skmacy		mc7_intr_handler(&adapter->pmrx);
2265167514Skmacy	if (cause & F_MC7_PMTX)
2266167514Skmacy		mc7_intr_handler(&adapter->pmtx);
2267167514Skmacy	if (cause & F_MC7_CM)
2268167514Skmacy		mc7_intr_handler(&adapter->cm);
2269167514Skmacy	if (cause & F_CIM)
2270167514Skmacy		cim_intr_handler(adapter);
2271167514Skmacy	if (cause & F_TP1)
2272167514Skmacy		tp_intr_handler(adapter);
2273167514Skmacy	if (cause & F_ULP2_RX)
2274167514Skmacy		ulprx_intr_handler(adapter);
2275167514Skmacy	if (cause & F_ULP2_TX)
2276167514Skmacy		ulptx_intr_handler(adapter);
2277167514Skmacy	if (cause & F_PM1_RX)
2278167514Skmacy		pmrx_intr_handler(adapter);
2279167514Skmacy	if (cause & F_PM1_TX)
2280167514Skmacy		pmtx_intr_handler(adapter);
2281167514Skmacy	if (cause & F_CPL_SWITCH)
2282167514Skmacy		cplsw_intr_handler(adapter);
2283167514Skmacy	if (cause & F_MPS0)
2284167514Skmacy		mps_intr_handler(adapter);
2285167514Skmacy	if (cause & F_MC5A)
2286167514Skmacy		t3_mc5_intr_handler(&adapter->mc5);
2287167514Skmacy	if (cause & F_XGMAC0_0)
2288167514Skmacy		mac_intr_handler(adapter, 0);
2289167514Skmacy	if (cause & F_XGMAC0_1)
2290167514Skmacy		mac_intr_handler(adapter, 1);
2291167514Skmacy	if (cause & F_T3DBG)
2292209840Snp		phy_intr_handler(adapter);
2293167514Skmacy
2294167514Skmacy	/* Clear the interrupts just processed. */
2295167514Skmacy	t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
2296167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
2297167514Skmacy	return 1;
2298167514Skmacy}
2299167514Skmacy
2300180583Skmacystatic unsigned int calc_gpio_intr(adapter_t *adap)
2301180583Skmacy{
2302180583Skmacy	unsigned int i, gpi_intr = 0;
2303180583Skmacy
2304180583Skmacy	for_each_port(adap, i)
2305180583Skmacy		if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) &&
2306180583Skmacy		    adapter_info(adap)->gpio_intr[i])
2307180583Skmacy			gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i];
2308180583Skmacy	return gpi_intr;
2309180583Skmacy}
2310180583Skmacy
2311167514Skmacy/**
2312167514Skmacy *	t3_intr_enable - enable interrupts
2313167514Skmacy *	@adapter: the adapter whose interrupts should be enabled
2314167514Skmacy *
2315167514Skmacy *	Enable interrupts by setting the interrupt enable registers of the
2316167514Skmacy *	various HW modules and then enabling the top-level interrupt
2317167514Skmacy *	concentrator.
2318167514Skmacy */
2319167514Skmacyvoid t3_intr_enable(adapter_t *adapter)
2320167514Skmacy{
2321167514Skmacy	static struct addr_val_pair intr_en_avp[] = {
2322167514Skmacy		{ A_MC7_INT_ENABLE, MC7_INTR_MASK },
2323167514Skmacy		{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
2324167514Skmacy			MC7_INTR_MASK },
2325167514Skmacy		{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
2326167514Skmacy			MC7_INTR_MASK },
2327167514Skmacy		{ A_MC5_DB_INT_ENABLE, MC5_INTR_MASK },
2328167514Skmacy		{ A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK },
2329167514Skmacy		{ A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK },
2330167514Skmacy		{ A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK },
2331167514Skmacy		{ A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK },
2332167514Skmacy		{ A_MPS_INT_ENABLE, MPS_INTR_MASK },
2333167514Skmacy	};
2334167514Skmacy
2335167514Skmacy	adapter->slow_intr_mask = PL_INTR_MASK;
2336167514Skmacy
2337167514Skmacy	t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
2338176472Skmacy	t3_write_reg(adapter, A_TP_INT_ENABLE,
2339176472Skmacy		     adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff);
2340189643Sgnn	t3_write_reg(adapter, A_SG_INT_ENABLE, SGE_INTR_MASK);
2341167514Skmacy
2342167514Skmacy	if (adapter->params.rev > 0) {
2343167514Skmacy		t3_write_reg(adapter, A_CPL_INTR_ENABLE,
2344167514Skmacy			     CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
2345167514Skmacy		t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
2346167514Skmacy			     ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
2347167514Skmacy			     F_PBL_BOUND_ERR_CH1);
2348167514Skmacy	} else {
2349167514Skmacy		t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
2350167514Skmacy		t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
2351167514Skmacy	}
2352167514Skmacy
2353180583Skmacy	t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter));
2354180583Skmacy
2355170654Skmacy	if (is_pcie(adapter))
2356167514Skmacy		t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
2357170654Skmacy	else
2358167514Skmacy		t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
2359167514Skmacy	t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
2360167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_ENABLE0);          /* flush */
2361167514Skmacy}
2362167514Skmacy
2363167514Skmacy/**
2364167514Skmacy *	t3_intr_disable - disable a card's interrupts
2365167514Skmacy *	@adapter: the adapter whose interrupts should be disabled
2366167514Skmacy *
2367167514Skmacy *	Disable interrupts.  We only disable the top-level interrupt
2368167514Skmacy *	concentrator and the SGE data interrupts.
2369167514Skmacy */
2370167514Skmacyvoid t3_intr_disable(adapter_t *adapter)
2371167514Skmacy{
2372167514Skmacy	t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
2373167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_ENABLE0);  /* flush */
2374167514Skmacy	adapter->slow_intr_mask = 0;
2375167514Skmacy}
2376167514Skmacy
2377167514Skmacy/**
2378167514Skmacy *	t3_intr_clear - clear all interrupts
2379167514Skmacy *	@adapter: the adapter whose interrupts should be cleared
2380167514Skmacy *
2381167514Skmacy *	Clears all interrupts.
2382167514Skmacy */
2383167514Skmacyvoid t3_intr_clear(adapter_t *adapter)
2384167514Skmacy{
2385167514Skmacy	static const unsigned int cause_reg_addr[] = {
2386167514Skmacy		A_SG_INT_CAUSE,
2387167514Skmacy		A_SG_RSPQ_FL_STATUS,
2388167514Skmacy		A_PCIX_INT_CAUSE,
2389167514Skmacy		A_MC7_INT_CAUSE,
2390167514Skmacy		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
2391167514Skmacy		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
2392167514Skmacy		A_CIM_HOST_INT_CAUSE,
2393167514Skmacy		A_TP_INT_CAUSE,
2394167514Skmacy		A_MC5_DB_INT_CAUSE,
2395167514Skmacy		A_ULPRX_INT_CAUSE,
2396167514Skmacy		A_ULPTX_INT_CAUSE,
2397167514Skmacy		A_CPL_INTR_CAUSE,
2398167514Skmacy		A_PM1_TX_INT_CAUSE,
2399167514Skmacy		A_PM1_RX_INT_CAUSE,
2400167514Skmacy		A_MPS_INT_CAUSE,
2401167514Skmacy		A_T3DBG_INT_CAUSE,
2402167514Skmacy	};
2403167514Skmacy	unsigned int i;
2404167514Skmacy
2405167514Skmacy	/* Clear PHY and MAC interrupts for each port. */
2406167514Skmacy	for_each_port(adapter, i)
2407167514Skmacy		t3_port_intr_clear(adapter, i);
2408167514Skmacy
2409167514Skmacy	for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
2410167514Skmacy		t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
2411167514Skmacy
2412172096Skmacy	if (is_pcie(adapter))
2413172096Skmacy		t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
2414167514Skmacy	t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
2415167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_CAUSE0);          /* flush */
2416167514Skmacy}
2417167514Skmacy
2418189643Sgnnvoid t3_xgm_intr_enable(adapter_t *adapter, int idx)
2419189643Sgnn{
2420189643Sgnn	struct port_info *pi = adap2pinfo(adapter, idx);
2421189643Sgnn
2422189643Sgnn	t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset,
2423189643Sgnn		     XGM_EXTRA_INTR_MASK);
2424189643Sgnn}
2425189643Sgnn
2426189643Sgnnvoid t3_xgm_intr_disable(adapter_t *adapter, int idx)
2427189643Sgnn{
2428189643Sgnn	struct port_info *pi = adap2pinfo(adapter, idx);
2429189643Sgnn
2430189643Sgnn	t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset,
2431189643Sgnn		     0x7ff);
2432189643Sgnn}
2433189643Sgnn
2434167514Skmacy/**
2435167514Skmacy *	t3_port_intr_enable - enable port-specific interrupts
2436167514Skmacy *	@adapter: associated adapter
2437167514Skmacy *	@idx: index of port whose interrupts should be enabled
2438167514Skmacy *
2439167514Skmacy *	Enable port-specific (i.e., MAC and PHY) interrupts for the given
2440167514Skmacy *	adapter port.
2441167514Skmacy */
2442167514Skmacyvoid t3_port_intr_enable(adapter_t *adapter, int idx)
2443167514Skmacy{
2444170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2445170654Skmacy
2446170654Skmacy	t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, XGM_INTR_MASK);
2447170654Skmacy	pi->phy.ops->intr_enable(&pi->phy);
2448167514Skmacy}
2449167514Skmacy
2450167514Skmacy/**
2451167514Skmacy *	t3_port_intr_disable - disable port-specific interrupts
2452167514Skmacy *	@adapter: associated adapter
2453167514Skmacy *	@idx: index of port whose interrupts should be disabled
2454167514Skmacy *
2455167514Skmacy *	Disable port-specific (i.e., MAC and PHY) interrupts for the given
2456167514Skmacy *	adapter port.
2457167514Skmacy */
2458167514Skmacyvoid t3_port_intr_disable(adapter_t *adapter, int idx)
2459167514Skmacy{
2460170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2461170654Skmacy
2462170654Skmacy	t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, 0);
2463170654Skmacy	pi->phy.ops->intr_disable(&pi->phy);
2464167514Skmacy}
2465167514Skmacy
2466167514Skmacy/**
2467167514Skmacy *	t3_port_intr_clear - clear port-specific interrupts
2468167514Skmacy *	@adapter: associated adapter
2469167514Skmacy *	@idx: index of port whose interrupts to clear
2470167514Skmacy *
2471167514Skmacy *	Clear port-specific (i.e., MAC and PHY) interrupts for the given
2472167514Skmacy *	adapter port.
2473167514Skmacy */
2474167514Skmacyvoid t3_port_intr_clear(adapter_t *adapter, int idx)
2475167514Skmacy{
2476170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2477170654Skmacy
2478170654Skmacy	t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 0xffffffff);
2479170654Skmacy	pi->phy.ops->intr_clear(&pi->phy);
2480167514Skmacy}
2481167514Skmacy
2482172096Skmacy#define SG_CONTEXT_CMD_ATTEMPTS 100
2483172096Skmacy
2484167514Skmacy/**
2485167514Skmacy * 	t3_sge_write_context - write an SGE context
2486167514Skmacy * 	@adapter: the adapter
2487167514Skmacy * 	@id: the context id
2488167514Skmacy * 	@type: the context type
2489167514Skmacy *
2490167514Skmacy * 	Program an SGE context with the values already loaded in the
2491167514Skmacy * 	CONTEXT_DATA? registers.
2492167514Skmacy */
2493167514Skmacystatic int t3_sge_write_context(adapter_t *adapter, unsigned int id,
2494167514Skmacy				unsigned int type)
2495167514Skmacy{
2496189643Sgnn	if (type == F_RESPONSEQ) {
2497189643Sgnn		/*
2498189643Sgnn		 * Can't write the Response Queue Context bits for
2499189643Sgnn		 * Interrupt Armed or the Reserve bits after the chip
2500189643Sgnn		 * has been initialized out of reset.  Writing to these
2501189643Sgnn		 * bits can confuse the hardware.
2502189643Sgnn		 */
2503189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
2504189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
2505189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0x17ffffff);
2506189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
2507189643Sgnn	} else {
2508189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
2509189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
2510189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
2511189643Sgnn		t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
2512189643Sgnn	}
2513167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2514167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
2515167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2516172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2517167514Skmacy}
2518167514Skmacy
2519189643Sgnn/**
2520189643Sgnn *	clear_sge_ctxt - completely clear an SGE context
2521189643Sgnn *	@adapter: the adapter
2522189643Sgnn *	@id: the context id
2523189643Sgnn *	@type: the context type
2524189643Sgnn *
2525189643Sgnn *	Completely clear an SGE context.  Used predominantly at post-reset
2526189643Sgnn *	initialization.  Note in particular that we don't skip writing to any
2527189643Sgnn *	"sensitive bits" in the contexts the way that t3_sge_write_context()
2528189643Sgnn *	does ...
2529189643Sgnn */
2530176472Skmacystatic int clear_sge_ctxt(adapter_t *adap, unsigned int id, unsigned int type)
2531176472Skmacy{
2532176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0);
2533176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0);
2534176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0);
2535176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0);
2536189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK0, 0xffffffff);
2537189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK1, 0xffffffff);
2538189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK2, 0xffffffff);
2539189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_MASK3, 0xffffffff);
2540189643Sgnn	t3_write_reg(adap, A_SG_CONTEXT_CMD,
2541189643Sgnn		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
2542189643Sgnn	return t3_wait_op_done(adap, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2543189643Sgnn			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2544176472Skmacy}
2545176472Skmacy
2546167514Skmacy/**
2547167514Skmacy *	t3_sge_init_ecntxt - initialize an SGE egress context
2548167514Skmacy *	@adapter: the adapter to configure
2549167514Skmacy *	@id: the context id
2550167514Skmacy *	@gts_enable: whether to enable GTS for the context
2551167514Skmacy *	@type: the egress context type
2552167514Skmacy *	@respq: associated response queue
2553167514Skmacy *	@base_addr: base address of queue
2554167514Skmacy *	@size: number of queue entries
2555167514Skmacy *	@token: uP token
2556167514Skmacy *	@gen: initial generation value for the context
2557167514Skmacy *	@cidx: consumer pointer
2558167514Skmacy *
2559167514Skmacy *	Initialize an SGE egress context and make it ready for use.  If the
2560167514Skmacy *	platform allows concurrent context operations, the caller is
2561167514Skmacy *	responsible for appropriate locking.
2562167514Skmacy */
2563167514Skmacyint t3_sge_init_ecntxt(adapter_t *adapter, unsigned int id, int gts_enable,
2564167514Skmacy		       enum sge_context_type type, int respq, u64 base_addr,
2565167514Skmacy		       unsigned int size, unsigned int token, int gen,
2566167514Skmacy		       unsigned int cidx)
2567167514Skmacy{
2568167514Skmacy	unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
2569167514Skmacy
2570167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2571167514Skmacy		return -EINVAL;
2572167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2573167514Skmacy		return -EBUSY;
2574167514Skmacy
2575167514Skmacy	base_addr >>= 12;
2576167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
2577167514Skmacy		     V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
2578167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
2579167514Skmacy		     V_EC_BASE_LO((u32)base_addr & 0xffff));
2580167514Skmacy	base_addr >>= 16;
2581167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, (u32)base_addr);
2582167514Skmacy	base_addr >>= 32;
2583167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2584167514Skmacy		     V_EC_BASE_HI((u32)base_addr & 0xf) | V_EC_RESPQ(respq) |
2585167514Skmacy		     V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
2586167514Skmacy		     F_EC_VALID);
2587167514Skmacy	return t3_sge_write_context(adapter, id, F_EGRESS);
2588167514Skmacy}
2589167514Skmacy
2590167514Skmacy/**
2591167514Skmacy *	t3_sge_init_flcntxt - initialize an SGE free-buffer list context
2592167514Skmacy *	@adapter: the adapter to configure
2593167514Skmacy *	@id: the context id
2594167514Skmacy *	@gts_enable: whether to enable GTS for the context
2595167514Skmacy *	@base_addr: base address of queue
2596167514Skmacy *	@size: number of queue entries
2597167514Skmacy *	@bsize: size of each buffer for this queue
2598167514Skmacy *	@cong_thres: threshold to signal congestion to upstream producers
2599167514Skmacy *	@gen: initial generation value for the context
2600167514Skmacy *	@cidx: consumer pointer
2601167514Skmacy *
2602167514Skmacy *	Initialize an SGE free list context and make it ready for use.  The
2603167514Skmacy *	caller is responsible for ensuring only one context operation occurs
2604167514Skmacy *	at a time.
2605167514Skmacy */
2606167514Skmacyint t3_sge_init_flcntxt(adapter_t *adapter, unsigned int id, int gts_enable,
2607167514Skmacy			u64 base_addr, unsigned int size, unsigned int bsize,
2608167514Skmacy			unsigned int cong_thres, int gen, unsigned int cidx)
2609167514Skmacy{
2610167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2611167514Skmacy		return -EINVAL;
2612167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2613167514Skmacy		return -EBUSY;
2614167514Skmacy
2615167514Skmacy	base_addr >>= 12;
2616167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, (u32)base_addr);
2617167514Skmacy	base_addr >>= 32;
2618167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
2619167514Skmacy		     V_FL_BASE_HI((u32)base_addr) |
2620167514Skmacy		     V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
2621167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
2622167514Skmacy		     V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
2623167514Skmacy		     V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
2624167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2625167514Skmacy		     V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
2626167514Skmacy		     V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
2627167514Skmacy	return t3_sge_write_context(adapter, id, F_FREELIST);
2628167514Skmacy}
2629167514Skmacy
2630167514Skmacy/**
2631167514Skmacy *	t3_sge_init_rspcntxt - initialize an SGE response queue context
2632167514Skmacy *	@adapter: the adapter to configure
2633167514Skmacy *	@id: the context id
2634167514Skmacy *	@irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
2635167514Skmacy *	@base_addr: base address of queue
2636167514Skmacy *	@size: number of queue entries
2637167514Skmacy *	@fl_thres: threshold for selecting the normal or jumbo free list
2638167514Skmacy *	@gen: initial generation value for the context
2639167514Skmacy *	@cidx: consumer pointer
2640167514Skmacy *
2641167514Skmacy *	Initialize an SGE response queue context and make it ready for use.
2642167514Skmacy *	The caller is responsible for ensuring only one context operation
2643167514Skmacy *	occurs at a time.
2644167514Skmacy */
2645167514Skmacyint t3_sge_init_rspcntxt(adapter_t *adapter, unsigned int id, int irq_vec_idx,
2646167514Skmacy			 u64 base_addr, unsigned int size,
2647167514Skmacy			 unsigned int fl_thres, int gen, unsigned int cidx)
2648167514Skmacy{
2649189643Sgnn	unsigned int ctrl, intr = 0;
2650167514Skmacy
2651167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2652167514Skmacy		return -EINVAL;
2653167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2654167514Skmacy		return -EBUSY;
2655167514Skmacy
2656167514Skmacy	base_addr >>= 12;
2657167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
2658167514Skmacy		     V_CQ_INDEX(cidx));
2659167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr);
2660167514Skmacy	base_addr >>= 32;
2661189643Sgnn        ctrl = t3_read_reg(adapter, A_SG_CONTROL);
2662189643Sgnn        if ((irq_vec_idx > 0) ||
2663189643Sgnn		((irq_vec_idx == 0) && !(ctrl & F_ONEINTMULTQ)))
2664189643Sgnn                	intr = F_RQ_INTR_EN;
2665189643Sgnn        if (irq_vec_idx >= 0)
2666189643Sgnn                intr |= V_RQ_MSI_VEC(irq_vec_idx);
2667167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2668167514Skmacy		     V_CQ_BASE_HI((u32)base_addr) | intr | V_RQ_GEN(gen));
2669167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
2670167514Skmacy	return t3_sge_write_context(adapter, id, F_RESPONSEQ);
2671167514Skmacy}
2672167514Skmacy
2673167514Skmacy/**
2674167514Skmacy *	t3_sge_init_cqcntxt - initialize an SGE completion queue context
2675167514Skmacy *	@adapter: the adapter to configure
2676167514Skmacy *	@id: the context id
2677167514Skmacy *	@base_addr: base address of queue
2678167514Skmacy *	@size: number of queue entries
2679167514Skmacy *	@rspq: response queue for async notifications
2680167514Skmacy *	@ovfl_mode: CQ overflow mode
2681167514Skmacy *	@credits: completion queue credits
2682167514Skmacy *	@credit_thres: the credit threshold
2683167514Skmacy *
2684167514Skmacy *	Initialize an SGE completion queue context and make it ready for use.
2685167514Skmacy *	The caller is responsible for ensuring only one context operation
2686167514Skmacy *	occurs at a time.
2687167514Skmacy */
2688167514Skmacyint t3_sge_init_cqcntxt(adapter_t *adapter, unsigned int id, u64 base_addr,
2689167514Skmacy			unsigned int size, int rspq, int ovfl_mode,
2690167514Skmacy			unsigned int credits, unsigned int credit_thres)
2691167514Skmacy{
2692167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2693167514Skmacy		return -EINVAL;
2694167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2695167514Skmacy		return -EBUSY;
2696167514Skmacy
2697167514Skmacy	base_addr >>= 12;
2698167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
2699167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr);
2700167514Skmacy	base_addr >>= 32;
2701167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2702167514Skmacy		     V_CQ_BASE_HI((u32)base_addr) | V_CQ_RSPQ(rspq) |
2703172096Skmacy		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
2704172096Skmacy		     V_CQ_ERR(ovfl_mode));
2705167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
2706167514Skmacy		     V_CQ_CREDIT_THRES(credit_thres));
2707167514Skmacy	return t3_sge_write_context(adapter, id, F_CQ);
2708167514Skmacy}
2709167514Skmacy
2710167514Skmacy/**
2711167514Skmacy *	t3_sge_enable_ecntxt - enable/disable an SGE egress context
2712167514Skmacy *	@adapter: the adapter
2713167514Skmacy *	@id: the egress context id
2714167514Skmacy *	@enable: enable (1) or disable (0) the context
2715167514Skmacy *
2716167514Skmacy *	Enable or disable an SGE egress context.  The caller is responsible for
2717167514Skmacy *	ensuring only one context operation occurs at a time.
2718167514Skmacy */
2719167514Skmacyint t3_sge_enable_ecntxt(adapter_t *adapter, unsigned int id, int enable)
2720167514Skmacy{
2721167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2722167514Skmacy		return -EBUSY;
2723167514Skmacy
2724167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2725167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2726167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2727167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
2728167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
2729167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2730167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
2731167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2732172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2733167514Skmacy}
2734167514Skmacy
2735167514Skmacy/**
2736167514Skmacy *	t3_sge_disable_fl - disable an SGE free-buffer list
2737167514Skmacy *	@adapter: the adapter
2738167514Skmacy *	@id: the free list context id
2739167514Skmacy *
2740167514Skmacy *	Disable an SGE free-buffer list.  The caller is responsible for
2741167514Skmacy *	ensuring only one context operation occurs at a time.
2742167514Skmacy */
2743167514Skmacyint t3_sge_disable_fl(adapter_t *adapter, unsigned int id)
2744167514Skmacy{
2745167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2746167514Skmacy		return -EBUSY;
2747167514Skmacy
2748167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2749167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2750167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
2751167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2752167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
2753167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2754167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
2755167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2756172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2757167514Skmacy}
2758167514Skmacy
2759167514Skmacy/**
2760167514Skmacy *	t3_sge_disable_rspcntxt - disable an SGE response queue
2761167514Skmacy *	@adapter: the adapter
2762167514Skmacy *	@id: the response queue context id
2763167514Skmacy *
2764167514Skmacy *	Disable an SGE response queue.  The caller is responsible for
2765167514Skmacy *	ensuring only one context operation occurs at a time.
2766167514Skmacy */
2767167514Skmacyint t3_sge_disable_rspcntxt(adapter_t *adapter, unsigned int id)
2768167514Skmacy{
2769167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2770167514Skmacy		return -EBUSY;
2771167514Skmacy
2772167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2773167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2774167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2775167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2776167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2777167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2778167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
2779167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2780172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2781167514Skmacy}
2782167514Skmacy
2783167514Skmacy/**
2784167514Skmacy *	t3_sge_disable_cqcntxt - disable an SGE completion queue
2785167514Skmacy *	@adapter: the adapter
2786167514Skmacy *	@id: the completion queue context id
2787167514Skmacy *
2788167514Skmacy *	Disable an SGE completion queue.  The caller is responsible for
2789167514Skmacy *	ensuring only one context operation occurs at a time.
2790167514Skmacy */
2791167514Skmacyint t3_sge_disable_cqcntxt(adapter_t *adapter, unsigned int id)
2792167514Skmacy{
2793167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2794167514Skmacy		return -EBUSY;
2795167514Skmacy
2796167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2797167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2798167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2799167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2800167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2801167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2802167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
2803167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2804172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2805167514Skmacy}
2806167514Skmacy
2807167514Skmacy/**
2808167514Skmacy *	t3_sge_cqcntxt_op - perform an operation on a completion queue context
2809167514Skmacy *	@adapter: the adapter
2810167514Skmacy *	@id: the context id
2811167514Skmacy *	@op: the operation to perform
2812172096Skmacy *	@credits: credits to return to the CQ
2813167514Skmacy *
2814167514Skmacy *	Perform the selected operation on an SGE completion queue context.
2815167514Skmacy *	The caller is responsible for ensuring only one context operation
2816167514Skmacy *	occurs at a time.
2817172096Skmacy *
2818172096Skmacy *	For most operations the function returns the current HW position in
2819172096Skmacy *	the completion queue.
2820167514Skmacy */
2821167514Skmacyint t3_sge_cqcntxt_op(adapter_t *adapter, unsigned int id, unsigned int op,
2822167514Skmacy		      unsigned int credits)
2823167514Skmacy{
2824167514Skmacy	u32 val;
2825167514Skmacy
2826167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2827167514Skmacy		return -EBUSY;
2828167514Skmacy
2829167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
2830167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
2831167514Skmacy		     V_CONTEXT(id) | F_CQ);
2832167514Skmacy	if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2833172096Skmacy				0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
2834167514Skmacy		return -EIO;
2835167514Skmacy
2836167514Skmacy	if (op >= 2 && op < 7) {
2837167514Skmacy		if (adapter->params.rev > 0)
2838167514Skmacy			return G_CQ_INDEX(val);
2839167514Skmacy
2840167514Skmacy		t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2841167514Skmacy			     V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
2842167514Skmacy		if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
2843172096Skmacy				    F_CONTEXT_CMD_BUSY, 0,
2844172096Skmacy				    SG_CONTEXT_CMD_ATTEMPTS, 1))
2845167514Skmacy			return -EIO;
2846167514Skmacy		return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
2847167514Skmacy	}
2848167514Skmacy	return 0;
2849167514Skmacy}
2850167514Skmacy
2851167514Skmacy/**
2852167514Skmacy * 	t3_sge_read_context - read an SGE context
2853167514Skmacy * 	@type: the context type
2854167514Skmacy * 	@adapter: the adapter
2855167514Skmacy * 	@id: the context id
2856167514Skmacy * 	@data: holds the retrieved context
2857167514Skmacy *
2858167514Skmacy * 	Read an SGE egress context.  The caller is responsible for ensuring
2859167514Skmacy * 	only one context operation occurs at a time.
2860167514Skmacy */
2861167514Skmacystatic int t3_sge_read_context(unsigned int type, adapter_t *adapter,
2862167514Skmacy			       unsigned int id, u32 data[4])
2863167514Skmacy{
2864167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2865167514Skmacy		return -EBUSY;
2866167514Skmacy
2867167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2868167514Skmacy		     V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
2869167514Skmacy	if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
2870172096Skmacy			    SG_CONTEXT_CMD_ATTEMPTS, 1))
2871167514Skmacy		return -EIO;
2872167514Skmacy	data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
2873167514Skmacy	data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
2874167514Skmacy	data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
2875167514Skmacy	data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
2876167514Skmacy	return 0;
2877167514Skmacy}
2878167514Skmacy
2879167514Skmacy/**
2880167514Skmacy * 	t3_sge_read_ecntxt - read an SGE egress context
2881167514Skmacy * 	@adapter: the adapter
2882167514Skmacy * 	@id: the context id
2883167514Skmacy * 	@data: holds the retrieved context
2884167514Skmacy *
2885167514Skmacy * 	Read an SGE egress context.  The caller is responsible for ensuring
2886167514Skmacy * 	only one context operation occurs at a time.
2887167514Skmacy */
2888167514Skmacyint t3_sge_read_ecntxt(adapter_t *adapter, unsigned int id, u32 data[4])
2889167514Skmacy{
2890167514Skmacy	if (id >= 65536)
2891167514Skmacy		return -EINVAL;
2892167514Skmacy	return t3_sge_read_context(F_EGRESS, adapter, id, data);
2893167514Skmacy}
2894167514Skmacy
2895167514Skmacy/**
2896167514Skmacy * 	t3_sge_read_cq - read an SGE CQ context
2897167514Skmacy * 	@adapter: the adapter
2898167514Skmacy * 	@id: the context id
2899167514Skmacy * 	@data: holds the retrieved context
2900167514Skmacy *
2901167514Skmacy * 	Read an SGE CQ context.  The caller is responsible for ensuring
2902167514Skmacy * 	only one context operation occurs at a time.
2903167514Skmacy */
2904167514Skmacyint t3_sge_read_cq(adapter_t *adapter, unsigned int id, u32 data[4])
2905167514Skmacy{
2906167514Skmacy	if (id >= 65536)
2907167514Skmacy		return -EINVAL;
2908167514Skmacy	return t3_sge_read_context(F_CQ, adapter, id, data);
2909167514Skmacy}
2910167514Skmacy
2911167514Skmacy/**
2912167514Skmacy * 	t3_sge_read_fl - read an SGE free-list context
2913167514Skmacy * 	@adapter: the adapter
2914167514Skmacy * 	@id: the context id
2915167514Skmacy * 	@data: holds the retrieved context
2916167514Skmacy *
2917167514Skmacy * 	Read an SGE free-list context.  The caller is responsible for ensuring
2918167514Skmacy * 	only one context operation occurs at a time.
2919167514Skmacy */
2920167514Skmacyint t3_sge_read_fl(adapter_t *adapter, unsigned int id, u32 data[4])
2921167514Skmacy{
2922167514Skmacy	if (id >= SGE_QSETS * 2)
2923167514Skmacy		return -EINVAL;
2924167514Skmacy	return t3_sge_read_context(F_FREELIST, adapter, id, data);
2925167514Skmacy}
2926167514Skmacy
2927167514Skmacy/**
2928167514Skmacy * 	t3_sge_read_rspq - read an SGE response queue context
2929167514Skmacy * 	@adapter: the adapter
2930167514Skmacy * 	@id: the context id
2931167514Skmacy * 	@data: holds the retrieved context
2932167514Skmacy *
2933167514Skmacy * 	Read an SGE response queue context.  The caller is responsible for
2934167514Skmacy * 	ensuring only one context operation occurs at a time.
2935167514Skmacy */
2936167514Skmacyint t3_sge_read_rspq(adapter_t *adapter, unsigned int id, u32 data[4])
2937167514Skmacy{
2938167514Skmacy	if (id >= SGE_QSETS)
2939167514Skmacy		return -EINVAL;
2940167514Skmacy	return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
2941167514Skmacy}
2942167514Skmacy
2943167514Skmacy/**
2944167514Skmacy *	t3_config_rss - configure Rx packet steering
2945167514Skmacy *	@adapter: the adapter
2946167514Skmacy *	@rss_config: RSS settings (written to TP_RSS_CONFIG)
2947167514Skmacy *	@cpus: values for the CPU lookup table (0xff terminated)
2948167514Skmacy *	@rspq: values for the response queue lookup table (0xffff terminated)
2949167514Skmacy *
2950167514Skmacy *	Programs the receive packet steering logic.  @cpus and @rspq provide
2951167514Skmacy *	the values for the CPU and response queue lookup tables.  If they
2952167514Skmacy *	provide fewer values than the size of the tables the supplied values
2953167514Skmacy *	are used repeatedly until the tables are fully populated.
2954167514Skmacy */
2955167514Skmacyvoid t3_config_rss(adapter_t *adapter, unsigned int rss_config, const u8 *cpus,
2956167514Skmacy		   const u16 *rspq)
2957167514Skmacy{
2958167514Skmacy	int i, j, cpu_idx = 0, q_idx = 0;
2959167514Skmacy
2960167514Skmacy	if (cpus)
2961167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2962167514Skmacy			u32 val = i << 16;
2963167514Skmacy
2964167514Skmacy			for (j = 0; j < 2; ++j) {
2965167514Skmacy				val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
2966167514Skmacy				if (cpus[cpu_idx] == 0xff)
2967167514Skmacy					cpu_idx = 0;
2968167514Skmacy			}
2969167514Skmacy			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
2970167514Skmacy		}
2971167514Skmacy
2972167514Skmacy	if (rspq)
2973167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2974167514Skmacy			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
2975167514Skmacy				     (i << 16) | rspq[q_idx++]);
2976167514Skmacy			if (rspq[q_idx] == 0xffff)
2977167514Skmacy				q_idx = 0;
2978167514Skmacy		}
2979167514Skmacy
2980167514Skmacy	t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
2981167514Skmacy}
2982167514Skmacy
2983167514Skmacy/**
2984167514Skmacy *	t3_read_rss - read the contents of the RSS tables
2985167514Skmacy *	@adapter: the adapter
2986167514Skmacy *	@lkup: holds the contents of the RSS lookup table
2987167514Skmacy *	@map: holds the contents of the RSS map table
2988167514Skmacy *
2989167514Skmacy *	Reads the contents of the receive packet steering tables.
2990167514Skmacy */
2991167514Skmacyint t3_read_rss(adapter_t *adapter, u8 *lkup, u16 *map)
2992167514Skmacy{
2993167514Skmacy	int i;
2994167514Skmacy	u32 val;
2995167514Skmacy
2996167514Skmacy	if (lkup)
2997167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2998167514Skmacy			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
2999167514Skmacy				     0xffff0000 | i);
3000167514Skmacy			val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
3001167514Skmacy			if (!(val & 0x80000000))
3002167514Skmacy				return -EAGAIN;
3003167514Skmacy			*lkup++ = (u8)val;
3004167514Skmacy			*lkup++ = (u8)(val >> 8);
3005167514Skmacy		}
3006167514Skmacy
3007167514Skmacy	if (map)
3008167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
3009167514Skmacy			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
3010167514Skmacy				     0xffff0000 | i);
3011167514Skmacy			val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
3012167514Skmacy			if (!(val & 0x80000000))
3013167514Skmacy				return -EAGAIN;
3014167514Skmacy			*map++ = (u16)val;
3015167514Skmacy		}
3016167514Skmacy	return 0;
3017167514Skmacy}
3018167514Skmacy
3019167514Skmacy/**
3020167514Skmacy *	t3_tp_set_offload_mode - put TP in NIC/offload mode
3021167514Skmacy *	@adap: the adapter
3022167514Skmacy *	@enable: 1 to select offload mode, 0 for regular NIC
3023167514Skmacy *
3024167514Skmacy *	Switches TP to NIC/offload mode.
3025167514Skmacy */
3026167514Skmacyvoid t3_tp_set_offload_mode(adapter_t *adap, int enable)
3027167514Skmacy{
3028167514Skmacy	if (is_offload(adap) || !enable)
3029167514Skmacy		t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
3030167514Skmacy				 V_NICMODE(!enable));
3031167514Skmacy}
3032167514Skmacy
3033172096Skmacy/**
3034172096Skmacy *	tp_wr_bits_indirect - set/clear bits in an indirect TP register
3035172096Skmacy *	@adap: the adapter
3036172096Skmacy *	@addr: the indirect TP register address
3037172096Skmacy *	@mask: specifies the field within the register to modify
3038172096Skmacy *	@val: new value for the field
3039172096Skmacy *
3040172096Skmacy *	Sets a field of an indirect TP register to the given value.
3041172096Skmacy */
3042171471Skmacystatic void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr,
3043171471Skmacy				unsigned int mask, unsigned int val)
3044171471Skmacy{
3045171471Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
3046171471Skmacy	val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask;
3047171471Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, val);
3048171471Skmacy}
3049171471Skmacy
3050167514Skmacy/**
3051180583Skmacy *	t3_enable_filters - enable the HW filters
3052180583Skmacy *	@adap: the adapter
3053180583Skmacy *
3054180583Skmacy *	Enables the HW filters for NIC traffic.
3055180583Skmacy */
3056180583Skmacyvoid t3_enable_filters(adapter_t *adap)
3057180583Skmacy{
3058180583Skmacy	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 0);
3059180583Skmacy	t3_set_reg_field(adap, A_MC5_DB_CONFIG, 0, F_FILTEREN);
3060180583Skmacy	t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 0, V_FIVETUPLELOOKUP(3));
3061180583Skmacy	tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, 0, F_LOOKUPEVERYPKT);
3062180583Skmacy}
3063180583Skmacy
3064180583Skmacy/**
3065189643Sgnn *	t3_disable_filters - disable the HW filters
3066189643Sgnn *	@adap: the adapter
3067189643Sgnn *
3068189643Sgnn *	Disables the HW filters for NIC traffic.
3069189643Sgnn */
3070189643Sgnnvoid t3_disable_filters(adapter_t *adap)
3071189643Sgnn{
3072189643Sgnn	/* note that we don't want to revert to NIC-only mode */
3073189643Sgnn	t3_set_reg_field(adap, A_MC5_DB_CONFIG, F_FILTEREN, 0);
3074189643Sgnn	t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG,
3075189643Sgnn			 V_FIVETUPLELOOKUP(M_FIVETUPLELOOKUP), 0);
3076189643Sgnn	tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, F_LOOKUPEVERYPKT, 0);
3077189643Sgnn}
3078189643Sgnn
3079189643Sgnn/**
3080167514Skmacy *	pm_num_pages - calculate the number of pages of the payload memory
3081167514Skmacy *	@mem_size: the size of the payload memory
3082167514Skmacy *	@pg_size: the size of each payload memory page
3083167514Skmacy *
3084167514Skmacy *	Calculate the number of pages, each of the given size, that fit in a
3085167514Skmacy *	memory of the specified size, respecting the HW requirement that the
3086167514Skmacy *	number of pages must be a multiple of 24.
3087167514Skmacy */
3088167514Skmacystatic inline unsigned int pm_num_pages(unsigned int mem_size,
3089167514Skmacy					unsigned int pg_size)
3090167514Skmacy{
3091167514Skmacy	unsigned int n = mem_size / pg_size;
3092167514Skmacy
3093167514Skmacy	return n - n % 24;
3094167514Skmacy}
3095167514Skmacy
3096167514Skmacy#define mem_region(adap, start, size, reg) \
3097167514Skmacy	t3_write_reg((adap), A_ ## reg, (start)); \
3098167514Skmacy	start += size
3099167514Skmacy
3100172096Skmacy/**
3101167514Skmacy *	partition_mem - partition memory and configure TP memory settings
3102167514Skmacy *	@adap: the adapter
3103167514Skmacy *	@p: the TP parameters
3104167514Skmacy *
3105167514Skmacy *	Partitions context and payload memory and configures TP's memory
3106167514Skmacy *	registers.
3107167514Skmacy */
3108167514Skmacystatic void partition_mem(adapter_t *adap, const struct tp_params *p)
3109167514Skmacy{
3110167514Skmacy	unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
3111167514Skmacy	unsigned int timers = 0, timers_shift = 22;
3112167514Skmacy
3113167514Skmacy	if (adap->params.rev > 0) {
3114167514Skmacy		if (tids <= 16 * 1024) {
3115167514Skmacy			timers = 1;
3116167514Skmacy			timers_shift = 16;
3117167514Skmacy		} else if (tids <= 64 * 1024) {
3118167514Skmacy			timers = 2;
3119167514Skmacy			timers_shift = 18;
3120167514Skmacy		} else if (tids <= 256 * 1024) {
3121167514Skmacy			timers = 3;
3122167514Skmacy			timers_shift = 20;
3123167514Skmacy		}
3124167514Skmacy	}
3125167514Skmacy
3126167514Skmacy	t3_write_reg(adap, A_TP_PMM_SIZE,
3127167514Skmacy		     p->chan_rx_size | (p->chan_tx_size >> 16));
3128167514Skmacy
3129167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
3130167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
3131167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
3132167514Skmacy	t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
3133167514Skmacy			 V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
3134167514Skmacy
3135167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
3136167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
3137167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
3138167514Skmacy
3139167514Skmacy	pstructs = p->rx_num_pgs + p->tx_num_pgs;
3140167514Skmacy	/* Add a bit of headroom and make multiple of 24 */
3141167514Skmacy	pstructs += 48;
3142167514Skmacy	pstructs -= pstructs % 24;
3143167514Skmacy	t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
3144167514Skmacy
3145167514Skmacy	m = tids * TCB_SIZE;
3146167514Skmacy	mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
3147167514Skmacy	mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
3148167514Skmacy	t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
3149167514Skmacy	m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
3150167514Skmacy	mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
3151167514Skmacy	mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
3152167514Skmacy	mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
3153167514Skmacy	mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
3154167514Skmacy
3155167514Skmacy	m = (m + 4095) & ~0xfff;
3156167514Skmacy	t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
3157167514Skmacy	t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
3158167514Skmacy
3159167514Skmacy	tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
3160167514Skmacy	m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
3161167514Skmacy	    adap->params.mc5.nfilters - adap->params.mc5.nroutes;
3162167514Skmacy	if (tids < m)
3163167514Skmacy		adap->params.mc5.nservers += m - tids;
3164167514Skmacy}
3165167514Skmacy
3166167514Skmacystatic inline void tp_wr_indirect(adapter_t *adap, unsigned int addr, u32 val)
3167167514Skmacy{
3168167514Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
3169167514Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, val);
3170167514Skmacy}
3171167514Skmacy
3172189643Sgnnstatic inline u32 tp_rd_indirect(adapter_t *adap, unsigned int addr)
3173189643Sgnn{
3174189643Sgnn	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
3175189643Sgnn	return t3_read_reg(adap, A_TP_PIO_DATA);
3176189643Sgnn}
3177189643Sgnn
3178167514Skmacystatic void tp_config(adapter_t *adap, const struct tp_params *p)
3179167514Skmacy{
3180167514Skmacy	t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
3181167514Skmacy		     F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
3182167514Skmacy		     F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
3183167514Skmacy	t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
3184167514Skmacy		     F_MTUENABLE | V_WINDOWSCALEMODE(1) |
3185180583Skmacy		     V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
3186167514Skmacy	t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
3187167514Skmacy		     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
3188180583Skmacy		     V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) |
3189167514Skmacy		     F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
3190176472Skmacy	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO,
3191167514Skmacy			 F_IPV6ENABLE | F_NICMODE);
3192167514Skmacy	t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
3193167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
3194170654Skmacy	t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
3195170654Skmacy			 adap->params.rev > 0 ? F_ENABLEESND :
3196170654Skmacy			 			F_T3A_ENABLEESND);
3197167514Skmacy	t3_set_reg_field(adap, A_TP_PC_CONFIG,
3198170654Skmacy			 F_ENABLEEPCMDAFULL,
3199170654Skmacy			 F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
3200170654Skmacy			 F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
3201176472Skmacy	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL,
3202176472Skmacy			 F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN |
3203176472Skmacy			 F_ENABLEARPMISS | F_DISBLEDAPARBIT0);
3204170654Skmacy	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
3205170654Skmacy	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
3206167514Skmacy
3207167514Skmacy	if (adap->params.rev > 0) {
3208167514Skmacy		tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
3209171471Skmacy		t3_set_reg_field(adap, A_TP_PARA_REG3, 0,
3210171471Skmacy				 F_TXPACEAUTO | F_TXPACEAUTOSTRICT);
3211167514Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
3212171471Skmacy		tp_wr_indirect(adap, A_TP_VLAN_PRI_MAP, 0xfa50);
3213171471Skmacy		tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP0, 0xfac688);
3214171471Skmacy		tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP1, 0xfac688);
3215167514Skmacy	} else
3216167514Skmacy		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
3217167514Skmacy
3218176472Skmacy	if (adap->params.rev == T3_REV_C)
3219176472Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG,
3220176472Skmacy				 V_TABLELATENCYDELTA(M_TABLELATENCYDELTA),
3221176472Skmacy				 V_TABLELATENCYDELTA(4));
3222176472Skmacy
3223167746Skmacy	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
3224167746Skmacy	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
3225167746Skmacy	t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
3226170654Skmacy	t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
3227170654Skmacy
3228170654Skmacy	if (adap->params.nports > 2) {
3229170654Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG2, 0,
3230180583Skmacy				 F_ENABLETXPORTFROMDA2 | F_ENABLETXPORTFROMDA |
3231180583Skmacy				 F_ENABLERXPORTFROMADDR);
3232170654Skmacy		tp_wr_bits_indirect(adap, A_TP_QOS_RX_MAP_MODE,
3233170654Skmacy				    V_RXMAPMODE(M_RXMAPMODE), 0);
3234170654Skmacy		tp_wr_indirect(adap, A_TP_INGRESS_CONFIG, V_BITPOS0(48) |
3235170654Skmacy			       V_BITPOS1(49) | V_BITPOS2(50) | V_BITPOS3(51) |
3236170654Skmacy			       F_ENABLEEXTRACT | F_ENABLEEXTRACTIONSFD |
3237170654Skmacy			       F_ENABLEINSERTION | F_ENABLEINSERTIONSFD);
3238170654Skmacy		tp_wr_indirect(adap, A_TP_PREAMBLE_MSB, 0xfb000000);
3239170654Skmacy		tp_wr_indirect(adap, A_TP_PREAMBLE_LSB, 0xd5);
3240170654Skmacy		tp_wr_indirect(adap, A_TP_INTF_FROM_TX_PKT, F_INTFFROMTXPKT);
3241170654Skmacy	}
3242167514Skmacy}
3243167514Skmacy
3244167514Skmacy/* TCP timer values in ms */
3245167514Skmacy#define TP_DACK_TIMER 50
3246167514Skmacy#define TP_RTO_MIN    250
3247167514Skmacy
3248167514Skmacy/**
3249167514Skmacy *	tp_set_timers - set TP timing parameters
3250167514Skmacy *	@adap: the adapter to set
3251167514Skmacy *	@core_clk: the core clock frequency in Hz
3252167514Skmacy *
3253167514Skmacy *	Set TP's timing parameters, such as the various timer resolutions and
3254167514Skmacy *	the TCP timer values.
3255167514Skmacy */
3256167514Skmacystatic void tp_set_timers(adapter_t *adap, unsigned int core_clk)
3257167514Skmacy{
3258170654Skmacy	unsigned int tre = adap->params.tp.tre;
3259167746Skmacy	unsigned int dack_re = adap->params.tp.dack_re;
3260167514Skmacy	unsigned int tstamp_re = fls(core_clk / 1000);     /* 1ms, at least */
3261167514Skmacy	unsigned int tps = core_clk >> tre;
3262167514Skmacy
3263167514Skmacy	t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
3264167514Skmacy		     V_DELAYEDACKRESOLUTION(dack_re) |
3265167514Skmacy		     V_TIMESTAMPRESOLUTION(tstamp_re));
3266167514Skmacy	t3_write_reg(adap, A_TP_DACK_TIMER,
3267167514Skmacy		     (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
3268167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
3269167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
3270167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
3271167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
3272167514Skmacy	t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
3273167514Skmacy		     V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
3274167514Skmacy		     V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
3275167514Skmacy		     V_KEEPALIVEMAX(9));
3276167514Skmacy
3277167514Skmacy#define SECONDS * tps
3278167514Skmacy
3279167514Skmacy	t3_write_reg(adap, A_TP_MSL,
3280167514Skmacy		     adap->params.rev > 0 ? 0 : 2 SECONDS);
3281167514Skmacy	t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
3282167514Skmacy	t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
3283167514Skmacy	t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
3284167514Skmacy	t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
3285167514Skmacy	t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
3286167514Skmacy	t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
3287167514Skmacy	t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
3288167514Skmacy	t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
3289167514Skmacy
3290167514Skmacy#undef SECONDS
3291167514Skmacy}
3292167514Skmacy
3293167514Skmacy/**
3294167514Skmacy *	t3_tp_set_coalescing_size - set receive coalescing size
3295167514Skmacy *	@adap: the adapter
3296167514Skmacy *	@size: the receive coalescing size
3297167514Skmacy *	@psh: whether a set PSH bit should deliver coalesced data
3298167514Skmacy *
3299167514Skmacy *	Set the receive coalescing size and PSH bit handling.
3300167514Skmacy */
3301167514Skmacyint t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh)
3302167514Skmacy{
3303167514Skmacy	u32 val;
3304167514Skmacy
3305167514Skmacy	if (size > MAX_RX_COALESCING_LEN)
3306167514Skmacy		return -EINVAL;
3307167514Skmacy
3308167514Skmacy	val = t3_read_reg(adap, A_TP_PARA_REG3);
3309167514Skmacy	val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
3310167514Skmacy
3311167514Skmacy	if (size) {
3312167514Skmacy		val |= F_RXCOALESCEENABLE;
3313167514Skmacy		if (psh)
3314167514Skmacy			val |= F_RXCOALESCEPSHEN;
3315170654Skmacy		size = min(MAX_RX_COALESCING_LEN, size);
3316167514Skmacy		t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
3317167514Skmacy			     V_MAXRXDATA(MAX_RX_COALESCING_LEN));
3318167514Skmacy	}
3319167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG3, val);
3320167514Skmacy	return 0;
3321167514Skmacy}
3322167514Skmacy
3323167514Skmacy/**
3324167514Skmacy *	t3_tp_set_max_rxsize - set the max receive size
3325167514Skmacy *	@adap: the adapter
3326167514Skmacy *	@size: the max receive size
3327167514Skmacy *
3328167514Skmacy *	Set TP's max receive size.  This is the limit that applies when
3329167514Skmacy *	receive coalescing is disabled.
3330167514Skmacy */
3331167514Skmacyvoid t3_tp_set_max_rxsize(adapter_t *adap, unsigned int size)
3332167514Skmacy{
3333167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG7,
3334167514Skmacy		     V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
3335167514Skmacy}
3336167514Skmacy
3337167514Skmacystatic void __devinit init_mtus(unsigned short mtus[])
3338167514Skmacy{
3339167514Skmacy	/*
3340167514Skmacy	 * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
3341298955Spfg	 * it can accommodate max size TCP/IP headers when SACK and timestamps
3342167514Skmacy	 * are enabled and still have at least 8 bytes of payload.
3343167514Skmacy	 */
3344167514Skmacy	mtus[0] = 88;
3345170654Skmacy	mtus[1] = 88;
3346167746Skmacy	mtus[2] = 256;
3347167746Skmacy	mtus[3] = 512;
3348167746Skmacy	mtus[4] = 576;
3349167514Skmacy	mtus[5] = 1024;
3350167514Skmacy	mtus[6] = 1280;
3351167514Skmacy	mtus[7] = 1492;
3352167514Skmacy	mtus[8] = 1500;
3353167514Skmacy	mtus[9] = 2002;
3354167514Skmacy	mtus[10] = 2048;
3355167514Skmacy	mtus[11] = 4096;
3356167514Skmacy	mtus[12] = 4352;
3357167514Skmacy	mtus[13] = 8192;
3358167514Skmacy	mtus[14] = 9000;
3359167514Skmacy	mtus[15] = 9600;
3360167514Skmacy}
3361167514Skmacy
3362172096Skmacy/**
3363172096Skmacy *	init_cong_ctrl - initialize congestion control parameters
3364172096Skmacy *	@a: the alpha values for congestion control
3365172096Skmacy *	@b: the beta values for congestion control
3366172096Skmacy *
3367172096Skmacy *	Initialize the congestion control parameters.
3368167514Skmacy */
3369167514Skmacystatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
3370167514Skmacy{
3371167514Skmacy	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
3372167514Skmacy	a[9] = 2;
3373167514Skmacy	a[10] = 3;
3374167514Skmacy	a[11] = 4;
3375167514Skmacy	a[12] = 5;
3376167514Skmacy	a[13] = 6;
3377167514Skmacy	a[14] = 7;
3378167514Skmacy	a[15] = 8;
3379167514Skmacy	a[16] = 9;
3380167514Skmacy	a[17] = 10;
3381167514Skmacy	a[18] = 14;
3382167514Skmacy	a[19] = 17;
3383167514Skmacy	a[20] = 21;
3384167514Skmacy	a[21] = 25;
3385167514Skmacy	a[22] = 30;
3386167514Skmacy	a[23] = 35;
3387167514Skmacy	a[24] = 45;
3388167514Skmacy	a[25] = 60;
3389167514Skmacy	a[26] = 80;
3390167514Skmacy	a[27] = 100;
3391167514Skmacy	a[28] = 200;
3392167514Skmacy	a[29] = 300;
3393167514Skmacy	a[30] = 400;
3394167514Skmacy	a[31] = 500;
3395167514Skmacy
3396167514Skmacy	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
3397167514Skmacy	b[9] = b[10] = 1;
3398167514Skmacy	b[11] = b[12] = 2;
3399167514Skmacy	b[13] = b[14] = b[15] = b[16] = 3;
3400167514Skmacy	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
3401167514Skmacy	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
3402167514Skmacy	b[28] = b[29] = 6;
3403167514Skmacy	b[30] = b[31] = 7;
3404167514Skmacy}
3405167514Skmacy
3406167514Skmacy/* The minimum additive increment value for the congestion control table */
3407167514Skmacy#define CC_MIN_INCR 2U
3408167514Skmacy
3409167514Skmacy/**
3410167514Skmacy *	t3_load_mtus - write the MTU and congestion control HW tables
3411167514Skmacy *	@adap: the adapter
3412167514Skmacy *	@mtus: the unrestricted values for the MTU table
3413172096Skmacy *	@alpha: the values for the congestion control alpha parameter
3414167514Skmacy *	@beta: the values for the congestion control beta parameter
3415167514Skmacy *	@mtu_cap: the maximum permitted effective MTU
3416167514Skmacy *
3417167514Skmacy *	Write the MTU table with the supplied MTUs capping each at &mtu_cap.
3418167514Skmacy *	Update the high-speed congestion control table with the supplied alpha,
3419167514Skmacy * 	beta, and MTUs.
3420167514Skmacy */
3421167514Skmacyvoid t3_load_mtus(adapter_t *adap, unsigned short mtus[NMTUS],
3422167514Skmacy		  unsigned short alpha[NCCTRL_WIN],
3423167514Skmacy		  unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
3424167514Skmacy{
3425167514Skmacy	static const unsigned int avg_pkts[NCCTRL_WIN] = {
3426167514Skmacy		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
3427167514Skmacy		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
3428167514Skmacy		28672, 40960, 57344, 81920, 114688, 163840, 229376 };
3429167514Skmacy
3430167514Skmacy	unsigned int i, w;
3431167514Skmacy
3432167514Skmacy	for (i = 0; i < NMTUS; ++i) {
3433167514Skmacy		unsigned int mtu = min(mtus[i], mtu_cap);
3434167514Skmacy		unsigned int log2 = fls(mtu);
3435167514Skmacy
3436167514Skmacy		if (!(mtu & ((1 << log2) >> 2)))     /* round */
3437167514Skmacy			log2--;
3438167514Skmacy		t3_write_reg(adap, A_TP_MTU_TABLE,
3439167514Skmacy			     (i << 24) | (log2 << 16) | mtu);
3440167514Skmacy
3441167514Skmacy		for (w = 0; w < NCCTRL_WIN; ++w) {
3442167514Skmacy			unsigned int inc;
3443167514Skmacy
3444167514Skmacy			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
3445167514Skmacy				  CC_MIN_INCR);
3446167514Skmacy
3447167514Skmacy			t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
3448167514Skmacy				     (w << 16) | (beta[w] << 13) | inc);
3449167514Skmacy		}
3450167514Skmacy	}
3451167514Skmacy}
3452167514Skmacy
3453167514Skmacy/**
3454167514Skmacy *	t3_read_hw_mtus - returns the values in the HW MTU table
3455167514Skmacy *	@adap: the adapter
3456167514Skmacy *	@mtus: where to store the HW MTU values
3457167514Skmacy *
3458167514Skmacy *	Reads the HW MTU table.
3459167514Skmacy */
3460167514Skmacyvoid t3_read_hw_mtus(adapter_t *adap, unsigned short mtus[NMTUS])
3461167514Skmacy{
3462167514Skmacy	int i;
3463167514Skmacy
3464167514Skmacy	for (i = 0; i < NMTUS; ++i) {
3465167514Skmacy		unsigned int val;
3466167514Skmacy
3467167514Skmacy		t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
3468167514Skmacy		val = t3_read_reg(adap, A_TP_MTU_TABLE);
3469167514Skmacy		mtus[i] = val & 0x3fff;
3470167514Skmacy	}
3471167514Skmacy}
3472167514Skmacy
3473167514Skmacy/**
3474167514Skmacy *	t3_get_cong_cntl_tab - reads the congestion control table
3475167514Skmacy *	@adap: the adapter
3476167514Skmacy *	@incr: where to store the alpha values
3477167514Skmacy *
3478167514Skmacy *	Reads the additive increments programmed into the HW congestion
3479167514Skmacy *	control table.
3480167514Skmacy */
3481167514Skmacyvoid t3_get_cong_cntl_tab(adapter_t *adap,
3482167514Skmacy			  unsigned short incr[NMTUS][NCCTRL_WIN])
3483167514Skmacy{
3484167514Skmacy	unsigned int mtu, w;
3485167514Skmacy
3486167514Skmacy	for (mtu = 0; mtu < NMTUS; ++mtu)
3487167514Skmacy		for (w = 0; w < NCCTRL_WIN; ++w) {
3488167514Skmacy			t3_write_reg(adap, A_TP_CCTRL_TABLE,
3489167514Skmacy				     0xffff0000 | (mtu << 5) | w);
3490167514Skmacy			incr[mtu][w] = (unsigned short)t3_read_reg(adap,
3491167514Skmacy				        A_TP_CCTRL_TABLE) & 0x1fff;
3492167514Skmacy		}
3493167514Skmacy}
3494167514Skmacy
3495167514Skmacy/**
3496167514Skmacy *	t3_tp_get_mib_stats - read TP's MIB counters
3497167514Skmacy *	@adap: the adapter
3498167514Skmacy *	@tps: holds the returned counter values
3499167514Skmacy *
3500167514Skmacy *	Returns the values of TP's MIB counters.
3501167514Skmacy */
3502167514Skmacyvoid t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps)
3503167514Skmacy{
3504167514Skmacy	t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *)tps,
3505167514Skmacy			 sizeof(*tps) / sizeof(u32), 0);
3506167514Skmacy}
3507167514Skmacy
3508167746Skmacy/**
3509167746Skmacy *	t3_read_pace_tbl - read the pace table
3510167746Skmacy *	@adap: the adapter
3511167746Skmacy *	@pace_vals: holds the returned values
3512167746Skmacy *
3513167746Skmacy *	Returns the values of TP's pace table in nanoseconds.
3514167746Skmacy */
3515167746Skmacyvoid t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED])
3516167746Skmacy{
3517167746Skmacy	unsigned int i, tick_ns = dack_ticks_to_usec(adap, 1000);
3518167746Skmacy
3519167746Skmacy	for (i = 0; i < NTX_SCHED; i++) {
3520167746Skmacy		t3_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i);
3521167746Skmacy		pace_vals[i] = t3_read_reg(adap, A_TP_PACE_TABLE) * tick_ns;
3522167746Skmacy	}
3523167746Skmacy}
3524167746Skmacy
3525167746Skmacy/**
3526167746Skmacy *	t3_set_pace_tbl - set the pace table
3527167746Skmacy *	@adap: the adapter
3528167746Skmacy *	@pace_vals: the pace values in nanoseconds
3529167746Skmacy *	@start: index of the first entry in the HW pace table to set
3530167746Skmacy *	@n: how many entries to set
3531167746Skmacy *
3532167746Skmacy *	Sets (a subset of the) HW pace table.
3533167746Skmacy */
3534167746Skmacyvoid t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals,
3535167746Skmacy		     unsigned int start, unsigned int n)
3536167746Skmacy{
3537167746Skmacy	unsigned int tick_ns = dack_ticks_to_usec(adap, 1000);
3538167746Skmacy
3539167746Skmacy	for ( ; n; n--, start++, pace_vals++)
3540167746Skmacy		t3_write_reg(adap, A_TP_PACE_TABLE, (start << 16) |
3541167746Skmacy			     ((*pace_vals + tick_ns / 2) / tick_ns));
3542167746Skmacy}
3543167746Skmacy
3544167514Skmacy#define ulp_region(adap, name, start, len) \
3545167514Skmacy	t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
3546167514Skmacy	t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
3547167514Skmacy		     (start) + (len) - 1); \
3548167514Skmacy	start += len
3549167514Skmacy
3550167514Skmacy#define ulptx_region(adap, name, start, len) \
3551167514Skmacy	t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
3552167514Skmacy	t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
3553167514Skmacy		     (start) + (len) - 1)
3554167514Skmacy
3555167514Skmacystatic void ulp_config(adapter_t *adap, const struct tp_params *p)
3556167514Skmacy{
3557167514Skmacy	unsigned int m = p->chan_rx_size;
3558167514Skmacy
3559167514Skmacy	ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
3560167514Skmacy	ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
3561167514Skmacy	ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
3562167514Skmacy	ulp_region(adap, STAG, m, p->chan_rx_size / 4);
3563167514Skmacy	ulp_region(adap, RQ, m, p->chan_rx_size / 4);
3564167514Skmacy	ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
3565167514Skmacy	ulp_region(adap, PBL, m, p->chan_rx_size / 4);
3566167514Skmacy	t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
3567167514Skmacy}
3568170654Skmacy
3569170654Skmacy
3570170654Skmacy/**
3571170654Skmacy *	t3_set_proto_sram - set the contents of the protocol sram
3572170654Skmacy *	@adapter: the adapter
3573170654Skmacy *	@data: the protocol image
3574170654Skmacy *
3575170654Skmacy *	Write the contents of the protocol SRAM.
3576170654Skmacy */
3577171471Skmacyint t3_set_proto_sram(adapter_t *adap, const u8 *data)
3578170654Skmacy{
3579170654Skmacy	int i;
3580172096Skmacy	const u32 *buf = (const u32 *)data;
3581170654Skmacy
3582170654Skmacy	for (i = 0; i < PROTO_SRAM_LINES; i++) {
3583171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++));
3584171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++));
3585171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++));
3586171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++));
3587171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++));
3588189643Sgnn
3589170654Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
3590170654Skmacy		if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
3591170654Skmacy			return -EIO;
3592170654Skmacy	}
3593170654Skmacy	return 0;
3594170654Skmacy}
3595167514Skmacy
3596172096Skmacy/**
3597172096Skmacy *	t3_config_trace_filter - configure one of the tracing filters
3598172096Skmacy *	@adapter: the adapter
3599172096Skmacy *	@tp: the desired trace filter parameters
3600172096Skmacy *	@filter_index: which filter to configure
3601172096Skmacy *	@invert: if set non-matching packets are traced instead of matching ones
3602172096Skmacy *	@enable: whether to enable or disable the filter
3603172096Skmacy *
3604172096Skmacy *	Configures one of the tracing filters available in HW.
3605172096Skmacy */
3606167514Skmacyvoid t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp,
3607167514Skmacy			    int filter_index, int invert, int enable)
3608167514Skmacy{
3609167514Skmacy	u32 addr, key[4], mask[4];
3610167514Skmacy
3611167514Skmacy	key[0] = tp->sport | (tp->sip << 16);
3612167514Skmacy	key[1] = (tp->sip >> 16) | (tp->dport << 16);
3613167514Skmacy	key[2] = tp->dip;
3614167514Skmacy	key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
3615167514Skmacy
3616167514Skmacy	mask[0] = tp->sport_mask | (tp->sip_mask << 16);
3617167514Skmacy	mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
3618167514Skmacy	mask[2] = tp->dip_mask;
3619167514Skmacy	mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
3620167514Skmacy
3621167514Skmacy	if (invert)
3622167514Skmacy		key[3] |= (1 << 29);
3623167514Skmacy	if (enable)
3624167514Skmacy		key[3] |= (1 << 28);
3625167514Skmacy
3626167514Skmacy	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
3627167514Skmacy	tp_wr_indirect(adapter, addr++, key[0]);
3628167514Skmacy	tp_wr_indirect(adapter, addr++, mask[0]);
3629167514Skmacy	tp_wr_indirect(adapter, addr++, key[1]);
3630167514Skmacy	tp_wr_indirect(adapter, addr++, mask[1]);
3631167514Skmacy	tp_wr_indirect(adapter, addr++, key[2]);
3632167514Skmacy	tp_wr_indirect(adapter, addr++, mask[2]);
3633167514Skmacy	tp_wr_indirect(adapter, addr++, key[3]);
3634167514Skmacy	tp_wr_indirect(adapter, addr,   mask[3]);
3635167514Skmacy	(void) t3_read_reg(adapter, A_TP_PIO_DATA);
3636167514Skmacy}
3637167514Skmacy
3638167514Skmacy/**
3639189643Sgnn *	t3_query_trace_filter - query a tracing filter
3640189643Sgnn *	@adapter: the adapter
3641189643Sgnn *	@tp: the current trace filter parameters
3642189643Sgnn *	@filter_index: which filter to query
3643189643Sgnn *	@inverted: non-zero if the filter is inverted
3644189643Sgnn *	@enabled: non-zero if the filter is enabled
3645189643Sgnn *
3646189643Sgnn *	Returns the current settings of the specified HW tracing filter.
3647189643Sgnn */
3648189643Sgnnvoid t3_query_trace_filter(adapter_t *adapter, struct trace_params *tp,
3649189643Sgnn			   int filter_index, int *inverted, int *enabled)
3650189643Sgnn{
3651189643Sgnn	u32 addr, key[4], mask[4];
3652189643Sgnn
3653189643Sgnn	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
3654189643Sgnn	key[0]  = tp_rd_indirect(adapter, addr++);
3655189643Sgnn	mask[0] = tp_rd_indirect(adapter, addr++);
3656189643Sgnn	key[1]  = tp_rd_indirect(adapter, addr++);
3657189643Sgnn	mask[1] = tp_rd_indirect(adapter, addr++);
3658189643Sgnn	key[2]  = tp_rd_indirect(adapter, addr++);
3659189643Sgnn	mask[2] = tp_rd_indirect(adapter, addr++);
3660189643Sgnn	key[3]  = tp_rd_indirect(adapter, addr++);
3661189643Sgnn	mask[3] = tp_rd_indirect(adapter, addr);
3662189643Sgnn
3663189643Sgnn	tp->sport = key[0] & 0xffff;
3664189643Sgnn	tp->sip   = (key[0] >> 16) | ((key[1] & 0xffff) << 16);
3665189643Sgnn	tp->dport = key[1] >> 16;
3666189643Sgnn	tp->dip   = key[2];
3667189643Sgnn	tp->proto = key[3] & 0xff;
3668189643Sgnn	tp->vlan  = key[3] >> 8;
3669189643Sgnn	tp->intf  = key[3] >> 20;
3670189643Sgnn
3671189643Sgnn	tp->sport_mask = mask[0] & 0xffff;
3672189643Sgnn	tp->sip_mask   = (mask[0] >> 16) | ((mask[1] & 0xffff) << 16);
3673189643Sgnn	tp->dport_mask = mask[1] >> 16;
3674189643Sgnn	tp->dip_mask   = mask[2];
3675189643Sgnn	tp->proto_mask = mask[3] & 0xff;
3676189643Sgnn	tp->vlan_mask  = mask[3] >> 8;
3677189643Sgnn	tp->intf_mask  = mask[3] >> 20;
3678189643Sgnn
3679189643Sgnn	*inverted = key[3] & (1 << 29);
3680189643Sgnn	*enabled  = key[3] & (1 << 28);
3681189643Sgnn}
3682189643Sgnn
3683189643Sgnn/**
3684167514Skmacy *	t3_config_sched - configure a HW traffic scheduler
3685167514Skmacy *	@adap: the adapter
3686167514Skmacy *	@kbps: target rate in Kbps
3687167514Skmacy *	@sched: the scheduler index
3688167514Skmacy *
3689167746Skmacy *	Configure a Tx HW scheduler for the target rate.
3690167514Skmacy */
3691167514Skmacyint t3_config_sched(adapter_t *adap, unsigned int kbps, int sched)
3692167514Skmacy{
3693167514Skmacy	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
3694167514Skmacy	unsigned int clk = adap->params.vpd.cclk * 1000;
3695167514Skmacy	unsigned int selected_cpt = 0, selected_bpt = 0;
3696167514Skmacy
3697167514Skmacy	if (kbps > 0) {
3698167514Skmacy		kbps *= 125;     /* -> bytes */
3699167514Skmacy		for (cpt = 1; cpt <= 255; cpt++) {
3700167514Skmacy			tps = clk / cpt;
3701167514Skmacy			bpt = (kbps + tps / 2) / tps;
3702167514Skmacy			if (bpt > 0 && bpt <= 255) {
3703167514Skmacy				v = bpt * tps;
3704167514Skmacy				delta = v >= kbps ? v - kbps : kbps - v;
3705176472Skmacy				if (delta < mindelta) {
3706167514Skmacy					mindelta = delta;
3707167514Skmacy					selected_cpt = cpt;
3708167514Skmacy					selected_bpt = bpt;
3709167514Skmacy				}
3710167514Skmacy			} else if (selected_cpt)
3711167514Skmacy				break;
3712167514Skmacy		}
3713167514Skmacy		if (!selected_cpt)
3714167514Skmacy			return -EINVAL;
3715167514Skmacy	}
3716167514Skmacy	t3_write_reg(adap, A_TP_TM_PIO_ADDR,
3717167514Skmacy		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
3718167514Skmacy	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3719167514Skmacy	if (sched & 1)
3720167514Skmacy		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
3721167514Skmacy	else
3722167514Skmacy		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
3723167514Skmacy	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
3724167514Skmacy	return 0;
3725167514Skmacy}
3726167514Skmacy
3727167746Skmacy/**
3728167746Skmacy *	t3_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler
3729167746Skmacy *	@adap: the adapter
3730167746Skmacy *	@sched: the scheduler index
3731167746Skmacy *	@ipg: the interpacket delay in tenths of nanoseconds
3732167746Skmacy *
3733167746Skmacy *	Set the interpacket delay for a HW packet rate scheduler.
3734167746Skmacy */
3735167746Skmacyint t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg)
3736167746Skmacy{
3737167746Skmacy	unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3738167746Skmacy
3739167746Skmacy	/* convert ipg to nearest number of core clocks */
3740167746Skmacy	ipg *= core_ticks_per_usec(adap);
3741167746Skmacy	ipg = (ipg + 5000) / 10000;
3742167746Skmacy	if (ipg > 0xffff)
3743167746Skmacy		return -EINVAL;
3744167746Skmacy
3745167746Skmacy	t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3746167746Skmacy	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3747167746Skmacy	if (sched & 1)
3748167746Skmacy		v = (v & 0xffff) | (ipg << 16);
3749167746Skmacy	else
3750167746Skmacy		v = (v & 0xffff0000) | ipg;
3751167746Skmacy	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
3752167746Skmacy	t3_read_reg(adap, A_TP_TM_PIO_DATA);
3753167746Skmacy	return 0;
3754167746Skmacy}
3755167746Skmacy
3756167746Skmacy/**
3757167746Skmacy *	t3_get_tx_sched - get the configuration of a Tx HW traffic scheduler
3758167746Skmacy *	@adap: the adapter
3759167746Skmacy *	@sched: the scheduler index
3760167746Skmacy *	@kbps: the byte rate in Kbps
3761167746Skmacy *	@ipg: the interpacket delay in tenths of nanoseconds
3762167746Skmacy *
3763167746Skmacy *	Return the current configuration of a HW Tx scheduler.
3764167746Skmacy */
3765167746Skmacyvoid t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps,
3766167746Skmacy		     unsigned int *ipg)
3767167746Skmacy{
3768167746Skmacy	unsigned int v, addr, bpt, cpt;
3769167746Skmacy
3770167746Skmacy	if (kbps) {
3771167746Skmacy		addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
3772167746Skmacy		t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3773167746Skmacy		v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3774167746Skmacy		if (sched & 1)
3775167746Skmacy			v >>= 16;
3776167746Skmacy		bpt = (v >> 8) & 0xff;
3777167746Skmacy		cpt = v & 0xff;
3778167746Skmacy		if (!cpt)
3779167746Skmacy			*kbps = 0;        /* scheduler disabled */
3780167746Skmacy		else {
3781167746Skmacy			v = (adap->params.vpd.cclk * 1000) / cpt;
3782167746Skmacy			*kbps = (v * bpt) / 125;
3783167746Skmacy		}
3784167746Skmacy	}
3785167746Skmacy	if (ipg) {
3786167746Skmacy		addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3787167746Skmacy		t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3788167746Skmacy		v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3789167746Skmacy		if (sched & 1)
3790167746Skmacy			v >>= 16;
3791167746Skmacy		v &= 0xffff;
3792167746Skmacy		*ipg = (10000 * v) / core_ticks_per_usec(adap);
3793167746Skmacy	}
3794167746Skmacy}
3795167746Skmacy
3796172096Skmacy/**
3797172096Skmacy *	tp_init - configure TP
3798172096Skmacy *	@adap: the adapter
3799172096Skmacy *	@p: TP configuration parameters
3800172096Skmacy *
3801172096Skmacy *	Initializes the TP HW module.
3802172096Skmacy */
3803167514Skmacystatic int tp_init(adapter_t *adap, const struct tp_params *p)
3804167514Skmacy{
3805167514Skmacy	int busy = 0;
3806167514Skmacy
3807167514Skmacy	tp_config(adap, p);
3808167514Skmacy	t3_set_vlan_accel(adap, 3, 0);
3809167514Skmacy
3810167514Skmacy	if (is_offload(adap)) {
3811167514Skmacy		tp_set_timers(adap, adap->params.vpd.cclk * 1000);
3812167514Skmacy		t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
3813167514Skmacy		busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
3814167514Skmacy				       0, 1000, 5);
3815167514Skmacy		if (busy)
3816167514Skmacy			CH_ERR(adap, "TP initialization timed out\n");
3817167514Skmacy	}
3818167514Skmacy
3819167514Skmacy	if (!busy)
3820167514Skmacy		t3_write_reg(adap, A_TP_RESET, F_TPRESET);
3821167514Skmacy	return busy;
3822167514Skmacy}
3823167514Skmacy
3824172096Skmacy/**
3825172096Skmacy *	t3_mps_set_active_ports - configure port failover
3826172096Skmacy *	@adap: the adapter
3827172096Skmacy *	@port_mask: bitmap of active ports
3828172096Skmacy *
3829172096Skmacy *	Sets the active ports according to the supplied bitmap.
3830172096Skmacy */
3831167514Skmacyint t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask)
3832167514Skmacy{
3833167514Skmacy	if (port_mask & ~((1 << adap->params.nports) - 1))
3834167514Skmacy		return -EINVAL;
3835167514Skmacy	t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
3836167514Skmacy			 port_mask << S_PORT0ACTIVE);
3837167514Skmacy	return 0;
3838167514Skmacy}
3839167514Skmacy
3840172096Skmacy/**
3841172096Skmacy * 	chan_init_hw - channel-dependent HW initialization
3842172096Skmacy *	@adap: the adapter
3843172096Skmacy *	@chan_map: bitmap of Tx channels being used
3844172096Skmacy *
3845172096Skmacy *	Perform the bits of HW initialization that are dependent on the Tx
3846172096Skmacy *	channels being used.
3847167514Skmacy */
3848170654Skmacystatic void chan_init_hw(adapter_t *adap, unsigned int chan_map)
3849167514Skmacy{
3850167514Skmacy	int i;
3851167514Skmacy
3852170654Skmacy	if (chan_map != 3) {                                 /* one channel */
3853167514Skmacy		t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
3854167514Skmacy		t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
3855170654Skmacy		t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT |
3856170654Skmacy			     (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE :
3857170654Skmacy					      F_TPTXPORT1EN | F_PORT1ACTIVE));
3858170654Skmacy		t3_write_reg(adap, A_PM1_TX_CFG,
3859170654Skmacy			     chan_map == 1 ? 0xffffffff : 0);
3860172096Skmacy		if (chan_map == 2)
3861172096Skmacy			t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3862172096Skmacy				     V_TX_MOD_QUEUE_REQ_MAP(0xff));
3863172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xd9c8);
3864172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfbea);
3865170654Skmacy	} else {                                             /* two channels */
3866167514Skmacy		t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
3867167514Skmacy		t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
3868167514Skmacy		t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
3869167514Skmacy			     V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
3870167514Skmacy		t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
3871167514Skmacy			     F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
3872167514Skmacy			     F_ENFORCEPKT);
3873167514Skmacy		t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
3874167514Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
3875167514Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3876167514Skmacy			     V_TX_MOD_QUEUE_REQ_MAP(0xaa));
3877167514Skmacy		for (i = 0; i < 16; i++)
3878167514Skmacy			t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
3879167514Skmacy				     (i << 16) | 0x1010);
3880172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xba98);
3881172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfedc);
3882167514Skmacy	}
3883167514Skmacy}
3884167514Skmacy
3885167514Skmacystatic int calibrate_xgm(adapter_t *adapter)
3886167514Skmacy{
3887167514Skmacy	if (uses_xaui(adapter)) {
3888167514Skmacy		unsigned int v, i;
3889167514Skmacy
3890167514Skmacy		for (i = 0; i < 5; ++i) {
3891167514Skmacy			t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
3892167514Skmacy			(void) t3_read_reg(adapter, A_XGM_XAUI_IMP);
3893171471Skmacy			msleep(1);
3894167514Skmacy			v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
3895167514Skmacy			if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
3896167514Skmacy				t3_write_reg(adapter, A_XGM_XAUI_IMP,
3897167514Skmacy					     V_XAUIIMP(G_CALIMP(v) >> 2));
3898167514Skmacy				return 0;
3899167514Skmacy			}
3900167514Skmacy		}
3901167514Skmacy		CH_ERR(adapter, "MAC calibration failed\n");
3902167514Skmacy		return -1;
3903167514Skmacy	} else {
3904167514Skmacy		t3_write_reg(adapter, A_XGM_RGMII_IMP,
3905167514Skmacy			     V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3906167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3907167514Skmacy				 F_XGM_IMPSETUPDATE);
3908167514Skmacy	}
3909167514Skmacy	return 0;
3910167514Skmacy}
3911167514Skmacy
3912167514Skmacystatic void calibrate_xgm_t3b(adapter_t *adapter)
3913167514Skmacy{
3914167514Skmacy	if (!uses_xaui(adapter)) {
3915167514Skmacy		t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
3916167514Skmacy			     F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3917167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
3918167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
3919167514Skmacy				 F_XGM_IMPSETUPDATE);
3920167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3921167514Skmacy				 0);
3922167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
3923167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
3924167514Skmacy	}
3925167514Skmacy}
3926167514Skmacy
3927167514Skmacystruct mc7_timing_params {
3928167514Skmacy	unsigned char ActToPreDly;
3929167514Skmacy	unsigned char ActToRdWrDly;
3930167514Skmacy	unsigned char PreCyc;
3931167514Skmacy	unsigned char RefCyc[5];
3932167514Skmacy	unsigned char BkCyc;
3933167514Skmacy	unsigned char WrToRdDly;
3934167514Skmacy	unsigned char RdToWrDly;
3935167514Skmacy};
3936167514Skmacy
3937167514Skmacy/*
3938167514Skmacy * Write a value to a register and check that the write completed.  These
3939167514Skmacy * writes normally complete in a cycle or two, so one read should suffice.
3940167514Skmacy * The very first read exists to flush the posted write to the device.
3941167514Skmacy */
3942167514Skmacystatic int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val)
3943167514Skmacy{
3944167514Skmacy	t3_write_reg(adapter,	addr, val);
3945167514Skmacy	(void) t3_read_reg(adapter, addr);                   /* flush */
3946167514Skmacy	if (!(t3_read_reg(adapter, addr) & F_BUSY))
3947167514Skmacy		return 0;
3948167514Skmacy	CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
3949167514Skmacy	return -EIO;
3950167514Skmacy}
3951167514Skmacy
3952167514Skmacystatic int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
3953167514Skmacy{
3954167514Skmacy	static const unsigned int mc7_mode[] = {
3955167514Skmacy		0x632, 0x642, 0x652, 0x432, 0x442
3956167514Skmacy	};
3957167514Skmacy	static const struct mc7_timing_params mc7_timings[] = {
3958167514Skmacy		{ 12, 3, 4, { 20, 28, 34, 52, 0 }, 15, 6, 4 },
3959167514Skmacy		{ 12, 4, 5, { 20, 28, 34, 52, 0 }, 16, 7, 4 },
3960167514Skmacy		{ 12, 5, 6, { 20, 28, 34, 52, 0 }, 17, 8, 4 },
3961167514Skmacy		{ 9,  3, 4, { 15, 21, 26, 39, 0 }, 12, 6, 4 },
3962167514Skmacy		{ 9,  4, 5, { 15, 21, 26, 39, 0 }, 13, 7, 4 }
3963167514Skmacy	};
3964167514Skmacy
3965167514Skmacy	u32 val;
3966167514Skmacy	unsigned int width, density, slow, attempts;
3967167514Skmacy	adapter_t *adapter = mc7->adapter;
3968167514Skmacy	const struct mc7_timing_params *p = &mc7_timings[mem_type];
3969167514Skmacy
3970170654Skmacy	if (!mc7->size)
3971169978Skmacy		return 0;
3972170654Skmacy
3973167514Skmacy	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
3974167514Skmacy	slow = val & F_SLOW;
3975167514Skmacy	width = G_WIDTH(val);
3976167514Skmacy	density = G_DEN(val);
3977167514Skmacy
3978167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
3979167514Skmacy	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);  /* flush */
3980171471Skmacy	msleep(1);
3981167514Skmacy
3982167514Skmacy	if (!slow) {
3983167514Skmacy		t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
3984167514Skmacy		(void) t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
3985171471Skmacy		msleep(1);
3986167514Skmacy		if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
3987167514Skmacy		    (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
3988167514Skmacy			CH_ERR(adapter, "%s MC7 calibration timed out\n",
3989167514Skmacy			       mc7->name);
3990167514Skmacy			goto out_fail;
3991167514Skmacy		}
3992167514Skmacy	}
3993167514Skmacy
3994167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
3995167514Skmacy		     V_ACTTOPREDLY(p->ActToPreDly) |
3996167514Skmacy		     V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
3997167514Skmacy		     V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
3998167514Skmacy		     V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
3999167514Skmacy
4000167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
4001167514Skmacy		     val | F_CLKEN | F_TERM150);
4002167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
4003167514Skmacy
4004167514Skmacy	if (!slow)
4005167514Skmacy		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
4006167514Skmacy				 F_DLLENB);
4007167514Skmacy	udelay(1);
4008167514Skmacy
4009167514Skmacy	val = slow ? 3 : 6;
4010167514Skmacy	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
4011167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
4012167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
4013167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
4014167514Skmacy		goto out_fail;
4015167514Skmacy
4016167514Skmacy	if (!slow) {
4017167514Skmacy		t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
4018167514Skmacy		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL,
4019167514Skmacy				 F_DLLRST, 0);
4020167514Skmacy		udelay(5);
4021167514Skmacy	}
4022167514Skmacy
4023167514Skmacy	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
4024167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
4025167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
4026167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
4027167514Skmacy		       mc7_mode[mem_type]) ||
4028167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
4029167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
4030167514Skmacy		goto out_fail;
4031167514Skmacy
4032167514Skmacy	/* clock value is in KHz */
4033167514Skmacy	mc7_clock = mc7_clock * 7812 + mc7_clock / 2;  /* ns */
4034167514Skmacy	mc7_clock /= 1000000;                          /* KHz->MHz, ns->us */
4035167514Skmacy
4036167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_REF,
4037167514Skmacy		     F_PERREFEN | V_PREREFDIV(mc7_clock));
4038167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */
4039167514Skmacy
4040167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_ECC,
4041167514Skmacy		     F_ECCGENEN | F_ECCCHKEN);
4042167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
4043167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
4044167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
4045167514Skmacy		     (mc7->size << width) - 1);
4046167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
4047167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */
4048167514Skmacy
4049167514Skmacy	attempts = 50;
4050167514Skmacy	do {
4051171471Skmacy		msleep(250);
4052167514Skmacy		val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
4053167514Skmacy	} while ((val & F_BUSY) && --attempts);
4054167514Skmacy	if (val & F_BUSY) {
4055167514Skmacy		CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
4056167514Skmacy		goto out_fail;
4057167514Skmacy	}
4058167514Skmacy
4059167514Skmacy	/* Enable normal memory accesses. */
4060167514Skmacy	t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
4061167514Skmacy	return 0;
4062167514Skmacy
4063167514Skmacy out_fail:
4064167514Skmacy	return -1;
4065167514Skmacy}
4066167514Skmacy
4067167514Skmacystatic void config_pcie(adapter_t *adap)
4068167514Skmacy{
4069167514Skmacy	static const u16 ack_lat[4][6] = {
4070167514Skmacy		{ 237, 416, 559, 1071, 2095, 4143 },
4071167514Skmacy		{ 128, 217, 289, 545, 1057, 2081 },
4072167514Skmacy		{ 73, 118, 154, 282, 538, 1050 },
4073167514Skmacy		{ 67, 107, 86, 150, 278, 534 }
4074167514Skmacy	};
4075167514Skmacy	static const u16 rpl_tmr[4][6] = {
4076167514Skmacy		{ 711, 1248, 1677, 3213, 6285, 12429 },
4077167514Skmacy		{ 384, 651, 867, 1635, 3171, 6243 },
4078167514Skmacy		{ 219, 354, 462, 846, 1614, 3150 },
4079167514Skmacy		{ 201, 321, 258, 450, 834, 1602 }
4080167514Skmacy	};
4081167514Skmacy
4082197791Snp	u16 val, devid;
4083167514Skmacy	unsigned int log2_width, pldsize;
4084167514Skmacy	unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
4085167514Skmacy
4086167514Skmacy	t3_os_pci_read_config_2(adap,
4087167514Skmacy				adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
4088167514Skmacy				&val);
4089167514Skmacy	pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
4090167514Skmacy
4091197791Snp	/*
4092197791Snp	 * Gen2 adapter pcie bridge compatibility requires minimum
4093197791Snp	 * Max_Read_Request_size
4094197791Snp	 */
4095197791Snp	t3_os_pci_read_config_2(adap, 0x2, &devid);
4096197791Snp	if (devid == 0x37) {
4097197791Snp		t3_os_pci_write_config_2(adap,
4098197791Snp		    adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
4099197791Snp		    val & ~PCI_EXP_DEVCTL_READRQ & ~PCI_EXP_DEVCTL_PAYLOAD);
4100197791Snp		pldsize = 0;
4101197791Snp	}
4102197791Snp
4103167514Skmacy	t3_os_pci_read_config_2(adap,
4104167514Skmacy				adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
4105167514Skmacy			       	&val);
4106167514Skmacy
4107167514Skmacy	fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
4108167514Skmacy	fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
4109167514Skmacy			G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
4110167514Skmacy	log2_width = fls(adap->params.pci.width) - 1;
4111167514Skmacy	acklat = ack_lat[log2_width][pldsize];
4112167514Skmacy	if (val & 1)                            /* check LOsEnable */
4113167514Skmacy		acklat += fst_trn_tx * 4;
4114167514Skmacy	rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
4115167514Skmacy
4116167514Skmacy	if (adap->params.rev == 0)
4117167514Skmacy		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
4118167514Skmacy				 V_T3A_ACKLAT(M_T3A_ACKLAT),
4119167514Skmacy				 V_T3A_ACKLAT(acklat));
4120167514Skmacy	else
4121167514Skmacy		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
4122167514Skmacy				 V_ACKLAT(acklat));
4123167514Skmacy
4124167514Skmacy	t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
4125167514Skmacy			 V_REPLAYLMT(rpllmt));
4126167514Skmacy
4127167514Skmacy	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
4128176472Skmacy	t3_set_reg_field(adap, A_PCIE_CFG, 0,
4129189643Sgnn			 F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST |
4130176472Skmacy			 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
4131167514Skmacy}
4132167514Skmacy
4133172096Skmacy/**
4134172096Skmacy * 	t3_init_hw - initialize and configure T3 HW modules
4135172096Skmacy * 	@adapter: the adapter
4136172096Skmacy * 	@fw_params: initial parameters to pass to firmware (optional)
4137167514Skmacy *
4138172096Skmacy *	Initialize and configure T3 HW modules.  This performs the
4139172096Skmacy *	initialization steps that need to be done once after a card is reset.
4140172096Skmacy *	MAC and PHY initialization is handled separarely whenever a port is
4141172096Skmacy *	enabled.
4142172096Skmacy *
4143172096Skmacy *	@fw_params are passed to FW and their value is platform dependent.
4144172096Skmacy *	Only the top 8 bits are available for use, the rest must be 0.
4145167514Skmacy */
4146167514Skmacyint t3_init_hw(adapter_t *adapter, u32 fw_params)
4147167514Skmacy{
4148176472Skmacy	int err = -EIO, attempts, i;
4149167514Skmacy	const struct vpd_params *vpd = &adapter->params.vpd;
4150167514Skmacy
4151167514Skmacy	if (adapter->params.rev > 0)
4152167514Skmacy		calibrate_xgm_t3b(adapter);
4153167514Skmacy	else if (calibrate_xgm(adapter))
4154167514Skmacy		goto out_err;
4155167514Skmacy
4156171471Skmacy	if (adapter->params.nports > 2)
4157197791Snp		t3_mac_init(&adap2pinfo(adapter, 0)->mac);
4158170654Skmacy
4159167514Skmacy	if (vpd->mclk) {
4160167514Skmacy		partition_mem(adapter, &adapter->params.tp);
4161167514Skmacy
4162167514Skmacy		if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
4163167514Skmacy		    mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
4164167514Skmacy		    mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
4165167514Skmacy		    t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
4166167514Skmacy			        adapter->params.mc5.nfilters,
4167167514Skmacy			       	adapter->params.mc5.nroutes))
4168167514Skmacy			goto out_err;
4169176472Skmacy
4170176472Skmacy		for (i = 0; i < 32; i++)
4171176472Skmacy			if (clear_sge_ctxt(adapter, i, F_CQ))
4172176472Skmacy				goto out_err;
4173167514Skmacy	}
4174167514Skmacy
4175167514Skmacy	if (tp_init(adapter, &adapter->params.tp))
4176167514Skmacy		goto out_err;
4177167514Skmacy
4178167514Skmacy	t3_tp_set_coalescing_size(adapter,
4179167514Skmacy				  min(adapter->params.sge.max_pkt_size,
4180167514Skmacy				      MAX_RX_COALESCING_LEN), 1);
4181167514Skmacy	t3_tp_set_max_rxsize(adapter,
4182167514Skmacy			     min(adapter->params.sge.max_pkt_size, 16384U));
4183167514Skmacy	ulp_config(adapter, &adapter->params.tp);
4184167514Skmacy	if (is_pcie(adapter))
4185167514Skmacy		config_pcie(adapter);
4186167514Skmacy	else
4187176472Skmacy		t3_set_reg_field(adapter, A_PCIX_CFG, 0,
4188176472Skmacy				 F_DMASTOPEN | F_CLIDECEN);
4189167514Skmacy
4190176472Skmacy	if (adapter->params.rev == T3_REV_C)
4191176472Skmacy		t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0,
4192176472Skmacy				 F_CFG_CQE_SOP_MASK);
4193176472Skmacy
4194170654Skmacy	t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
4195172096Skmacy	t3_write_reg(adapter, A_PM1_RX_MODE, 0);
4196172096Skmacy	t3_write_reg(adapter, A_PM1_TX_MODE, 0);
4197170654Skmacy	chan_init_hw(adapter, adapter->params.chan_map);
4198167514Skmacy	t3_sge_init(adapter, &adapter->params.sge);
4199219945Snp	t3_set_reg_field(adapter, A_PL_RST, 0, F_FATALPERREN);
4200167514Skmacy
4201180583Skmacy	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
4202180583Skmacy
4203167514Skmacy	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
4204167514Skmacy	t3_write_reg(adapter, A_CIM_BOOT_CFG,
4205167514Skmacy		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
4206167514Skmacy	(void) t3_read_reg(adapter, A_CIM_BOOT_CFG);    /* flush */
4207167514Skmacy
4208176472Skmacy	attempts = 100;
4209167514Skmacy	do {                          /* wait for uP to initialize */
4210171471Skmacy		msleep(20);
4211167514Skmacy	} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
4212169978Skmacy	if (!attempts) {
4213169978Skmacy		CH_ERR(adapter, "uP initialization timed out\n");
4214167514Skmacy		goto out_err;
4215169978Skmacy	}
4216170654Skmacy
4217167514Skmacy	err = 0;
4218167514Skmacy out_err:
4219167514Skmacy	return err;
4220167514Skmacy}
4221167514Skmacy
4222167514Skmacy/**
4223167514Skmacy *	get_pci_mode - determine a card's PCI mode
4224167514Skmacy *	@adapter: the adapter
4225167514Skmacy *	@p: where to store the PCI settings
4226167514Skmacy *
4227167514Skmacy *	Determines a card's PCI mode and associated parameters, such as speed
4228167514Skmacy *	and width.
4229167514Skmacy */
4230167514Skmacystatic void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p)
4231167514Skmacy{
4232167514Skmacy	static unsigned short speed_map[] = { 33, 66, 100, 133 };
4233167514Skmacy	u32 pci_mode, pcie_cap;
4234167514Skmacy
4235167514Skmacy	pcie_cap = t3_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
4236167514Skmacy	if (pcie_cap) {
4237167514Skmacy		u16 val;
4238167514Skmacy
4239167514Skmacy		p->variant = PCI_VARIANT_PCIE;
4240167514Skmacy		p->pcie_cap_addr = pcie_cap;
4241167514Skmacy		t3_os_pci_read_config_2(adapter, pcie_cap + PCI_EXP_LNKSTA,
4242167514Skmacy					&val);
4243167514Skmacy		p->width = (val >> 4) & 0x3f;
4244167514Skmacy		return;
4245167514Skmacy	}
4246167514Skmacy
4247167514Skmacy	pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
4248167514Skmacy	p->speed = speed_map[G_PCLKRANGE(pci_mode)];
4249167514Skmacy	p->width = (pci_mode & F_64BIT) ? 64 : 32;
4250167514Skmacy	pci_mode = G_PCIXINITPAT(pci_mode);
4251167514Skmacy	if (pci_mode == 0)
4252167514Skmacy		p->variant = PCI_VARIANT_PCI;
4253167514Skmacy	else if (pci_mode < 4)
4254167514Skmacy		p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
4255167514Skmacy	else if (pci_mode < 8)
4256167514Skmacy		p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
4257167514Skmacy	else
4258167514Skmacy		p->variant = PCI_VARIANT_PCIX_266_MODE2;
4259167514Skmacy}
4260167514Skmacy
4261167514Skmacy/**
4262167514Skmacy *	init_link_config - initialize a link's SW state
4263167514Skmacy *	@lc: structure holding the link state
4264172096Skmacy *	@caps: link capabilities
4265167514Skmacy *
4266167514Skmacy *	Initializes the SW state maintained for each link, including the link's
4267167514Skmacy *	capabilities and default speed/duplex/flow-control/autonegotiation
4268167514Skmacy *	settings.
4269167514Skmacy */
4270167514Skmacystatic void __devinit init_link_config(struct link_config *lc,
4271167514Skmacy				       unsigned int caps)
4272167514Skmacy{
4273167514Skmacy	lc->supported = caps;
4274167514Skmacy	lc->requested_speed = lc->speed = SPEED_INVALID;
4275167514Skmacy	lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
4276167514Skmacy	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
4277167514Skmacy	if (lc->supported & SUPPORTED_Autoneg) {
4278167514Skmacy		lc->advertising = lc->supported;
4279167514Skmacy		lc->autoneg = AUTONEG_ENABLE;
4280167514Skmacy		lc->requested_fc |= PAUSE_AUTONEG;
4281167514Skmacy	} else {
4282167514Skmacy		lc->advertising = 0;
4283167514Skmacy		lc->autoneg = AUTONEG_DISABLE;
4284167514Skmacy	}
4285167514Skmacy}
4286167514Skmacy
4287167514Skmacy/**
4288167514Skmacy *	mc7_calc_size - calculate MC7 memory size
4289167514Skmacy *	@cfg: the MC7 configuration
4290167514Skmacy *
4291167514Skmacy *	Calculates the size of an MC7 memory in bytes from the value of its
4292167514Skmacy *	configuration register.
4293167514Skmacy */
4294167514Skmacystatic unsigned int __devinit mc7_calc_size(u32 cfg)
4295167514Skmacy{
4296167514Skmacy	unsigned int width = G_WIDTH(cfg);
4297167514Skmacy	unsigned int banks = !!(cfg & F_BKS) + 1;
4298167514Skmacy	unsigned int org = !!(cfg & F_ORG) + 1;
4299167514Skmacy	unsigned int density = G_DEN(cfg);
4300167514Skmacy	unsigned int MBs = ((256 << density) * banks) / (org << width);
4301167514Skmacy
4302167514Skmacy	return MBs << 20;
4303167514Skmacy}
4304167514Skmacy
4305167514Skmacystatic void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7,
4306167514Skmacy			       unsigned int base_addr, const char *name)
4307167514Skmacy{
4308167514Skmacy	u32 cfg;
4309167514Skmacy
4310167514Skmacy	mc7->adapter = adapter;
4311167514Skmacy	mc7->name = name;
4312167514Skmacy	mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
4313167514Skmacy	cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
4314169978Skmacy	mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
4315167514Skmacy	mc7->width = G_WIDTH(cfg);
4316167514Skmacy}
4317167514Skmacy
4318167514Skmacyvoid mac_prep(struct cmac *mac, adapter_t *adapter, int index)
4319167514Skmacy{
4320197791Snp	u16 devid;
4321197791Snp
4322167514Skmacy	mac->adapter = adapter;
4323170654Skmacy	mac->multiport = adapter->params.nports > 2;
4324170654Skmacy	if (mac->multiport) {
4325170654Skmacy		mac->ext_port = (unsigned char)index;
4326170654Skmacy		mac->nucast = 8;
4327170654Skmacy	} else
4328170654Skmacy		mac->nucast = 1;
4329170654Skmacy
4330197791Snp	/* Gen2 adapter uses VPD xauicfg[] to notify driver which MAC
4331197791Snp	   is connected to each port, its suppose to be using xgmac0 for both ports
4332197791Snp	 */
4333197791Snp	t3_os_pci_read_config_2(adapter, 0x2, &devid);
4334197791Snp
4335197791Snp	if (mac->multiport ||
4336197791Snp		(!adapter->params.vpd.xauicfg[1] && (devid==0x37)))
4337197791Snp			index  = 0;
4338197791Snp
4339167514Skmacy	mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
4340167514Skmacy
4341167514Skmacy	if (adapter->params.rev == 0 && uses_xaui(adapter)) {
4342167514Skmacy		t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
4343167514Skmacy			     is_10G(adapter) ? 0x2901c04 : 0x2301c04);
4344167514Skmacy		t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
4345167514Skmacy				 F_ENRGMII, 0);
4346167514Skmacy	}
4347167514Skmacy}
4348167514Skmacy
4349172096Skmacy/**
4350172096Skmacy *	early_hw_init - HW initialization done at card detection time
4351172096Skmacy *	@adapter: the adapter
4352172096Skmacy *	@ai: contains information about the adapter type and properties
4353172096Skmacy *
4354172096Skmacy *	Perfoms the part of HW initialization that is done early on when the
4355172096Skmacy *	driver first detecs the card.  Most of the HW state is initialized
4356172096Skmacy *	lazily later on when a port or an offload function are first used.
4357172096Skmacy */
4358167514Skmacyvoid early_hw_init(adapter_t *adapter, const struct adapter_info *ai)
4359167514Skmacy{
4360170654Skmacy	u32 val = V_PORTSPEED(is_10G(adapter) || adapter->params.nports > 2 ?
4361170654Skmacy			      3 : 2);
4362189643Sgnn	u32 gpio_out = ai->gpio_out;
4363167514Skmacy
4364167514Skmacy	mi1_init(adapter, ai);
4365167514Skmacy	t3_write_reg(adapter, A_I2C_CFG,                  /* set for 80KHz */
4366167514Skmacy		     V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
4367167514Skmacy	t3_write_reg(adapter, A_T3DBG_GPIO_EN,
4368189643Sgnn		     gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
4369169978Skmacy	t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
4370176472Skmacy	t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff));
4371170654Skmacy
4372167514Skmacy	if (adapter->params.rev == 0 || !uses_xaui(adapter))
4373167514Skmacy		val |= F_ENRGMII;
4374167514Skmacy
4375167514Skmacy	/* Enable MAC clocks so we can access the registers */
4376167514Skmacy	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
4377167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
4378167514Skmacy
4379167514Skmacy	val |= F_CLKDIVRESET_;
4380167514Skmacy	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
4381167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
4382167514Skmacy	t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
4383167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
4384167514Skmacy}
4385167514Skmacy
4386172096Skmacy/**
4387172096Skmacy *	t3_reset_adapter - reset the adapter
4388172096Skmacy *	@adapter: the adapter
4389172096Skmacy *
4390172096Skmacy * 	Reset the adapter.
4391167514Skmacy */
4392189643Sgnnint t3_reset_adapter(adapter_t *adapter)
4393167514Skmacy{
4394189643Sgnn	int i, save_and_restore_pcie =
4395167746Skmacy	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
4396167746Skmacy	uint16_t devid = 0;
4397167514Skmacy
4398167746Skmacy	if (save_and_restore_pcie)
4399167514Skmacy		t3_os_pci_save_state(adapter);
4400167514Skmacy	t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
4401167514Skmacy
4402167514Skmacy 	/*
4403167514Skmacy	 * Delay. Give Some time to device to reset fully.
4404167514Skmacy	 * XXX The delay time should be modified.
4405167514Skmacy	 */
4406167514Skmacy	for (i = 0; i < 10; i++) {
4407171471Skmacy		msleep(50);
4408167514Skmacy		t3_os_pci_read_config_2(adapter, 0x00, &devid);
4409167514Skmacy		if (devid == 0x1425)
4410167514Skmacy			break;
4411167514Skmacy	}
4412167514Skmacy
4413167514Skmacy	if (devid != 0x1425)
4414167514Skmacy		return -1;
4415167514Skmacy
4416167746Skmacy	if (save_and_restore_pcie)
4417167514Skmacy		t3_os_pci_restore_state(adapter);
4418167514Skmacy	return 0;
4419167514Skmacy}
4420167514Skmacy
4421181614Skmacystatic int init_parity(adapter_t *adap)
4422176472Skmacy{
4423176472Skmacy	int i, err, addr;
4424176472Skmacy
4425176472Skmacy	if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
4426176472Skmacy		return -EBUSY;
4427176472Skmacy
4428176472Skmacy	for (err = i = 0; !err && i < 16; i++)
4429176472Skmacy		err = clear_sge_ctxt(adap, i, F_EGRESS);
4430176472Skmacy	for (i = 0xfff0; !err && i <= 0xffff; i++)
4431176472Skmacy		err = clear_sge_ctxt(adap, i, F_EGRESS);
4432176472Skmacy	for (i = 0; !err && i < SGE_QSETS; i++)
4433176472Skmacy		err = clear_sge_ctxt(adap, i, F_RESPONSEQ);
4434176472Skmacy	if (err)
4435176472Skmacy		return err;
4436176472Skmacy
4437176472Skmacy	t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0);
4438176472Skmacy	for (i = 0; i < 4; i++)
4439176472Skmacy		for (addr = 0; addr <= M_IBQDBGADDR; addr++) {
4440176472Skmacy			t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN |
4441176472Skmacy				     F_IBQDBGWR | V_IBQDBGQID(i) |
4442176472Skmacy				     V_IBQDBGADDR(addr));
4443176472Skmacy			err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG,
4444176472Skmacy					      F_IBQDBGBUSY, 0, 2, 1);
4445176472Skmacy			if (err)
4446176472Skmacy				return err;
4447176472Skmacy		}
4448176472Skmacy	return 0;
4449176472Skmacy}
4450176472Skmacy
4451172096Skmacy/**
4452172096Skmacy *	t3_prep_adapter - prepare SW and HW for operation
4453172096Skmacy *	@adapter: the adapter
4454172096Skmacy *	@ai: contains information about the adapter type and properties
4455172096Skmacy *
4456172096Skmacy *	Initialize adapter SW state for the various HW modules, set initial
4457172096Skmacy *	values for some adapter tunables, take PHYs out of reset, and
4458172096Skmacy *	initialize the MDIO interface.
4459167514Skmacy */
4460167514Skmacyint __devinit t3_prep_adapter(adapter_t *adapter,
4461167514Skmacy			      const struct adapter_info *ai, int reset)
4462167514Skmacy{
4463167514Skmacy	int ret;
4464167514Skmacy	unsigned int i, j = 0;
4465167514Skmacy
4466167514Skmacy	get_pci_mode(adapter, &adapter->params.pci);
4467167514Skmacy
4468167514Skmacy	adapter->params.info = ai;
4469170654Skmacy	adapter->params.nports = ai->nports0 + ai->nports1;
4470201907Snp	adapter->params.chan_map = (!!ai->nports0) | (!!ai->nports1 << 1);
4471167514Skmacy	adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
4472189643Sgnn
4473189643Sgnn	/*
4474189643Sgnn	 * We used to only run the "adapter check task" once a second if
4475189643Sgnn	 * we had PHYs which didn't support interrupts (we would check
4476189643Sgnn	 * their link status once a second).  Now we check other conditions
4477189643Sgnn	 * in that routine which would [potentially] impose a very high
4478189643Sgnn	 * interrupt load on the system.  As such, we now always scan the
4479189643Sgnn	 * adapter state once a second ...
4480189643Sgnn	 */
4481189643Sgnn	adapter->params.linkpoll_period = 10;
4482189643Sgnn
4483171471Skmacy	if (adapter->params.nports > 2)
4484171471Skmacy		adapter->params.stats_update_period = VSC_STATS_ACCUM_SECS;
4485171471Skmacy	else
4486171471Skmacy		adapter->params.stats_update_period = is_10G(adapter) ?
4487171471Skmacy			MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
4488167514Skmacy	adapter->params.pci.vpd_cap_addr =
4489167514Skmacy		t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD);
4490167514Skmacy
4491167514Skmacy	ret = get_vpd_params(adapter, &adapter->params.vpd);
4492171471Skmacy	if (ret < 0)
4493167514Skmacy		return ret;
4494171471Skmacy
4495167514Skmacy	if (reset && t3_reset_adapter(adapter))
4496167514Skmacy		return -1;
4497167514Skmacy
4498167514Skmacy	if (adapter->params.vpd.mclk) {
4499167514Skmacy		struct tp_params *p = &adapter->params.tp;
4500167514Skmacy
4501167514Skmacy		mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
4502167514Skmacy		mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
4503167514Skmacy		mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
4504167514Skmacy
4505170654Skmacy		p->nchan = adapter->params.chan_map == 3 ? 2 : 1;
4506167514Skmacy		p->pmrx_size = t3_mc7_size(&adapter->pmrx);
4507167514Skmacy		p->pmtx_size = t3_mc7_size(&adapter->pmtx);
4508167514Skmacy		p->cm_size = t3_mc7_size(&adapter->cm);
4509167514Skmacy		p->chan_rx_size = p->pmrx_size / 2;     /* only 1 Rx channel */
4510167514Skmacy		p->chan_tx_size = p->pmtx_size / p->nchan;
4511167514Skmacy		p->rx_pg_size = 64 * 1024;
4512167514Skmacy		p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
4513167514Skmacy		p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
4514167514Skmacy		p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
4515167514Skmacy		p->ntimer_qs = p->cm_size >= (128 << 20) ||
4516167514Skmacy			       adapter->params.rev > 0 ? 12 : 6;
4517170654Skmacy		p->tre = fls(adapter->params.vpd.cclk / (1000 / TP_TMR_RES)) -
4518170654Skmacy			 1;
4519167746Skmacy		p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */
4520169978Skmacy	}
4521170654Skmacy
4522169978Skmacy	adapter->params.offload = t3_mc7_size(&adapter->pmrx) &&
4523170654Skmacy				  t3_mc7_size(&adapter->pmtx) &&
4524170654Skmacy				  t3_mc7_size(&adapter->cm);
4525167514Skmacy
4526205950Snp	t3_sge_prep(adapter, &adapter->params.sge);
4527205950Snp
4528169978Skmacy	if (is_offload(adapter)) {
4529167514Skmacy		adapter->params.mc5.nservers = DEFAULT_NSERVERS;
4530189643Sgnn		/* PR 6487. TOE and filtering are mutually exclusive */
4531189643Sgnn		adapter->params.mc5.nfilters = 0;
4532167514Skmacy		adapter->params.mc5.nroutes = 0;
4533167514Skmacy		t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
4534167514Skmacy
4535167514Skmacy		init_mtus(adapter->params.mtus);
4536167514Skmacy		init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
4537167514Skmacy	}
4538167514Skmacy
4539167514Skmacy	early_hw_init(adapter, ai);
4540176472Skmacy	ret = init_parity(adapter);
4541176472Skmacy	if (ret)
4542176472Skmacy		return ret;
4543167514Skmacy
4544171471Skmacy	if (adapter->params.nports > 2 &&
4545171471Skmacy	    (ret = t3_vsc7323_init(adapter, adapter->params.nports)))
4546171471Skmacy		return ret;
4547171471Skmacy
4548167514Skmacy	for_each_port(adapter, i) {
4549167514Skmacy		u8 hw_addr[6];
4550176472Skmacy		const struct port_type_info *pti;
4551170654Skmacy		struct port_info *p = adap2pinfo(adapter, i);
4552167514Skmacy
4553189643Sgnn		for (;;) {
4554189643Sgnn			unsigned port_type = adapter->params.vpd.port_type[j];
4555189643Sgnn			if (port_type) {
4556189643Sgnn				if (port_type < ARRAY_SIZE(port_types)) {
4557189643Sgnn					pti = &port_types[port_type];
4558189643Sgnn					break;
4559189643Sgnn				} else
4560189643Sgnn					return -EINVAL;
4561189643Sgnn			}
4562189643Sgnn			j++;
4563189643Sgnn			if (j >= ARRAY_SIZE(adapter->params.vpd.port_type))
4564189643Sgnn				return -EINVAL;
4565189643Sgnn		}
4566197791Snp		ret = pti->phy_prep(p, ai->phy_base_addr + j,
4567176472Skmacy				    ai->mdio_ops);
4568176472Skmacy		if (ret)
4569176472Skmacy			return ret;
4570167514Skmacy		mac_prep(&p->mac, adapter, j);
4571167514Skmacy		++j;
4572167514Skmacy
4573167514Skmacy		/*
4574167514Skmacy		 * The VPD EEPROM stores the base Ethernet address for the
4575167514Skmacy		 * card.  A port's address is derived from the base by adding
4576167514Skmacy		 * the port's index to the base's low octet.
4577167514Skmacy		 */
4578167514Skmacy		memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
4579167514Skmacy		hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
4580167514Skmacy
4581167514Skmacy		t3_os_set_hw_addr(adapter, i, hw_addr);
4582176472Skmacy		init_link_config(&p->link_config, p->phy.caps);
4583167514Skmacy		p->phy.ops->power_down(&p->phy, 1);
4584189643Sgnn
4585189643Sgnn		/*
4586189643Sgnn		 * If the PHY doesn't support interrupts for link status
4587189643Sgnn		 * changes, schedule a scan of the adapter links at least
4588189643Sgnn		 * once a second.
4589189643Sgnn		 */
4590189643Sgnn		if (!(p->phy.caps & SUPPORTED_IRQ) &&
4591189643Sgnn		    adapter->params.linkpoll_period > 10)
4592167514Skmacy			adapter->params.linkpoll_period = 10;
4593167514Skmacy	}
4594167514Skmacy
4595167514Skmacy	return 0;
4596167514Skmacy}
4597167514Skmacy
4598181614Skmacy/**
4599181614Skmacy *	t3_reinit_adapter - prepare HW for operation again
4600181614Skmacy *	@adapter: the adapter
4601181614Skmacy *
4602181614Skmacy *	Put HW in the same state as @t3_prep_adapter without any changes to
4603181614Skmacy *	SW state.  This is a cut down version of @t3_prep_adapter intended
4604181614Skmacy *	to be used after events that wipe out HW state but preserve SW state,
4605181614Skmacy *	e.g., EEH.  The device must be reset before calling this.
4606181614Skmacy */
4607181614Skmacyint t3_reinit_adapter(adapter_t *adap)
4608181614Skmacy{
4609181614Skmacy	unsigned int i;
4610189643Sgnn	int ret, j = 0;
4611181614Skmacy
4612181614Skmacy	early_hw_init(adap, adap->params.info);
4613181614Skmacy	ret = init_parity(adap);
4614181614Skmacy	if (ret)
4615181614Skmacy		return ret;
4616181614Skmacy
4617181614Skmacy	if (adap->params.nports > 2 &&
4618181614Skmacy	    (ret = t3_vsc7323_init(adap, adap->params.nports)))
4619181614Skmacy		return ret;
4620181614Skmacy
4621181614Skmacy	for_each_port(adap, i) {
4622181614Skmacy		const struct port_type_info *pti;
4623181614Skmacy		struct port_info *p = adap2pinfo(adap, i);
4624181614Skmacy
4625189643Sgnn		for (;;) {
4626189643Sgnn			unsigned port_type = adap->params.vpd.port_type[j];
4627189643Sgnn			if (port_type) {
4628189643Sgnn				if (port_type < ARRAY_SIZE(port_types)) {
4629189643Sgnn					pti = &port_types[port_type];
4630189643Sgnn					break;
4631189643Sgnn				} else
4632189643Sgnn					return -EINVAL;
4633189643Sgnn			}
4634189643Sgnn			j++;
4635189643Sgnn			if (j >= ARRAY_SIZE(adap->params.vpd.port_type))
4636189643Sgnn				return -EINVAL;
4637189643Sgnn		}
4638197791Snp		ret = pti->phy_prep(p, p->phy.addr, NULL);
4639181614Skmacy		if (ret)
4640181614Skmacy			return ret;
4641181614Skmacy		p->phy.ops->power_down(&p->phy, 1);
4642181614Skmacy	}
4643181614Skmacy	return 0;
4644181614Skmacy}
4645181614Skmacy
4646167514Skmacyvoid t3_led_ready(adapter_t *adapter)
4647167514Skmacy{
4648167514Skmacy	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
4649167514Skmacy			 F_GPIO0_OUT_VAL);
4650167514Skmacy}
4651167514Skmacy
4652167514Skmacyvoid t3_port_failover(adapter_t *adapter, int port)
4653167514Skmacy{
4654167514Skmacy	u32 val;
4655167514Skmacy
4656167514Skmacy	val = port ? F_PORT1ACTIVE : F_PORT0ACTIVE;
4657167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4658167514Skmacy			 val);
4659167514Skmacy}
4660167514Skmacy
4661167514Skmacyvoid t3_failover_done(adapter_t *adapter, int port)
4662167514Skmacy{
4663167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4664167514Skmacy			 F_PORT0ACTIVE | F_PORT1ACTIVE);
4665167514Skmacy}
4666167514Skmacy
4667167514Skmacyvoid t3_failover_clear(adapter_t *adapter)
4668167514Skmacy{
4669167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4670167514Skmacy			 F_PORT0ACTIVE | F_PORT1ACTIVE);
4671167514Skmacy}
4672189643Sgnn
4673189643Sgnnstatic int t3_cim_hac_read(adapter_t *adapter, u32 addr, u32 *val)
4674189643Sgnn{
4675189643Sgnn	u32 v;
4676189643Sgnn
4677189643Sgnn	t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr);
4678189643Sgnn	if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL,
4679189643Sgnn				F_HOSTBUSY, 0, 10, 10, &v))
4680189643Sgnn		return -EIO;
4681189643Sgnn
4682189643Sgnn	*val = t3_read_reg(adapter, A_CIM_HOST_ACC_DATA);
4683189643Sgnn
4684189643Sgnn	return 0;
4685189643Sgnn}
4686189643Sgnn
4687189643Sgnnstatic int t3_cim_hac_write(adapter_t *adapter, u32 addr, u32 val)
4688189643Sgnn{
4689189643Sgnn	u32 v;
4690189643Sgnn
4691189643Sgnn	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, val);
4692189643Sgnn
4693189643Sgnn	addr |= F_HOSTWRITE;
4694189643Sgnn	t3_write_reg(adapter, A_CIM_HOST_ACC_CTRL, addr);
4695189643Sgnn
4696189643Sgnn	if (t3_wait_op_done_val(adapter, A_CIM_HOST_ACC_CTRL,
4697189643Sgnn				F_HOSTBUSY, 0, 10, 5, &v))
4698189643Sgnn		return -EIO;
4699189643Sgnn	return 0;
4700189643Sgnn}
4701189643Sgnn
4702189643Sgnnint t3_get_up_la(adapter_t *adapter, u32 *stopped, u32 *index,
4703189643Sgnn		 u32 *size, void *data)
4704189643Sgnn{
4705189643Sgnn	u32 v, *buf = data;
4706189643Sgnn	int i, cnt,  ret;
4707189643Sgnn
4708189643Sgnn	if (*size < LA_ENTRIES * 4)
4709189643Sgnn		return -EINVAL;
4710189643Sgnn
4711189643Sgnn	ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4712189643Sgnn	if (ret)
4713189643Sgnn		goto out;
4714189643Sgnn
4715189643Sgnn	*stopped = !(v & 1);
4716189643Sgnn
4717189643Sgnn	/* Freeze LA */
4718189643Sgnn	if (!*stopped) {
4719189643Sgnn		ret = t3_cim_hac_write(adapter, LA_CTRL, 0);
4720189643Sgnn		if (ret)
4721189643Sgnn			goto out;
4722189643Sgnn	}
4723189643Sgnn
4724189643Sgnn	for (i = 0; i < LA_ENTRIES; i++) {
4725189643Sgnn		v = (i << 2) | (1 << 1);
4726189643Sgnn		ret = t3_cim_hac_write(adapter, LA_CTRL, v);
4727189643Sgnn		if (ret)
4728189643Sgnn			goto out;
4729189643Sgnn
4730189643Sgnn		ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4731189643Sgnn		if (ret)
4732189643Sgnn			goto out;
4733189643Sgnn
4734189643Sgnn		cnt = 20;
4735189643Sgnn		while ((v & (1 << 1)) && cnt) {
4736189643Sgnn			udelay(5);
4737189643Sgnn			--cnt;
4738189643Sgnn			ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4739189643Sgnn			if (ret)
4740189643Sgnn				goto out;
4741189643Sgnn		}
4742189643Sgnn
4743189643Sgnn		if (v & (1 << 1))
4744189643Sgnn			return -EIO;
4745189643Sgnn
4746189643Sgnn		ret = t3_cim_hac_read(adapter, LA_DATA, &v);
4747189643Sgnn		if (ret)
4748189643Sgnn			goto out;
4749189643Sgnn
4750189643Sgnn		*buf++ = v;
4751189643Sgnn	}
4752189643Sgnn
4753189643Sgnn	ret = t3_cim_hac_read(adapter, LA_CTRL, &v);
4754189643Sgnn	if (ret)
4755189643Sgnn		goto out;
4756189643Sgnn
4757189643Sgnn	*index = (v >> 16) + 4;
4758189643Sgnn	*size = LA_ENTRIES * 4;
4759189643Sgnnout:
4760189643Sgnn	/* Unfreeze LA */
4761189643Sgnn	t3_cim_hac_write(adapter, LA_CTRL, 1);
4762189643Sgnn	return ret;
4763189643Sgnn}
4764189643Sgnn
4765189643Sgnnint t3_get_up_ioqs(adapter_t *adapter, u32 *size, void *data)
4766189643Sgnn{
4767189643Sgnn	u32 v, *buf = data;
4768189643Sgnn	int i, j, ret;
4769189643Sgnn
4770189643Sgnn	if (*size < IOQ_ENTRIES * sizeof(struct t3_ioq_entry))
4771189643Sgnn		return -EINVAL;
4772189643Sgnn
4773189643Sgnn	for (i = 0; i < 4; i++) {
4774189643Sgnn		ret = t3_cim_hac_read(adapter, (4 * i), &v);
4775189643Sgnn		if (ret)
4776189643Sgnn			goto out;
4777189643Sgnn
4778189643Sgnn		*buf++ = v;
4779189643Sgnn	}
4780189643Sgnn
4781189643Sgnn	for (i = 0; i < IOQ_ENTRIES; i++) {
4782189643Sgnn		u32 base_addr = 0x10 * (i + 1);
4783189643Sgnn
4784189643Sgnn		for (j = 0; j < 4; j++) {
4785189643Sgnn			ret = t3_cim_hac_read(adapter, base_addr + 4 * j, &v);
4786189643Sgnn			if (ret)
4787189643Sgnn				goto out;
4788189643Sgnn
4789189643Sgnn			*buf++ = v;
4790189643Sgnn		}
4791189643Sgnn	}
4792189643Sgnn
4793189643Sgnn	*size = IOQ_ENTRIES * sizeof(struct t3_ioq_entry);
4794189643Sgnn
4795189643Sgnnout:
4796189643Sgnn	return ret;
4797189643Sgnn}
4798189643Sgnn
4799