cxgb_t3_hw.c revision 181614
1167514Skmacy/**************************************************************************
2167514Skmacy
3167514SkmacyCopyright (c) 2007, 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: head/sys/dev/cxgb/common/cxgb_t3_hw.c 181614 2008-08-11 23:01:34Z kmacy $");
32167514Skmacy
33170654Skmacy
34170076Skmacy#ifdef CONFIG_DEFINED
35170076Skmacy#include <cxgb_include.h>
36170076Skmacy#else
37170076Skmacy#include <dev/cxgb/cxgb_include.h>
38170076Skmacy#endif
39167514Skmacy
40171471Skmacy#undef msleep
41171471Skmacy#define msleep t3_os_sleep
42170654Skmacy
43167514Skmacy/**
44167514Skmacy *	t3_wait_op_done_val - wait until an operation is completed
45167514Skmacy *	@adapter: the adapter performing the operation
46167514Skmacy *	@reg: the register to check for completion
47167514Skmacy *	@mask: a single-bit field within @reg that indicates completion
48167514Skmacy *	@polarity: the value of the field when the operation is completed
49167514Skmacy *	@attempts: number of check iterations
50167514Skmacy *	@delay: delay in usecs between iterations
51167514Skmacy *	@valp: where to store the value of the register at completion time
52167514Skmacy *
53167514Skmacy *	Wait until an operation is completed by checking a bit in a register
54167514Skmacy *	up to @attempts times.  If @valp is not NULL the value of the register
55167514Skmacy *	at the time it indicated completion is stored there.  Returns 0 if the
56167514Skmacy *	operation completes and	-EAGAIN	otherwise.
57167514Skmacy */
58167514Skmacyint t3_wait_op_done_val(adapter_t *adapter, int reg, u32 mask, int polarity,
59167514Skmacy			int attempts, int delay, u32 *valp)
60167514Skmacy{
61167514Skmacy	while (1) {
62167514Skmacy		u32 val = t3_read_reg(adapter, reg);
63167514Skmacy
64167514Skmacy		if (!!(val & mask) == polarity) {
65167514Skmacy			if (valp)
66167514Skmacy				*valp = val;
67167514Skmacy			return 0;
68167514Skmacy		}
69167514Skmacy		if (--attempts == 0)
70167514Skmacy			return -EAGAIN;
71167514Skmacy		if (delay)
72167514Skmacy			udelay(delay);
73167514Skmacy	}
74167514Skmacy}
75167514Skmacy
76167514Skmacy/**
77167514Skmacy *	t3_write_regs - write a bunch of registers
78167514Skmacy *	@adapter: the adapter to program
79167514Skmacy *	@p: an array of register address/register value pairs
80167514Skmacy *	@n: the number of address/value pairs
81167514Skmacy *	@offset: register address offset
82167514Skmacy *
83167514Skmacy *	Takes an array of register address/register value pairs and writes each
84167514Skmacy *	value to the corresponding register.  Register addresses are adjusted
85167514Skmacy *	by the supplied offset.
86167514Skmacy */
87167514Skmacyvoid t3_write_regs(adapter_t *adapter, const struct addr_val_pair *p, int n,
88167514Skmacy		   unsigned int offset)
89167514Skmacy{
90167514Skmacy	while (n--) {
91167514Skmacy		t3_write_reg(adapter, p->reg_addr + offset, p->val);
92167514Skmacy		p++;
93167514Skmacy	}
94167514Skmacy}
95167514Skmacy
96167514Skmacy/**
97167514Skmacy *	t3_set_reg_field - set a register field to a value
98167514Skmacy *	@adapter: the adapter to program
99167514Skmacy *	@addr: the register address
100167514Skmacy *	@mask: specifies the portion of the register to modify
101167514Skmacy *	@val: the new value for the register field
102167514Skmacy *
103167514Skmacy *	Sets a register field specified by the supplied mask to the
104167514Skmacy *	given value.
105167514Skmacy */
106167514Skmacyvoid t3_set_reg_field(adapter_t *adapter, unsigned int addr, u32 mask, u32 val)
107167514Skmacy{
108167514Skmacy	u32 v = t3_read_reg(adapter, addr) & ~mask;
109167514Skmacy
110167514Skmacy	t3_write_reg(adapter, addr, v | val);
111167514Skmacy	(void) t3_read_reg(adapter, addr);      /* flush */
112167514Skmacy}
113167514Skmacy
114167514Skmacy/**
115167514Skmacy *	t3_read_indirect - read indirectly addressed registers
116167514Skmacy *	@adap: the adapter
117167514Skmacy *	@addr_reg: register holding the indirect address
118167514Skmacy *	@data_reg: register holding the value of the indirect register
119167514Skmacy *	@vals: where the read register values are stored
120167514Skmacy *	@start_idx: index of first indirect register to read
121167514Skmacy *	@nregs: how many indirect registers to read
122167514Skmacy *
123167514Skmacy *	Reads registers that are accessed indirectly through an address/data
124167514Skmacy *	register pair.
125167514Skmacy */
126170654Skmacystatic void t3_read_indirect(adapter_t *adap, unsigned int addr_reg,
127167514Skmacy		      unsigned int data_reg, u32 *vals, unsigned int nregs,
128167514Skmacy		      unsigned int start_idx)
129167514Skmacy{
130167514Skmacy	while (nregs--) {
131167514Skmacy		t3_write_reg(adap, addr_reg, start_idx);
132167514Skmacy		*vals++ = t3_read_reg(adap, data_reg);
133167514Skmacy		start_idx++;
134167514Skmacy	}
135167514Skmacy}
136167514Skmacy
137167514Skmacy/**
138167514Skmacy *	t3_mc7_bd_read - read from MC7 through backdoor accesses
139167514Skmacy *	@mc7: identifies MC7 to read from
140167514Skmacy *	@start: index of first 64-bit word to read
141167514Skmacy *	@n: number of 64-bit words to read
142167514Skmacy *	@buf: where to store the read result
143167514Skmacy *
144167514Skmacy *	Read n 64-bit words from MC7 starting at word start, using backdoor
145167514Skmacy *	accesses.
146167514Skmacy */
147167514Skmacyint t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
148167514Skmacy                   u64 *buf)
149167514Skmacy{
150167514Skmacy	static int shift[] = { 0, 0, 16, 24 };
151167514Skmacy	static int step[]  = { 0, 32, 16, 8 };
152167514Skmacy
153167514Skmacy	unsigned int size64 = mc7->size / 8;  /* # of 64-bit words */
154167514Skmacy	adapter_t *adap = mc7->adapter;
155167514Skmacy
156167514Skmacy	if (start >= size64 || start + n > size64)
157167514Skmacy		return -EINVAL;
158167514Skmacy
159167514Skmacy	start *= (8 << mc7->width);
160167514Skmacy	while (n--) {
161167514Skmacy		int i;
162167514Skmacy		u64 val64 = 0;
163167514Skmacy
164167514Skmacy		for (i = (1 << mc7->width) - 1; i >= 0; --i) {
165167514Skmacy			int attempts = 10;
166167514Skmacy			u32 val;
167167514Skmacy
168167514Skmacy			t3_write_reg(adap, mc7->offset + A_MC7_BD_ADDR,
169167514Skmacy				       start);
170167514Skmacy			t3_write_reg(adap, mc7->offset + A_MC7_BD_OP, 0);
171167514Skmacy			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_OP);
172167514Skmacy			while ((val & F_BUSY) && attempts--)
173167514Skmacy				val = t3_read_reg(adap,
174167514Skmacy						  mc7->offset + A_MC7_BD_OP);
175167514Skmacy			if (val & F_BUSY)
176167514Skmacy				return -EIO;
177167514Skmacy
178167514Skmacy			val = t3_read_reg(adap, mc7->offset + A_MC7_BD_DATA1);
179167514Skmacy			if (mc7->width == 0) {
180167514Skmacy				val64 = t3_read_reg(adap,
181167514Skmacy						mc7->offset + A_MC7_BD_DATA0);
182167514Skmacy				val64 |= (u64)val << 32;
183167514Skmacy			} else {
184167514Skmacy				if (mc7->width > 1)
185167514Skmacy					val >>= shift[mc7->width];
186167514Skmacy				val64 |= (u64)val << (step[mc7->width] * i);
187167514Skmacy			}
188167514Skmacy			start += 8;
189167514Skmacy		}
190167514Skmacy		*buf++ = val64;
191167514Skmacy	}
192167514Skmacy	return 0;
193167514Skmacy}
194167514Skmacy
195167514Skmacy/*
196167514Skmacy * Initialize MI1.
197167514Skmacy */
198167514Skmacystatic void mi1_init(adapter_t *adap, const struct adapter_info *ai)
199167514Skmacy{
200167514Skmacy        u32 clkdiv = adap->params.vpd.cclk / (2 * adap->params.vpd.mdc) - 1;
201167514Skmacy        u32 val = F_PREEN | V_MDIINV(ai->mdiinv) | V_MDIEN(ai->mdien) |
202167514Skmacy		  V_CLKDIV(clkdiv);
203167514Skmacy
204167514Skmacy	if (!(ai->caps & SUPPORTED_10000baseT_Full))
205167514Skmacy		val |= V_ST(1);
206167514Skmacy        t3_write_reg(adap, A_MI1_CFG, val);
207167514Skmacy}
208167514Skmacy
209170654Skmacy#define MDIO_ATTEMPTS 20
210167514Skmacy
211167514Skmacy/*
212167514Skmacy * MI1 read/write operations for direct-addressed PHYs.
213167514Skmacy */
214167514Skmacystatic int mi1_read(adapter_t *adapter, int phy_addr, int mmd_addr,
215167514Skmacy		    int reg_addr, unsigned int *valp)
216167514Skmacy{
217167514Skmacy	int ret;
218167514Skmacy	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
219167514Skmacy
220167514Skmacy	if (mmd_addr)
221167514Skmacy		return -EINVAL;
222167514Skmacy
223167514Skmacy	MDIO_LOCK(adapter);
224167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
225167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(2));
226170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
227167514Skmacy	if (!ret)
228167514Skmacy		*valp = t3_read_reg(adapter, A_MI1_DATA);
229167514Skmacy	MDIO_UNLOCK(adapter);
230167514Skmacy	return ret;
231167514Skmacy}
232167514Skmacy
233167514Skmacystatic int mi1_write(adapter_t *adapter, int phy_addr, int mmd_addr,
234167514Skmacy		     int reg_addr, unsigned int val)
235167514Skmacy{
236167514Skmacy	int ret;
237167514Skmacy	u32 addr = V_REGADDR(reg_addr) | V_PHYADDR(phy_addr);
238167514Skmacy
239167514Skmacy	if (mmd_addr)
240167514Skmacy		return -EINVAL;
241167514Skmacy
242167514Skmacy	MDIO_LOCK(adapter);
243167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
244167514Skmacy	t3_write_reg(adapter, A_MI1_DATA, val);
245167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
246170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
247167514Skmacy	MDIO_UNLOCK(adapter);
248167514Skmacy	return ret;
249167514Skmacy}
250167514Skmacy
251167514Skmacystatic struct mdio_ops mi1_mdio_ops = {
252167514Skmacy	mi1_read,
253167514Skmacy	mi1_write
254167514Skmacy};
255167514Skmacy
256167514Skmacy/*
257167514Skmacy * MI1 read/write operations for indirect-addressed PHYs.
258167514Skmacy */
259167514Skmacystatic int mi1_ext_read(adapter_t *adapter, int phy_addr, int mmd_addr,
260167514Skmacy			int reg_addr, unsigned int *valp)
261167514Skmacy{
262167514Skmacy	int ret;
263167514Skmacy	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
264167514Skmacy
265167514Skmacy	MDIO_LOCK(adapter);
266167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
267167514Skmacy	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
268167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
269170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
270167514Skmacy	if (!ret) {
271167514Skmacy		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(3));
272167514Skmacy		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
273170654Skmacy				      MDIO_ATTEMPTS, 10);
274167514Skmacy		if (!ret)
275167514Skmacy			*valp = t3_read_reg(adapter, A_MI1_DATA);
276167514Skmacy	}
277167514Skmacy	MDIO_UNLOCK(adapter);
278167514Skmacy	return ret;
279167514Skmacy}
280167514Skmacy
281167514Skmacystatic int mi1_ext_write(adapter_t *adapter, int phy_addr, int mmd_addr,
282167514Skmacy			 int reg_addr, unsigned int val)
283167514Skmacy{
284167514Skmacy	int ret;
285167514Skmacy	u32 addr = V_REGADDR(mmd_addr) | V_PHYADDR(phy_addr);
286167514Skmacy
287167514Skmacy	MDIO_LOCK(adapter);
288167514Skmacy	t3_write_reg(adapter, A_MI1_ADDR, addr);
289167514Skmacy	t3_write_reg(adapter, A_MI1_DATA, reg_addr);
290167514Skmacy	t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(0));
291170654Skmacy	ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0, MDIO_ATTEMPTS, 10);
292167514Skmacy	if (!ret) {
293167514Skmacy		t3_write_reg(adapter, A_MI1_DATA, val);
294167514Skmacy		t3_write_reg(adapter, A_MI1_OP, V_MDI_OP(1));
295167514Skmacy		ret = t3_wait_op_done(adapter, A_MI1_OP, F_BUSY, 0,
296170654Skmacy				      MDIO_ATTEMPTS, 10);
297167514Skmacy	}
298167514Skmacy	MDIO_UNLOCK(adapter);
299167514Skmacy	return ret;
300167514Skmacy}
301167514Skmacy
302167514Skmacystatic struct mdio_ops mi1_mdio_ext_ops = {
303167514Skmacy	mi1_ext_read,
304167514Skmacy	mi1_ext_write
305167514Skmacy};
306167514Skmacy
307167514Skmacy/**
308167514Skmacy *	t3_mdio_change_bits - modify the value of a PHY register
309167514Skmacy *	@phy: the PHY to operate on
310167514Skmacy *	@mmd: the device address
311167514Skmacy *	@reg: the register address
312167514Skmacy *	@clear: what part of the register value to mask off
313167514Skmacy *	@set: what part of the register value to set
314167514Skmacy *
315167514Skmacy *	Changes the value of a PHY register by applying a mask to its current
316167514Skmacy *	value and ORing the result with a new value.
317167514Skmacy */
318167514Skmacyint t3_mdio_change_bits(struct cphy *phy, int mmd, int reg, unsigned int clear,
319167514Skmacy			unsigned int set)
320167514Skmacy{
321167514Skmacy	int ret;
322167514Skmacy	unsigned int val;
323167514Skmacy
324167514Skmacy	ret = mdio_read(phy, mmd, reg, &val);
325167514Skmacy	if (!ret) {
326167514Skmacy		val &= ~clear;
327167514Skmacy		ret = mdio_write(phy, mmd, reg, val | set);
328167514Skmacy	}
329167514Skmacy	return ret;
330167514Skmacy}
331167514Skmacy
332167514Skmacy/**
333167514Skmacy *	t3_phy_reset - reset a PHY block
334167514Skmacy *	@phy: the PHY to operate on
335167514Skmacy *	@mmd: the device address of the PHY block to reset
336167514Skmacy *	@wait: how long to wait for the reset to complete in 1ms increments
337167514Skmacy *
338167514Skmacy *	Resets a PHY block and optionally waits for the reset to complete.
339167514Skmacy *	@mmd should be 0 for 10/100/1000 PHYs and the device address to reset
340167514Skmacy *	for 10G PHYs.
341167514Skmacy */
342167514Skmacyint t3_phy_reset(struct cphy *phy, int mmd, int wait)
343167514Skmacy{
344167514Skmacy	int err;
345167514Skmacy	unsigned int ctl;
346167514Skmacy
347167514Skmacy	err = t3_mdio_change_bits(phy, mmd, MII_BMCR, BMCR_PDOWN, BMCR_RESET);
348167514Skmacy	if (err || !wait)
349167514Skmacy		return err;
350167514Skmacy
351167514Skmacy	do {
352167514Skmacy		err = mdio_read(phy, mmd, MII_BMCR, &ctl);
353167514Skmacy		if (err)
354167514Skmacy			return err;
355167514Skmacy		ctl &= BMCR_RESET;
356167514Skmacy		if (ctl)
357171471Skmacy			msleep(1);
358167514Skmacy	} while (ctl && --wait);
359167514Skmacy
360167514Skmacy	return ctl ? -1 : 0;
361167514Skmacy}
362167514Skmacy
363167514Skmacy/**
364167514Skmacy *	t3_phy_advertise - set the PHY advertisement registers for autoneg
365167514Skmacy *	@phy: the PHY to operate on
366167514Skmacy *	@advert: bitmap of capabilities the PHY should advertise
367167514Skmacy *
368167514Skmacy *	Sets a 10/100/1000 PHY's advertisement registers to advertise the
369167514Skmacy *	requested capabilities.
370167514Skmacy */
371167514Skmacyint t3_phy_advertise(struct cphy *phy, unsigned int advert)
372167514Skmacy{
373167514Skmacy	int err;
374167514Skmacy	unsigned int val = 0;
375167514Skmacy
376167514Skmacy	err = mdio_read(phy, 0, MII_CTRL1000, &val);
377167514Skmacy	if (err)
378167514Skmacy		return err;
379167514Skmacy
380167514Skmacy	val &= ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
381167514Skmacy	if (advert & ADVERTISED_1000baseT_Half)
382167514Skmacy		val |= ADVERTISE_1000HALF;
383167514Skmacy	if (advert & ADVERTISED_1000baseT_Full)
384167514Skmacy		val |= ADVERTISE_1000FULL;
385167514Skmacy
386167514Skmacy	err = mdio_write(phy, 0, MII_CTRL1000, val);
387167514Skmacy	if (err)
388167514Skmacy		return err;
389167514Skmacy
390167514Skmacy	val = 1;
391167514Skmacy	if (advert & ADVERTISED_10baseT_Half)
392167514Skmacy		val |= ADVERTISE_10HALF;
393167514Skmacy	if (advert & ADVERTISED_10baseT_Full)
394167514Skmacy		val |= ADVERTISE_10FULL;
395167514Skmacy	if (advert & ADVERTISED_100baseT_Half)
396167514Skmacy		val |= ADVERTISE_100HALF;
397167514Skmacy	if (advert & ADVERTISED_100baseT_Full)
398167514Skmacy		val |= ADVERTISE_100FULL;
399167514Skmacy	if (advert & ADVERTISED_Pause)
400167514Skmacy		val |= ADVERTISE_PAUSE_CAP;
401167514Skmacy	if (advert & ADVERTISED_Asym_Pause)
402167514Skmacy		val |= ADVERTISE_PAUSE_ASYM;
403167514Skmacy	return mdio_write(phy, 0, MII_ADVERTISE, val);
404167514Skmacy}
405167514Skmacy
406167514Skmacy/**
407176472Skmacy *	t3_phy_advertise_fiber - set fiber PHY advertisement register
408176472Skmacy *	@phy: the PHY to operate on
409176472Skmacy *	@advert: bitmap of capabilities the PHY should advertise
410176472Skmacy *
411176472Skmacy *	Sets a fiber PHY's advertisement register to advertise the
412176472Skmacy *	requested capabilities.
413176472Skmacy */
414176472Skmacyint t3_phy_advertise_fiber(struct cphy *phy, unsigned int advert)
415176472Skmacy{
416176472Skmacy	unsigned int val = 0;
417176472Skmacy
418176472Skmacy	if (advert & ADVERTISED_1000baseT_Half)
419176472Skmacy		val |= ADVERTISE_1000XHALF;
420176472Skmacy	if (advert & ADVERTISED_1000baseT_Full)
421176472Skmacy		val |= ADVERTISE_1000XFULL;
422176472Skmacy	if (advert & ADVERTISED_Pause)
423176472Skmacy		val |= ADVERTISE_1000XPAUSE;
424176472Skmacy	if (advert & ADVERTISED_Asym_Pause)
425176472Skmacy		val |= ADVERTISE_1000XPSE_ASYM;
426176472Skmacy	return mdio_write(phy, 0, MII_ADVERTISE, val);
427176472Skmacy}
428176472Skmacy
429176472Skmacy/**
430167514Skmacy *	t3_set_phy_speed_duplex - force PHY speed and duplex
431167514Skmacy *	@phy: the PHY to operate on
432167514Skmacy *	@speed: requested PHY speed
433167514Skmacy *	@duplex: requested PHY duplex
434167514Skmacy *
435167514Skmacy *	Force a 10/100/1000 PHY's speed and duplex.  This also disables
436167514Skmacy *	auto-negotiation except for GigE, where auto-negotiation is mandatory.
437167514Skmacy */
438167514Skmacyint t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
439167514Skmacy{
440167514Skmacy	int err;
441167514Skmacy	unsigned int ctl;
442167514Skmacy
443167514Skmacy	err = mdio_read(phy, 0, MII_BMCR, &ctl);
444167514Skmacy	if (err)
445167514Skmacy		return err;
446167514Skmacy
447167514Skmacy	if (speed >= 0) {
448167514Skmacy		ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
449167514Skmacy		if (speed == SPEED_100)
450167514Skmacy			ctl |= BMCR_SPEED100;
451167514Skmacy		else if (speed == SPEED_1000)
452167514Skmacy			ctl |= BMCR_SPEED1000;
453167514Skmacy	}
454167514Skmacy	if (duplex >= 0) {
455167514Skmacy		ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
456167514Skmacy		if (duplex == DUPLEX_FULL)
457167514Skmacy			ctl |= BMCR_FULLDPLX;
458167514Skmacy	}
459167514Skmacy	if (ctl & BMCR_SPEED1000)  /* auto-negotiation required for GigE */
460167514Skmacy		ctl |= BMCR_ANENABLE;
461167514Skmacy	return mdio_write(phy, 0, MII_BMCR, ctl);
462167514Skmacy}
463167514Skmacy
464180583Skmacyint t3_phy_lasi_intr_enable(struct cphy *phy)
465180583Skmacy{
466180583Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 1);
467180583Skmacy}
468180583Skmacy
469180583Skmacyint t3_phy_lasi_intr_disable(struct cphy *phy)
470180583Skmacy{
471180583Skmacy	return mdio_write(phy, MDIO_DEV_PMA_PMD, LASI_CTRL, 0);
472180583Skmacy}
473180583Skmacy
474180583Skmacyint t3_phy_lasi_intr_clear(struct cphy *phy)
475180583Skmacy{
476180583Skmacy	u32 val;
477180583Skmacy
478180583Skmacy	return mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &val);
479180583Skmacy}
480180583Skmacy
481180583Skmacyint t3_phy_lasi_intr_handler(struct cphy *phy)
482180583Skmacy{
483180583Skmacy	unsigned int status;
484180583Skmacy	int err = mdio_read(phy, MDIO_DEV_PMA_PMD, LASI_STAT, &status);
485180583Skmacy
486180583Skmacy	if (err)
487180583Skmacy		return err;
488180583Skmacy	return (status & 1) ?  cphy_cause_link_change : 0;
489180583Skmacy}
490180583Skmacy
491167514Skmacystatic struct adapter_info t3_adap_info[] = {
492170654Skmacy	{ 1, 1, 0, 0, 0,
493167514Skmacy	  F_GPIO2_OEN | F_GPIO4_OEN |
494180583Skmacy	  F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
495167514Skmacy	  &mi1_mdio_ops, "Chelsio PE9000" },
496170654Skmacy	{ 1, 1, 0, 0, 0,
497167514Skmacy	  F_GPIO2_OEN | F_GPIO4_OEN |
498180583Skmacy	  F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, { S_GPIO3, S_GPIO5 }, 0,
499167514Skmacy	  &mi1_mdio_ops, "Chelsio T302" },
500170654Skmacy	{ 1, 0, 0, 0, 0,
501167514Skmacy	  F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
502176472Skmacy	  F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
503180583Skmacy	  { 0 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
504167514Skmacy	  &mi1_mdio_ext_ops, "Chelsio T310" },
505170654Skmacy	{ 1, 1, 0, 0, 0,
506167514Skmacy	  F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
507167514Skmacy	  F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
508180583Skmacy	  F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
509180583Skmacy	  { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
510167514Skmacy	  &mi1_mdio_ext_ops, "Chelsio T320" },
511170654Skmacy	{ 4, 0, 0, 0, 0,
512170654Skmacy	  F_GPIO5_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO5_OUT_VAL |
513170654Skmacy	  F_GPIO6_OUT_VAL | F_GPIO7_OUT_VAL,
514180583Skmacy	  { S_GPIO1, S_GPIO2, S_GPIO3, S_GPIO4 }, SUPPORTED_AUI,
515170654Skmacy	  &mi1_mdio_ops, "Chelsio T304" },
516167514Skmacy};
517167514Skmacy
518167514Skmacy/*
519167514Skmacy * Return the adapter_info structure with a given index.  Out-of-range indices
520167514Skmacy * return NULL.
521167514Skmacy */
522167514Skmacyconst struct adapter_info *t3_get_adapter_info(unsigned int id)
523167514Skmacy{
524167514Skmacy	return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
525167514Skmacy}
526167514Skmacy
527181614Skmacystruct port_type_info {
528181614Skmacy	int (*phy_prep)(struct cphy *phy, adapter_t *adapter, int phy_addr,
529181614Skmacy			const struct mdio_ops *ops);
530181614Skmacy};
531181614Skmacy
532167514Skmacystatic struct port_type_info port_types[] = {
533171471Skmacy	{ NULL },
534176472Skmacy	{ t3_ael1002_phy_prep },
535176472Skmacy	{ t3_vsc8211_phy_prep },
536176472Skmacy	{ t3_mv88e1xxx_phy_prep },
537176472Skmacy	{ t3_xaui_direct_phy_prep },
538180583Skmacy	{ t3_ael2005_phy_prep },
539176472Skmacy	{ t3_qt2045_phy_prep },
540176472Skmacy	{ t3_ael1006_phy_prep },
541180583Skmacy	{ t3_tn1010_phy_prep },
542167514Skmacy};
543167514Skmacy
544167514Skmacy#define VPD_ENTRY(name, len) \
545176472Skmacy	u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
546167514Skmacy
547167514Skmacy/*
548167514Skmacy * Partial EEPROM Vital Product Data structure.  Includes only the ID and
549167514Skmacy * VPD-R sections.
550167514Skmacy */
551167514Skmacystruct t3_vpd {
552167514Skmacy	u8  id_tag;
553167514Skmacy	u8  id_len[2];
554167514Skmacy	u8  id_data[16];
555167514Skmacy	u8  vpdr_tag;
556167514Skmacy	u8  vpdr_len[2];
557167514Skmacy	VPD_ENTRY(pn, 16);                     /* part number */
558167514Skmacy	VPD_ENTRY(ec, 16);                     /* EC level */
559172096Skmacy	VPD_ENTRY(sn, SERNUM_LEN);             /* serial number */
560167514Skmacy	VPD_ENTRY(na, 12);                     /* MAC address base */
561167514Skmacy	VPD_ENTRY(cclk, 6);                    /* core clock */
562167514Skmacy	VPD_ENTRY(mclk, 6);                    /* mem clock */
563167514Skmacy	VPD_ENTRY(uclk, 6);                    /* uP clk */
564167514Skmacy	VPD_ENTRY(mdc, 6);                     /* MDIO clk */
565167514Skmacy	VPD_ENTRY(mt, 2);                      /* mem timing */
566167514Skmacy	VPD_ENTRY(xaui0cfg, 6);                /* XAUI0 config */
567167514Skmacy	VPD_ENTRY(xaui1cfg, 6);                /* XAUI1 config */
568167514Skmacy	VPD_ENTRY(port0, 2);                   /* PHY0 complex */
569167514Skmacy	VPD_ENTRY(port1, 2);                   /* PHY1 complex */
570167514Skmacy	VPD_ENTRY(port2, 2);                   /* PHY2 complex */
571167514Skmacy	VPD_ENTRY(port3, 2);                   /* PHY3 complex */
572167514Skmacy	VPD_ENTRY(rv, 1);                      /* csum */
573167514Skmacy	u32 pad;                  /* for multiple-of-4 sizing and alignment */
574167514Skmacy};
575167514Skmacy
576181614Skmacy#define EEPROM_MAX_POLL   40
577167514Skmacy#define EEPROM_STAT_ADDR  0x4000
578167514Skmacy#define VPD_BASE          0xc00
579167514Skmacy
580167514Skmacy/**
581167514Skmacy *	t3_seeprom_read - read a VPD EEPROM location
582167514Skmacy *	@adapter: adapter to read
583167514Skmacy *	@addr: EEPROM address
584167514Skmacy *	@data: where to store the read data
585167514Skmacy *
586167514Skmacy *	Read a 32-bit word from a location in VPD EEPROM using the card's PCI
587167514Skmacy *	VPD ROM capability.  A zero is written to the flag bit when the
588167514Skmacy *	addres is written to the control register.  The hardware device will
589167514Skmacy *	set the flag to 1 when 4 bytes have been read into the data register.
590167514Skmacy */
591167514Skmacyint t3_seeprom_read(adapter_t *adapter, u32 addr, u32 *data)
592167514Skmacy{
593167514Skmacy	u16 val;
594167514Skmacy	int attempts = EEPROM_MAX_POLL;
595167514Skmacy	unsigned int base = adapter->params.pci.vpd_cap_addr;
596167514Skmacy
597167514Skmacy	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
598167514Skmacy		return -EINVAL;
599167514Skmacy
600167514Skmacy	t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR, (u16)addr);
601167514Skmacy	do {
602167514Skmacy		udelay(10);
603167514Skmacy		t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val);
604167514Skmacy	} while (!(val & PCI_VPD_ADDR_F) && --attempts);
605167514Skmacy
606167514Skmacy	if (!(val & PCI_VPD_ADDR_F)) {
607167514Skmacy		CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
608167514Skmacy		return -EIO;
609167514Skmacy	}
610167514Skmacy	t3_os_pci_read_config_4(adapter, base + PCI_VPD_DATA, data);
611167514Skmacy	*data = le32_to_cpu(*data);
612167514Skmacy	return 0;
613167514Skmacy}
614167514Skmacy
615167514Skmacy/**
616167514Skmacy *	t3_seeprom_write - write a VPD EEPROM location
617167514Skmacy *	@adapter: adapter to write
618167514Skmacy *	@addr: EEPROM address
619167514Skmacy *	@data: value to write
620167514Skmacy *
621167514Skmacy *	Write a 32-bit word to a location in VPD EEPROM using the card's PCI
622167514Skmacy *	VPD ROM capability.
623167514Skmacy */
624167514Skmacyint t3_seeprom_write(adapter_t *adapter, u32 addr, u32 data)
625167514Skmacy{
626167514Skmacy	u16 val;
627167514Skmacy	int attempts = EEPROM_MAX_POLL;
628167514Skmacy	unsigned int base = adapter->params.pci.vpd_cap_addr;
629167514Skmacy
630167514Skmacy	if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
631167514Skmacy		return -EINVAL;
632167514Skmacy
633167514Skmacy	t3_os_pci_write_config_4(adapter, base + PCI_VPD_DATA,
634167514Skmacy				 cpu_to_le32(data));
635167514Skmacy	t3_os_pci_write_config_2(adapter, base + PCI_VPD_ADDR,
636167514Skmacy				 (u16)addr | PCI_VPD_ADDR_F);
637167514Skmacy	do {
638171471Skmacy		msleep(1);
639167514Skmacy		t3_os_pci_read_config_2(adapter, base + PCI_VPD_ADDR, &val);
640167514Skmacy	} while ((val & PCI_VPD_ADDR_F) && --attempts);
641167514Skmacy
642167514Skmacy	if (val & PCI_VPD_ADDR_F) {
643167514Skmacy		CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
644167514Skmacy		return -EIO;
645167514Skmacy	}
646167514Skmacy	return 0;
647167514Skmacy}
648167514Skmacy
649167514Skmacy/**
650167514Skmacy *	t3_seeprom_wp - enable/disable EEPROM write protection
651167514Skmacy *	@adapter: the adapter
652167514Skmacy *	@enable: 1 to enable write protection, 0 to disable it
653167514Skmacy *
654167514Skmacy *	Enables or disables write protection on the serial EEPROM.
655167514Skmacy */
656167514Skmacyint t3_seeprom_wp(adapter_t *adapter, int enable)
657167514Skmacy{
658167514Skmacy	return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
659167514Skmacy}
660167514Skmacy
661167514Skmacy/*
662167514Skmacy * Convert a character holding a hex digit to a number.
663167514Skmacy */
664167514Skmacystatic unsigned int hex2int(unsigned char c)
665167514Skmacy{
666167514Skmacy	return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
667167514Skmacy}
668167514Skmacy
669167514Skmacy/**
670167514Skmacy *	get_vpd_params - read VPD parameters from VPD EEPROM
671167514Skmacy *	@adapter: adapter to read
672167514Skmacy *	@p: where to store the parameters
673167514Skmacy *
674167514Skmacy *	Reads card parameters stored in VPD EEPROM.
675167514Skmacy */
676167514Skmacystatic int get_vpd_params(adapter_t *adapter, struct vpd_params *p)
677167514Skmacy{
678167514Skmacy	int i, addr, ret;
679167514Skmacy	struct t3_vpd vpd;
680167514Skmacy
681167514Skmacy	/*
682167514Skmacy	 * Card information is normally at VPD_BASE but some early cards had
683167514Skmacy	 * it at 0.
684167514Skmacy	 */
685167514Skmacy	ret = t3_seeprom_read(adapter, VPD_BASE, (u32 *)&vpd);
686167514Skmacy	if (ret)
687167514Skmacy		return ret;
688167514Skmacy	addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
689167514Skmacy
690167514Skmacy	for (i = 0; i < sizeof(vpd); i += 4) {
691167514Skmacy		ret = t3_seeprom_read(adapter, addr + i,
692167514Skmacy				      (u32 *)((u8 *)&vpd + i));
693167514Skmacy		if (ret)
694167514Skmacy			return ret;
695167514Skmacy	}
696167514Skmacy
697167514Skmacy	p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
698167514Skmacy	p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
699167514Skmacy	p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
700167514Skmacy	p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
701167514Skmacy	p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
702172096Skmacy	memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
703167514Skmacy
704167514Skmacy	/* Old eeproms didn't have port information */
705167514Skmacy	if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
706167514Skmacy		p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
707167514Skmacy		p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
708167514Skmacy	} else {
709167514Skmacy		p->port_type[0] = (u8)hex2int(vpd.port0_data[0]);
710167514Skmacy		p->port_type[1] = (u8)hex2int(vpd.port1_data[0]);
711170654Skmacy		p->port_type[2] = (u8)hex2int(vpd.port2_data[0]);
712170654Skmacy		p->port_type[3] = (u8)hex2int(vpd.port3_data[0]);
713167514Skmacy		p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
714167514Skmacy		p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
715167514Skmacy	}
716167514Skmacy
717167514Skmacy	for (i = 0; i < 6; i++)
718167514Skmacy		p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
719167514Skmacy				 hex2int(vpd.na_data[2 * i + 1]);
720167514Skmacy	return 0;
721167514Skmacy}
722167514Skmacy
723176472Skmacy/* BIOS boot header */
724176472Skmacytypedef struct boot_header_s {
725176472Skmacy	u8	signature[2];	/* signature */
726176472Skmacy	u8	length;		/* image length (include header) */
727176472Skmacy	u8	offset[4];	/* initialization vector */
728176472Skmacy	u8	reserved[19];	/* reserved */
729176472Skmacy	u8	exheader[2];	/* offset to expansion header */
730176472Skmacy} boot_header_t;
731176472Skmacy
732167514Skmacy/* serial flash and firmware constants */
733167514Skmacyenum {
734167514Skmacy	SF_ATTEMPTS = 5,           /* max retries for SF1 operations */
735167514Skmacy	SF_SEC_SIZE = 64 * 1024,   /* serial flash sector size */
736167514Skmacy	SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */
737167514Skmacy
738167514Skmacy	/* flash command opcodes */
739167514Skmacy	SF_PROG_PAGE    = 2,       /* program page */
740167514Skmacy	SF_WR_DISABLE   = 4,       /* disable writes */
741167514Skmacy	SF_RD_STATUS    = 5,       /* read status register */
742167514Skmacy	SF_WR_ENABLE    = 6,       /* enable writes */
743167514Skmacy	SF_RD_DATA_FAST = 0xb,     /* read flash */
744167514Skmacy	SF_ERASE_SECTOR = 0xd8,    /* erase sector */
745167514Skmacy
746167514Skmacy	FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */
747167746Skmacy	FW_VERS_ADDR = 0x77ffc,    /* flash address holding FW version */
748176472Skmacy	FW_MIN_SIZE = 8,           /* at least version and csum */
749176472Skmacy	FW_MAX_SIZE = FW_VERS_ADDR - FW_FLASH_BOOT_ADDR,
750176472Skmacy
751176472Skmacy	BOOT_FLASH_BOOT_ADDR = 0x0,/* start address of boot image in flash */
752176472Skmacy	BOOT_SIGNATURE = 0xaa55,   /* signature of BIOS boot ROM */
753176472Skmacy	BOOT_SIZE_INC = 512,       /* image size measured in 512B chunks */
754176472Skmacy	BOOT_MIN_SIZE = sizeof(boot_header_t), /* at least basic header */
755176472Skmacy	BOOT_MAX_SIZE = 0xff*BOOT_SIZE_INC /* 1 byte * length increment  */
756167514Skmacy};
757167514Skmacy
758167514Skmacy/**
759167514Skmacy *	sf1_read - read data from the serial flash
760167514Skmacy *	@adapter: the adapter
761167514Skmacy *	@byte_cnt: number of bytes to read
762167514Skmacy *	@cont: whether another operation will be chained
763167514Skmacy *	@valp: where to store the read data
764167514Skmacy *
765167514Skmacy *	Reads up to 4 bytes of data from the serial flash.  The location of
766167514Skmacy *	the read needs to be specified prior to calling this by issuing the
767167514Skmacy *	appropriate commands to the serial flash.
768167514Skmacy */
769167514Skmacystatic int sf1_read(adapter_t *adapter, unsigned int byte_cnt, int cont,
770167514Skmacy		    u32 *valp)
771167514Skmacy{
772167514Skmacy	int ret;
773167514Skmacy
774167514Skmacy	if (!byte_cnt || byte_cnt > 4)
775167514Skmacy		return -EINVAL;
776167514Skmacy	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
777167514Skmacy		return -EBUSY;
778167514Skmacy	t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
779167514Skmacy	ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
780167514Skmacy	if (!ret)
781167514Skmacy		*valp = t3_read_reg(adapter, A_SF_DATA);
782167514Skmacy	return ret;
783167514Skmacy}
784167514Skmacy
785167514Skmacy/**
786167514Skmacy *	sf1_write - write data to the serial flash
787167514Skmacy *	@adapter: the adapter
788167514Skmacy *	@byte_cnt: number of bytes to write
789167514Skmacy *	@cont: whether another operation will be chained
790167514Skmacy *	@val: value to write
791167514Skmacy *
792167514Skmacy *	Writes up to 4 bytes of data to the serial flash.  The location of
793167514Skmacy *	the write needs to be specified prior to calling this by issuing the
794167514Skmacy *	appropriate commands to the serial flash.
795167514Skmacy */
796167514Skmacystatic int sf1_write(adapter_t *adapter, unsigned int byte_cnt, int cont,
797167514Skmacy		     u32 val)
798167514Skmacy{
799167514Skmacy	if (!byte_cnt || byte_cnt > 4)
800167514Skmacy		return -EINVAL;
801167514Skmacy	if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
802167514Skmacy		return -EBUSY;
803167514Skmacy	t3_write_reg(adapter, A_SF_DATA, val);
804167514Skmacy	t3_write_reg(adapter, A_SF_OP,
805167514Skmacy		     V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
806167514Skmacy	return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
807167514Skmacy}
808167514Skmacy
809167514Skmacy/**
810167514Skmacy *	flash_wait_op - wait for a flash operation to complete
811167514Skmacy *	@adapter: the adapter
812167514Skmacy *	@attempts: max number of polls of the status register
813167514Skmacy *	@delay: delay between polls in ms
814167514Skmacy *
815167514Skmacy *	Wait for a flash operation to complete by polling the status register.
816167514Skmacy */
817167514Skmacystatic int flash_wait_op(adapter_t *adapter, int attempts, int delay)
818167514Skmacy{
819167514Skmacy	int ret;
820167514Skmacy	u32 status;
821167514Skmacy
822167514Skmacy	while (1) {
823167514Skmacy		if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
824167514Skmacy		    (ret = sf1_read(adapter, 1, 0, &status)) != 0)
825167514Skmacy			return ret;
826167514Skmacy		if (!(status & 1))
827167514Skmacy			return 0;
828167514Skmacy		if (--attempts == 0)
829167514Skmacy			return -EAGAIN;
830167514Skmacy		if (delay)
831171471Skmacy			msleep(delay);
832167514Skmacy	}
833167514Skmacy}
834167514Skmacy
835167514Skmacy/**
836167514Skmacy *	t3_read_flash - read words from serial flash
837167514Skmacy *	@adapter: the adapter
838167514Skmacy *	@addr: the start address for the read
839167514Skmacy *	@nwords: how many 32-bit words to read
840167514Skmacy *	@data: where to store the read data
841167514Skmacy *	@byte_oriented: whether to store data as bytes or as words
842167514Skmacy *
843167514Skmacy *	Read the specified number of 32-bit words from the serial flash.
844167514Skmacy *	If @byte_oriented is set the read data is stored as a byte array
845167514Skmacy *	(i.e., big-endian), otherwise as 32-bit words in the platform's
846167514Skmacy *	natural endianess.
847167514Skmacy */
848167514Skmacyint t3_read_flash(adapter_t *adapter, unsigned int addr, unsigned int nwords,
849167514Skmacy		  u32 *data, int byte_oriented)
850167514Skmacy{
851167514Skmacy	int ret;
852167514Skmacy
853167514Skmacy	if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
854167514Skmacy		return -EINVAL;
855167514Skmacy
856167514Skmacy	addr = swab32(addr) | SF_RD_DATA_FAST;
857167514Skmacy
858167514Skmacy	if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
859167514Skmacy	    (ret = sf1_read(adapter, 1, 1, data)) != 0)
860167514Skmacy		return ret;
861167514Skmacy
862167514Skmacy	for ( ; nwords; nwords--, data++) {
863167514Skmacy		ret = sf1_read(adapter, 4, nwords > 1, data);
864167514Skmacy		if (ret)
865167514Skmacy			return ret;
866167514Skmacy		if (byte_oriented)
867167514Skmacy			*data = htonl(*data);
868167514Skmacy	}
869167514Skmacy	return 0;
870167514Skmacy}
871167514Skmacy
872167514Skmacy/**
873167514Skmacy *	t3_write_flash - write up to a page of data to the serial flash
874167514Skmacy *	@adapter: the adapter
875167514Skmacy *	@addr: the start address to write
876167514Skmacy *	@n: length of data to write
877167514Skmacy *	@data: the data to write
878176472Skmacy *	@byte_oriented: whether to store data as bytes or as words
879167514Skmacy *
880167514Skmacy *	Writes up to a page of data (256 bytes) to the serial flash starting
881167514Skmacy *	at the given address.
882176472Skmacy *	If @byte_oriented is set the write data is stored as a 32-bit
883176472Skmacy *	big-endian array, otherwise in the processor's native endianess.
884176472Skmacy *
885167514Skmacy */
886167514Skmacystatic int t3_write_flash(adapter_t *adapter, unsigned int addr,
887176472Skmacy			  unsigned int n, const u8 *data,
888176472Skmacy			  int byte_oriented)
889167514Skmacy{
890167514Skmacy	int ret;
891167514Skmacy	u32 buf[64];
892176472Skmacy	unsigned int c, left, val, offset = addr & 0xff;
893167514Skmacy
894167514Skmacy	if (addr + n > SF_SIZE || offset + n > 256)
895167514Skmacy		return -EINVAL;
896167514Skmacy
897167514Skmacy	val = swab32(addr) | SF_PROG_PAGE;
898167514Skmacy
899167514Skmacy	if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
900167514Skmacy	    (ret = sf1_write(adapter, 4, 1, val)) != 0)
901167514Skmacy		return ret;
902167514Skmacy
903167514Skmacy	for (left = n; left; left -= c) {
904167514Skmacy		c = min(left, 4U);
905176472Skmacy		val = *(const u32*)data;
906176472Skmacy		data += c;
907176472Skmacy		if (byte_oriented)
908176472Skmacy			val = htonl(val);
909167514Skmacy
910167514Skmacy		ret = sf1_write(adapter, c, c != left, val);
911167514Skmacy		if (ret)
912167514Skmacy			return ret;
913167514Skmacy	}
914167514Skmacy	if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
915167514Skmacy		return ret;
916167514Skmacy
917167514Skmacy	/* Read the page to verify the write succeeded */
918176472Skmacy	ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf,
919176472Skmacy			    byte_oriented);
920167514Skmacy	if (ret)
921167514Skmacy		return ret;
922167514Skmacy
923167514Skmacy	if (memcmp(data - n, (u8 *)buf + offset, n))
924167514Skmacy		return -EIO;
925167514Skmacy	return 0;
926167514Skmacy}
927167514Skmacy
928170654Skmacy/**
929171471Skmacy *	t3_get_tp_version - read the tp sram version
930171471Skmacy *	@adapter: the adapter
931171471Skmacy *	@vers: where to place the version
932171471Skmacy *
933171471Skmacy *	Reads the protocol sram version from sram.
934171471Skmacy */
935171471Skmacyint t3_get_tp_version(adapter_t *adapter, u32 *vers)
936171471Skmacy{
937171471Skmacy	int ret;
938171471Skmacy
939171471Skmacy	/* Get version loaded in SRAM */
940171471Skmacy	t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
941171471Skmacy	ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
942171471Skmacy			      1, 1, 5, 1);
943171471Skmacy	if (ret)
944171471Skmacy		return ret;
945171471Skmacy
946171471Skmacy	*vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
947171471Skmacy
948171471Skmacy	return 0;
949171471Skmacy}
950171471Skmacy
951171471Skmacy/**
952170654Skmacy *	t3_check_tpsram_version - read the tp sram version
953170654Skmacy *	@adapter: the adapter
954170654Skmacy *
955170654Skmacy */
956176472Skmacyint t3_check_tpsram_version(adapter_t *adapter, int *must_load)
957170654Skmacy{
958170654Skmacy	int ret;
959170654Skmacy	u32 vers;
960170654Skmacy	unsigned int major, minor;
961170654Skmacy
962176472Skmacy	if (adapter->params.rev == T3_REV_A)
963176472Skmacy		return 0;
964176472Skmacy
965176472Skmacy	*must_load = 1;
966176472Skmacy
967176472Skmacy	ret = t3_get_tp_version(adapter, &vers);
968170654Skmacy	if (ret)
969170654Skmacy		return ret;
970170654Skmacy
971170654Skmacy	vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
972170654Skmacy
973170654Skmacy	major = G_TP_VERSION_MAJOR(vers);
974170654Skmacy	minor = G_TP_VERSION_MINOR(vers);
975170654Skmacy
976170654Skmacy	if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
977170654Skmacy		return 0;
978170654Skmacy
979176472Skmacy	if (major != TP_VERSION_MAJOR)
980176472Skmacy		CH_ERR(adapter, "found wrong TP version (%u.%u), "
981176472Skmacy		       "driver needs version %d.%d\n", major, minor,
982176472Skmacy		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
983176472Skmacy	else {
984176472Skmacy		*must_load = 0;
985176472Skmacy		CH_ERR(adapter, "found wrong TP version (%u.%u), "
986176472Skmacy		       "driver compiled for version %d.%d\n", major, minor,
987176472Skmacy		       TP_VERSION_MAJOR, TP_VERSION_MINOR);
988176472Skmacy	}
989170654Skmacy	return -EINVAL;
990170654Skmacy}
991170654Skmacy
992170654Skmacy/**
993170654Skmacy *	t3_check_tpsram - check if provided protocol SRAM
994170654Skmacy *			  is compatible with this driver
995170654Skmacy *	@adapter: the adapter
996170654Skmacy *	@tp_sram: the firmware image to write
997170654Skmacy *	@size: image size
998170654Skmacy *
999170654Skmacy *	Checks if an adapter's tp sram is compatible with the driver.
1000170654Skmacy *	Returns 0 if the versions are compatible, a negative error otherwise.
1001170654Skmacy */
1002171471Skmacyint t3_check_tpsram(adapter_t *adapter, const u8 *tp_sram, unsigned int size)
1003170654Skmacy{
1004170654Skmacy	u32 csum;
1005170654Skmacy	unsigned int i;
1006170654Skmacy	const u32 *p = (const u32 *)tp_sram;
1007170654Skmacy
1008170654Skmacy	/* Verify checksum */
1009170654Skmacy	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1010170654Skmacy		csum += ntohl(p[i]);
1011170654Skmacy	if (csum != 0xffffffff) {
1012170654Skmacy		CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
1013170654Skmacy		       csum);
1014170654Skmacy		return -EINVAL;
1015170654Skmacy	}
1016170654Skmacy
1017170654Skmacy	return 0;
1018170654Skmacy}
1019170654Skmacy
1020167514Skmacyenum fw_version_type {
1021167514Skmacy	FW_VERSION_N3,
1022167514Skmacy	FW_VERSION_T3
1023167514Skmacy};
1024167514Skmacy
1025167514Skmacy/**
1026167514Skmacy *	t3_get_fw_version - read the firmware version
1027167514Skmacy *	@adapter: the adapter
1028167514Skmacy *	@vers: where to place the version
1029167514Skmacy *
1030167514Skmacy *	Reads the FW version from flash.
1031167514Skmacy */
1032167514Skmacyint t3_get_fw_version(adapter_t *adapter, u32 *vers)
1033167514Skmacy{
1034167514Skmacy	return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
1035167514Skmacy}
1036167514Skmacy
1037167514Skmacy/**
1038167514Skmacy *	t3_check_fw_version - check if the FW is compatible with this driver
1039167514Skmacy *	@adapter: the adapter
1040167514Skmacy *
1041167514Skmacy *	Checks if an adapter's FW is compatible with the driver.  Returns 0
1042167514Skmacy *	if the versions are compatible, a negative error otherwise.
1043167514Skmacy */
1044176472Skmacyint t3_check_fw_version(adapter_t *adapter, int *must_load)
1045167514Skmacy{
1046167514Skmacy	int ret;
1047167514Skmacy	u32 vers;
1048167514Skmacy	unsigned int type, major, minor;
1049167514Skmacy
1050176472Skmacy	*must_load = 1;
1051167514Skmacy	ret = t3_get_fw_version(adapter, &vers);
1052167514Skmacy	if (ret)
1053167514Skmacy		return ret;
1054167514Skmacy
1055167514Skmacy	type = G_FW_VERSION_TYPE(vers);
1056167514Skmacy	major = G_FW_VERSION_MAJOR(vers);
1057167514Skmacy	minor = G_FW_VERSION_MINOR(vers);
1058167514Skmacy
1059167746Skmacy	if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR &&
1060167746Skmacy	    minor == FW_VERSION_MINOR)
1061167514Skmacy		return 0;
1062167514Skmacy
1063176472Skmacy	if (major != FW_VERSION_MAJOR)
1064176472Skmacy		CH_ERR(adapter, "found wrong FW version(%u.%u), "
1065176472Skmacy		       "driver needs version %u.%u\n", major, minor,
1066176472Skmacy		       FW_VERSION_MAJOR, FW_VERSION_MINOR);
1067176472Skmacy	else if ((int)minor < FW_VERSION_MINOR) {
1068176472Skmacy		*must_load = 0;
1069176472Skmacy		CH_WARN(adapter, "found old FW minor version(%u.%u), "
1070176472Skmacy		        "driver compiled for version %u.%u\n", major, minor,
1071176472Skmacy			FW_VERSION_MAJOR, FW_VERSION_MINOR);
1072176472Skmacy	} else {
1073176472Skmacy		CH_WARN(adapter, "found newer FW version(%u.%u), "
1074176472Skmacy		        "driver compiled for version %u.%u\n", major, minor,
1075176472Skmacy			FW_VERSION_MAJOR, FW_VERSION_MINOR);
1076176472Skmacy			return 0;
1077176472Skmacy	}
1078167514Skmacy	return -EINVAL;
1079167514Skmacy}
1080167514Skmacy
1081167514Skmacy/**
1082167514Skmacy *	t3_flash_erase_sectors - erase a range of flash sectors
1083167514Skmacy *	@adapter: the adapter
1084167514Skmacy *	@start: the first sector to erase
1085167514Skmacy *	@end: the last sector to erase
1086167514Skmacy *
1087167514Skmacy *	Erases the sectors in the given range.
1088167514Skmacy */
1089167514Skmacystatic int t3_flash_erase_sectors(adapter_t *adapter, int start, int end)
1090167514Skmacy{
1091167514Skmacy	while (start <= end) {
1092167514Skmacy		int ret;
1093167514Skmacy
1094167514Skmacy		if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
1095167514Skmacy		    (ret = sf1_write(adapter, 4, 0,
1096167514Skmacy				     SF_ERASE_SECTOR | (start << 8))) != 0 ||
1097167514Skmacy		    (ret = flash_wait_op(adapter, 5, 500)) != 0)
1098167514Skmacy			return ret;
1099167514Skmacy		start++;
1100167514Skmacy	}
1101167514Skmacy	return 0;
1102167514Skmacy}
1103167514Skmacy
1104167514Skmacy/*
1105167514Skmacy *	t3_load_fw - download firmware
1106167514Skmacy *	@adapter: the adapter
1107170654Skmacy *	@fw_data: the firmware image to write
1108167514Skmacy *	@size: image size
1109167514Skmacy *
1110167514Skmacy *	Write the supplied firmware image to the card's serial flash.
1111167514Skmacy *	The FW image has the following sections: @size - 8 bytes of code and
1112167514Skmacy *	data, followed by 4 bytes of FW version, followed by the 32-bit
1113167514Skmacy *	1's complement checksum of the whole image.
1114167514Skmacy */
1115167514Skmacyint t3_load_fw(adapter_t *adapter, const u8 *fw_data, unsigned int size)
1116167514Skmacy{
1117167514Skmacy	u32 csum;
1118167514Skmacy	unsigned int i;
1119167514Skmacy	const u32 *p = (const u32 *)fw_data;
1120167514Skmacy	int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
1121167514Skmacy
1122170654Skmacy	if ((size & 3) || size < FW_MIN_SIZE)
1123167514Skmacy		return -EINVAL;
1124176472Skmacy	if (size - 8 > FW_MAX_SIZE)
1125167514Skmacy		return -EFBIG;
1126167514Skmacy
1127167514Skmacy	for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1128167514Skmacy		csum += ntohl(p[i]);
1129167514Skmacy	if (csum != 0xffffffff) {
1130167514Skmacy		CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
1131167514Skmacy		       csum);
1132167514Skmacy		return -EINVAL;
1133167514Skmacy	}
1134167514Skmacy
1135167514Skmacy	ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
1136167514Skmacy	if (ret)
1137167514Skmacy		goto out;
1138167514Skmacy
1139167514Skmacy	size -= 8;  /* trim off version and checksum */
1140167514Skmacy	for (addr = FW_FLASH_BOOT_ADDR; size; ) {
1141167514Skmacy		unsigned int chunk_size = min(size, 256U);
1142167514Skmacy
1143176472Skmacy		ret = t3_write_flash(adapter, addr, chunk_size, fw_data, 1);
1144167514Skmacy		if (ret)
1145167514Skmacy			goto out;
1146167514Skmacy
1147167514Skmacy		addr += chunk_size;
1148167514Skmacy		fw_data += chunk_size;
1149167514Skmacy		size -= chunk_size;
1150167514Skmacy	}
1151167514Skmacy
1152176472Skmacy	ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data, 1);
1153167514Skmacyout:
1154167514Skmacy	if (ret)
1155167514Skmacy		CH_ERR(adapter, "firmware download failed, error %d\n", ret);
1156167514Skmacy	return ret;
1157167514Skmacy}
1158167514Skmacy
1159176472Skmacy/*
1160176472Skmacy *	t3_load_boot - download boot flash
1161176472Skmacy *	@adapter: the adapter
1162176472Skmacy *	@boot_data: the boot image to write
1163176472Skmacy *	@size: image size
1164176472Skmacy *
1165176472Skmacy *	Write the supplied boot image to the card's serial flash.
1166176472Skmacy *	The boot image has the following sections: a 28-byte header and the
1167176472Skmacy *	boot image.
1168176472Skmacy */
1169176472Skmacyint t3_load_boot(adapter_t *adapter, u8 *boot_data, unsigned int size)
1170176472Skmacy{
1171176472Skmacy	boot_header_t *header = (boot_header_t *)boot_data;
1172176472Skmacy	int ret;
1173176472Skmacy	unsigned int addr;
1174176472Skmacy	unsigned int boot_sector = BOOT_FLASH_BOOT_ADDR >> 16;
1175176472Skmacy	unsigned int boot_end = (BOOT_FLASH_BOOT_ADDR + size - 1) >> 16;
1176176472Skmacy
1177176472Skmacy	/*
1178176472Skmacy	 * Perform some primitive sanity testing to avoid accidentally
1179176472Skmacy	 * writing garbage over the boot sectors.  We ought to check for
1180176472Skmacy	 * more but it's not worth it for now ...
1181176472Skmacy	 */
1182176472Skmacy	if (size < BOOT_MIN_SIZE || size > BOOT_MAX_SIZE) {
1183176472Skmacy		CH_ERR(adapter, "boot image too small/large\n");
1184176472Skmacy		return -EFBIG;
1185176472Skmacy	}
1186176472Skmacy	if (le16_to_cpu(*(u16*)header->signature) != BOOT_SIGNATURE) {
1187176472Skmacy		CH_ERR(adapter, "boot image missing signature\n");
1188176472Skmacy		return -EINVAL;
1189176472Skmacy	}
1190176472Skmacy	if (header->length * BOOT_SIZE_INC != size) {
1191176472Skmacy		CH_ERR(adapter, "boot image header length != image length\n");
1192176472Skmacy		return -EINVAL;
1193176472Skmacy	}
1194176472Skmacy
1195176472Skmacy	ret = t3_flash_erase_sectors(adapter, boot_sector, boot_end);
1196176472Skmacy	if (ret)
1197176472Skmacy		goto out;
1198176472Skmacy
1199176472Skmacy	for (addr = BOOT_FLASH_BOOT_ADDR; size; ) {
1200176472Skmacy		unsigned int chunk_size = min(size, 256U);
1201176472Skmacy
1202176472Skmacy		ret = t3_write_flash(adapter, addr, chunk_size, boot_data, 0);
1203176472Skmacy		if (ret)
1204176472Skmacy			goto out;
1205176472Skmacy
1206176472Skmacy		addr += chunk_size;
1207176472Skmacy		boot_data += chunk_size;
1208176472Skmacy		size -= chunk_size;
1209176472Skmacy	}
1210176472Skmacy
1211176472Skmacyout:
1212176472Skmacy	if (ret)
1213176472Skmacy		CH_ERR(adapter, "boot image download failed, error %d\n", ret);
1214176472Skmacy	return ret;
1215176472Skmacy}
1216176472Skmacy
1217167514Skmacy#define CIM_CTL_BASE 0x2000
1218167514Skmacy
1219167514Skmacy/**
1220167514Skmacy *	t3_cim_ctl_blk_read - read a block from CIM control region
1221167514Skmacy *	@adap: the adapter
1222167514Skmacy *	@addr: the start address within the CIM control region
1223167514Skmacy *	@n: number of words to read
1224167514Skmacy *	@valp: where to store the result
1225167514Skmacy *
1226167514Skmacy *	Reads a block of 4-byte words from the CIM control region.
1227167514Skmacy */
1228167514Skmacyint t3_cim_ctl_blk_read(adapter_t *adap, unsigned int addr, unsigned int n,
1229167514Skmacy			unsigned int *valp)
1230167514Skmacy{
1231167514Skmacy	int ret = 0;
1232167514Skmacy
1233167514Skmacy	if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1234167514Skmacy		return -EBUSY;
1235167514Skmacy
1236167514Skmacy	for ( ; !ret && n--; addr += 4) {
1237167514Skmacy		t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
1238167514Skmacy		ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1239167514Skmacy				      0, 5, 2);
1240167514Skmacy		if (!ret)
1241167514Skmacy			*valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
1242167514Skmacy	}
1243167514Skmacy	return ret;
1244167514Skmacy}
1245167514Skmacy
1246167514Skmacy/**
1247167514Skmacy *	t3_link_changed - handle interface link changes
1248167514Skmacy *	@adapter: the adapter
1249167514Skmacy *	@port_id: the port index that changed link state
1250167514Skmacy *
1251167514Skmacy *	Called when a port's link settings change to propagate the new values
1252167514Skmacy *	to the associated PHY and MAC.  After performing the common tasks it
1253167514Skmacy *	invokes an OS-specific handler.
1254167514Skmacy */
1255167514Skmacyvoid t3_link_changed(adapter_t *adapter, int port_id)
1256167514Skmacy{
1257167514Skmacy	int link_ok, speed, duplex, fc;
1258170654Skmacy	struct port_info *pi = adap2pinfo(adapter, port_id);
1259170654Skmacy	struct cphy *phy = &pi->phy;
1260170654Skmacy	struct cmac *mac = &pi->mac;
1261170654Skmacy	struct link_config *lc = &pi->link_config;
1262167514Skmacy
1263167514Skmacy	phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1264167514Skmacy
1265180583Skmacy	if (lc->requested_fc & PAUSE_AUTONEG)
1266180583Skmacy		fc &= lc->requested_fc;
1267180583Skmacy	else
1268180583Skmacy		fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1269180583Skmacy
1270180583Skmacy	if (link_ok == lc->link_ok && speed == lc->speed &&
1271180583Skmacy	    duplex == lc->duplex && fc == lc->fc)
1272180583Skmacy		return;                            /* nothing changed */
1273180583Skmacy
1274167514Skmacy	if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
1275167514Skmacy	    uses_xaui(adapter)) {
1276167514Skmacy		if (link_ok)
1277167514Skmacy			t3b_pcs_reset(mac);
1278167514Skmacy		t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
1279167514Skmacy			     link_ok ? F_TXACTENABLE | F_RXEN : 0);
1280167514Skmacy	}
1281167514Skmacy	lc->link_ok = (unsigned char)link_ok;
1282167514Skmacy	lc->speed = speed < 0 ? SPEED_INVALID : speed;
1283167514Skmacy	lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1284167514Skmacy
1285167514Skmacy	if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
1286167514Skmacy		/* Set MAC speed, duplex, and flow control to match PHY. */
1287167514Skmacy		t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
1288167514Skmacy		lc->fc = (unsigned char)fc;
1289167514Skmacy	}
1290167514Skmacy
1291167514Skmacy	t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
1292167514Skmacy}
1293167514Skmacy
1294167514Skmacy/**
1295167514Skmacy *	t3_link_start - apply link configuration to MAC/PHY
1296167514Skmacy *	@phy: the PHY to setup
1297167514Skmacy *	@mac: the MAC to setup
1298167514Skmacy *	@lc: the requested link configuration
1299167514Skmacy *
1300167514Skmacy *	Set up a port's MAC and PHY according to a desired link configuration.
1301167514Skmacy *	- If the PHY can auto-negotiate first decide what to advertise, then
1302167514Skmacy *	  enable/disable auto-negotiation as desired, and reset.
1303167514Skmacy *	- If the PHY does not auto-negotiate just reset it.
1304167514Skmacy *	- If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
1305167514Skmacy *	  otherwise do it later based on the outcome of auto-negotiation.
1306167514Skmacy */
1307167514Skmacyint t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
1308167514Skmacy{
1309167514Skmacy	unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1310167514Skmacy
1311167514Skmacy	lc->link_ok = 0;
1312167514Skmacy	if (lc->supported & SUPPORTED_Autoneg) {
1313167514Skmacy		lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
1314167514Skmacy		if (fc) {
1315167514Skmacy			lc->advertising |= ADVERTISED_Asym_Pause;
1316167514Skmacy			if (fc & PAUSE_RX)
1317167514Skmacy				lc->advertising |= ADVERTISED_Pause;
1318167514Skmacy		}
1319167514Skmacy		phy->ops->advertise(phy, lc->advertising);
1320167514Skmacy
1321167514Skmacy		if (lc->autoneg == AUTONEG_DISABLE) {
1322167514Skmacy			lc->speed = lc->requested_speed;
1323167514Skmacy			lc->duplex = lc->requested_duplex;
1324167514Skmacy			lc->fc = (unsigned char)fc;
1325167514Skmacy			t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
1326167514Skmacy						   fc);
1327167514Skmacy			/* Also disables autoneg */
1328167514Skmacy			phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
1329167514Skmacy		} else
1330167514Skmacy			phy->ops->autoneg_enable(phy);
1331167514Skmacy	} else {
1332167514Skmacy		t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
1333167514Skmacy		lc->fc = (unsigned char)fc;
1334167514Skmacy		phy->ops->reset(phy, 0);
1335167514Skmacy	}
1336167514Skmacy	return 0;
1337167514Skmacy}
1338167514Skmacy
1339167514Skmacy/**
1340167514Skmacy *	t3_set_vlan_accel - control HW VLAN extraction
1341167514Skmacy *	@adapter: the adapter
1342167514Skmacy *	@ports: bitmap of adapter ports to operate on
1343167514Skmacy *	@on: enable (1) or disable (0) HW VLAN extraction
1344167514Skmacy *
1345167514Skmacy *	Enables or disables HW extraction of VLAN tags for the given port.
1346167514Skmacy */
1347167514Skmacyvoid t3_set_vlan_accel(adapter_t *adapter, unsigned int ports, int on)
1348167514Skmacy{
1349167514Skmacy	t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
1350167514Skmacy			 ports << S_VLANEXTRACTIONENABLE,
1351167514Skmacy			 on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
1352167514Skmacy}
1353167514Skmacy
1354167514Skmacystruct intr_info {
1355167514Skmacy	unsigned int mask;       /* bits to check in interrupt status */
1356167514Skmacy	const char *msg;         /* message to print or NULL */
1357167514Skmacy	short stat_idx;          /* stat counter to increment or -1 */
1358181614Skmacy	unsigned short fatal;    /* whether the condition reported is fatal */
1359167514Skmacy};
1360167514Skmacy
1361167514Skmacy/**
1362167514Skmacy *	t3_handle_intr_status - table driven interrupt handler
1363167514Skmacy *	@adapter: the adapter that generated the interrupt
1364167514Skmacy *	@reg: the interrupt status register to process
1365167514Skmacy *	@mask: a mask to apply to the interrupt status
1366167514Skmacy *	@acts: table of interrupt actions
1367167514Skmacy *	@stats: statistics counters tracking interrupt occurences
1368167514Skmacy *
1369167514Skmacy *	A table driven interrupt handler that applies a set of masks to an
1370167514Skmacy *	interrupt status word and performs the corresponding actions if the
1371167514Skmacy *	interrupts described by the mask have occured.  The actions include
1372167514Skmacy *	optionally printing a warning or alert message, and optionally
1373167514Skmacy *	incrementing a stat counter.  The table is terminated by an entry
1374167514Skmacy *	specifying mask 0.  Returns the number of fatal interrupt conditions.
1375167514Skmacy */
1376167514Skmacystatic int t3_handle_intr_status(adapter_t *adapter, unsigned int reg,
1377167514Skmacy				 unsigned int mask,
1378167514Skmacy				 const struct intr_info *acts,
1379167514Skmacy				 unsigned long *stats)
1380167514Skmacy{
1381167514Skmacy	int fatal = 0;
1382167514Skmacy	unsigned int status = t3_read_reg(adapter, reg) & mask;
1383167514Skmacy
1384167514Skmacy	for ( ; acts->mask; ++acts) {
1385167514Skmacy		if (!(status & acts->mask)) continue;
1386167514Skmacy		if (acts->fatal) {
1387167514Skmacy			fatal++;
1388167514Skmacy			CH_ALERT(adapter, "%s (0x%x)\n",
1389167514Skmacy				 acts->msg, status & acts->mask);
1390167514Skmacy		} else if (acts->msg)
1391167514Skmacy			CH_WARN(adapter, "%s (0x%x)\n",
1392167514Skmacy				acts->msg, status & acts->mask);
1393167514Skmacy		if (acts->stat_idx >= 0)
1394167514Skmacy			stats[acts->stat_idx]++;
1395167514Skmacy	}
1396167514Skmacy	if (status)                           /* clear processed interrupts */
1397167514Skmacy		t3_write_reg(adapter, reg, status);
1398167514Skmacy	return fatal;
1399167514Skmacy}
1400167514Skmacy
1401176472Skmacy#define SGE_INTR_MASK (F_RSPQDISABLED | \
1402176472Skmacy		       F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \
1403176472Skmacy		       F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
1404176472Skmacy		       F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
1405176472Skmacy		       V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
1406176472Skmacy		       F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
1407176472Skmacy		       F_HIRCQPARITYERROR)
1408167514Skmacy#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
1409167514Skmacy		       F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
1410167514Skmacy		       F_NFASRCHFAIL)
1411167514Skmacy#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
1412167514Skmacy#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1413167514Skmacy		       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
1414167514Skmacy		       F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
1415167514Skmacy#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
1416167514Skmacy			F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
1417167514Skmacy			F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
1418167514Skmacy			F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
1419167514Skmacy			V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
1420167514Skmacy			V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
1421167514Skmacy#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
1422167514Skmacy			F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
1423167514Skmacy			/* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
1424176472Skmacy			F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \
1425176472Skmacy			F_TXPARERR | V_BISTERR(M_BISTERR))
1426176472Skmacy#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \
1427176472Skmacy			 F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \
1428176472Skmacy			 F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0)
1429176472Skmacy#define ULPTX_INTR_MASK 0xfc
1430176472Skmacy#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \
1431167514Skmacy			 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
1432167514Skmacy			 F_ZERO_SWITCH_ERROR)
1433167514Skmacy#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
1434167514Skmacy		       F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
1435167514Skmacy		       F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
1436176472Skmacy	 	       F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \
1437176472Skmacy		       F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \
1438176472Skmacy		       F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \
1439176472Skmacy		       F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \
1440176472Skmacy		       F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR)
1441167514Skmacy#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
1442167514Skmacy			V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
1443167514Skmacy			V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
1444167514Skmacy#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
1445167514Skmacy			V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
1446167514Skmacy			V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
1447167514Skmacy#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
1448167514Skmacy		       V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
1449167514Skmacy		       V_RXTPPARERRENB(M_RXTPPARERRENB) | \
1450167514Skmacy		       V_MCAPARERRENB(M_MCAPARERRENB))
1451167514Skmacy#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
1452167514Skmacy		      F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
1453167514Skmacy		      F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
1454167514Skmacy		      F_MPS0 | F_CPL_SWITCH)
1455167514Skmacy
1456167514Skmacy/*
1457167514Skmacy * Interrupt handler for the PCIX1 module.
1458167514Skmacy */
1459167514Skmacystatic void pci_intr_handler(adapter_t *adapter)
1460167514Skmacy{
1461167514Skmacy	static struct intr_info pcix1_intr_info[] = {
1462167514Skmacy		{ F_MSTDETPARERR, "PCI master detected parity error", -1, 1 },
1463167514Skmacy		{ F_SIGTARABT, "PCI signaled target abort", -1, 1 },
1464167514Skmacy		{ F_RCVTARABT, "PCI received target abort", -1, 1 },
1465167514Skmacy		{ F_RCVMSTABT, "PCI received master abort", -1, 1 },
1466167514Skmacy		{ F_SIGSYSERR, "PCI signaled system error", -1, 1 },
1467167514Skmacy		{ F_DETPARERR, "PCI detected parity error", -1, 1 },
1468167514Skmacy		{ F_SPLCMPDIS, "PCI split completion discarded", -1, 1 },
1469167514Skmacy		{ F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1 },
1470167514Skmacy		{ F_RCVSPLCMPERR, "PCI received split completion error", -1,
1471167514Skmacy		  1 },
1472167514Skmacy		{ F_DETCORECCERR, "PCI correctable ECC error",
1473167514Skmacy		  STAT_PCI_CORR_ECC, 0 },
1474167514Skmacy		{ F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1 },
1475167514Skmacy		{ F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 },
1476167514Skmacy		{ V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
1477167514Skmacy		  1 },
1478167514Skmacy		{ V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
1479167514Skmacy		  1 },
1480167514Skmacy		{ V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
1481167514Skmacy		  1 },
1482167514Skmacy		{ V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
1483167514Skmacy		  "error", -1, 1 },
1484167514Skmacy		{ 0 }
1485167514Skmacy	};
1486167514Skmacy
1487167514Skmacy	if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
1488167514Skmacy				  pcix1_intr_info, adapter->irq_stats))
1489167514Skmacy		t3_fatal_err(adapter);
1490167514Skmacy}
1491167514Skmacy
1492167514Skmacy/*
1493167514Skmacy * Interrupt handler for the PCIE module.
1494167514Skmacy */
1495167514Skmacystatic void pcie_intr_handler(adapter_t *adapter)
1496167514Skmacy{
1497167514Skmacy	static struct intr_info pcie_intr_info[] = {
1498167514Skmacy		{ F_PEXERR, "PCI PEX error", -1, 1 },
1499167514Skmacy		{ F_UNXSPLCPLERRR,
1500167514Skmacy		  "PCI unexpected split completion DMA read error", -1, 1 },
1501167514Skmacy		{ F_UNXSPLCPLERRC,
1502167514Skmacy		  "PCI unexpected split completion DMA command error", -1, 1 },
1503167514Skmacy		{ F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1 },
1504167514Skmacy		{ F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1 },
1505167514Skmacy		{ F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1 },
1506167514Skmacy		{ F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1 },
1507167514Skmacy		{ V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
1508167514Skmacy		  "PCI MSI-X table/PBA parity error", -1, 1 },
1509176472Skmacy		{ F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1 },
1510176472Skmacy		{ F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1 },
1511176472Skmacy		{ F_RXPARERR, "PCI Rx parity error", -1, 1 },
1512176472Skmacy		{ F_TXPARERR, "PCI Tx parity error", -1, 1 },
1513167514Skmacy		{ V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1 },
1514167514Skmacy		{ 0 }
1515167514Skmacy	};
1516167514Skmacy
1517172096Skmacy	if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
1518172096Skmacy		CH_ALERT(adapter, "PEX error code 0x%x\n",
1519172096Skmacy			 t3_read_reg(adapter, A_PCIE_PEX_ERR));
1520172096Skmacy
1521167514Skmacy	if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
1522167514Skmacy				  pcie_intr_info, adapter->irq_stats))
1523167514Skmacy		t3_fatal_err(adapter);
1524167514Skmacy}
1525167514Skmacy
1526167514Skmacy/*
1527167514Skmacy * TP interrupt handler.
1528167514Skmacy */
1529167514Skmacystatic void tp_intr_handler(adapter_t *adapter)
1530167514Skmacy{
1531167514Skmacy	static struct intr_info tp_intr_info[] = {
1532167514Skmacy		{ 0xffffff,  "TP parity error", -1, 1 },
1533167514Skmacy		{ 0x1000000, "TP out of Rx pages", -1, 1 },
1534167514Skmacy		{ 0x2000000, "TP out of Tx pages", -1, 1 },
1535167514Skmacy		{ 0 }
1536167514Skmacy	};
1537176472Skmacy	static struct intr_info tp_intr_info_t3c[] = {
1538176472Skmacy		{ 0x1fffffff,  "TP parity error", -1, 1 },
1539176472Skmacy		{ F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1 },
1540176472Skmacy		{ F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
1541176472Skmacy		{ 0 }
1542176472Skmacy	};
1543167514Skmacy
1544167514Skmacy	if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
1545176472Skmacy				  adapter->params.rev < T3_REV_C ?
1546176472Skmacy					tp_intr_info : tp_intr_info_t3c, NULL))
1547167514Skmacy		t3_fatal_err(adapter);
1548167514Skmacy}
1549167514Skmacy
1550167514Skmacy/*
1551167514Skmacy * CIM interrupt handler.
1552167514Skmacy */
1553167514Skmacystatic void cim_intr_handler(adapter_t *adapter)
1554167514Skmacy{
1555167514Skmacy	static struct intr_info cim_intr_info[] = {
1556167514Skmacy		{ F_RSVDSPACEINT, "CIM reserved space write", -1, 1 },
1557167514Skmacy		{ F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1 },
1558167514Skmacy		{ F_FLASHRANGEINT, "CIM flash address out of range", -1, 1 },
1559167514Skmacy		{ F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
1560167514Skmacy		{ F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1 },
1561167514Skmacy		{ F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
1562167514Skmacy		{ F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1 },
1563167514Skmacy		{ F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
1564167514Skmacy		{ F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1 },
1565167514Skmacy		{ F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1 },
1566167514Skmacy		{ F_BLKRDPLINT, "CIM block read from PL space", -1, 1 },
1567167514Skmacy		{ F_BLKWRPLINT, "CIM block write to PL space", -1, 1 },
1568176472Skmacy		{ F_DRAMPARERR, "CIM DRAM parity error", -1, 1 },
1569176472Skmacy		{ F_ICACHEPARERR, "CIM icache parity error", -1, 1 },
1570176472Skmacy		{ F_DCACHEPARERR, "CIM dcache parity error", -1, 1 },
1571176472Skmacy		{ F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1 },
1572176472Skmacy		{ F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1 },
1573176472Skmacy		{ F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1 },
1574176472Skmacy		{ F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1 },
1575176472Skmacy		{ F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1 },
1576176472Skmacy		{ F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1 },
1577176472Skmacy		{ F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1 },
1578176472Skmacy		{ F_ITAGPARERR, "CIM itag parity error", -1, 1 },
1579176472Skmacy		{ F_DTAGPARERR, "CIM dtag parity error", -1, 1 },
1580167514Skmacy		{ 0 }
1581167514Skmacy        };
1582167514Skmacy
1583176472Skmacy	if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, CIM_INTR_MASK,
1584167514Skmacy				  cim_intr_info, NULL))
1585167514Skmacy		t3_fatal_err(adapter);
1586167514Skmacy}
1587167514Skmacy
1588167514Skmacy/*
1589167514Skmacy * ULP RX interrupt handler.
1590167514Skmacy */
1591167514Skmacystatic void ulprx_intr_handler(adapter_t *adapter)
1592167514Skmacy{
1593167514Skmacy	static struct intr_info ulprx_intr_info[] = {
1594176472Skmacy		{ F_PARERRDATA, "ULP RX data parity error", -1, 1 },
1595176472Skmacy		{ F_PARERRPCMD, "ULP RX command parity error", -1, 1 },
1596176472Skmacy		{ F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1 },
1597176472Skmacy		{ F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1 },
1598176472Skmacy		{ F_ARBFPERR, "ULP RX ArbF parity error", -1, 1 },
1599176472Skmacy		{ F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1 },
1600176472Skmacy		{ F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1 },
1601176472Skmacy		{ F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1 },
1602167514Skmacy		{ 0 }
1603167514Skmacy        };
1604167514Skmacy
1605167514Skmacy	if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
1606167514Skmacy				  ulprx_intr_info, NULL))
1607167514Skmacy		t3_fatal_err(adapter);
1608167514Skmacy}
1609167514Skmacy
1610167514Skmacy/*
1611167514Skmacy * ULP TX interrupt handler.
1612167514Skmacy */
1613167514Skmacystatic void ulptx_intr_handler(adapter_t *adapter)
1614167514Skmacy{
1615167514Skmacy	static struct intr_info ulptx_intr_info[] = {
1616167514Skmacy		{ F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
1617167514Skmacy		  STAT_ULP_CH0_PBL_OOB, 0 },
1618167514Skmacy		{ F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
1619167514Skmacy		  STAT_ULP_CH1_PBL_OOB, 0 },
1620176472Skmacy		{ 0xfc, "ULP TX parity error", -1, 1 },
1621167514Skmacy		{ 0 }
1622167514Skmacy        };
1623167514Skmacy
1624167514Skmacy	if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
1625167514Skmacy				  ulptx_intr_info, adapter->irq_stats))
1626167514Skmacy		t3_fatal_err(adapter);
1627167514Skmacy}
1628167514Skmacy
1629167514Skmacy#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
1630167514Skmacy	F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
1631167514Skmacy	F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
1632167514Skmacy	F_ICSPI1_TX_FRAMING_ERROR)
1633167514Skmacy#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
1634167514Skmacy	F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
1635167514Skmacy	F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
1636167514Skmacy	F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
1637167514Skmacy
1638167514Skmacy/*
1639167514Skmacy * PM TX interrupt handler.
1640167514Skmacy */
1641167514Skmacystatic void pmtx_intr_handler(adapter_t *adapter)
1642167514Skmacy{
1643167514Skmacy	static struct intr_info pmtx_intr_info[] = {
1644167514Skmacy		{ F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
1645167514Skmacy		{ ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1 },
1646167514Skmacy		{ OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1 },
1647167514Skmacy		{ V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
1648167514Skmacy		  "PMTX ispi parity error", -1, 1 },
1649167514Skmacy		{ V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
1650167514Skmacy		  "PMTX ospi parity error", -1, 1 },
1651167514Skmacy		{ 0 }
1652167514Skmacy        };
1653167514Skmacy
1654167514Skmacy	if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
1655167514Skmacy				  pmtx_intr_info, NULL))
1656167514Skmacy		t3_fatal_err(adapter);
1657167514Skmacy}
1658167514Skmacy
1659167514Skmacy#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
1660167514Skmacy	F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
1661167514Skmacy	F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
1662167514Skmacy	F_IESPI1_TX_FRAMING_ERROR)
1663167514Skmacy#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
1664167514Skmacy	F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
1665167514Skmacy	F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
1666167514Skmacy	F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
1667167514Skmacy
1668167514Skmacy/*
1669167514Skmacy * PM RX interrupt handler.
1670167514Skmacy */
1671167514Skmacystatic void pmrx_intr_handler(adapter_t *adapter)
1672167514Skmacy{
1673167514Skmacy	static struct intr_info pmrx_intr_info[] = {
1674167514Skmacy		{ F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
1675167514Skmacy		{ IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1 },
1676167514Skmacy		{ OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1 },
1677167514Skmacy		{ V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
1678167514Skmacy		  "PMRX ispi parity error", -1, 1 },
1679167514Skmacy		{ V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
1680167514Skmacy		  "PMRX ospi parity error", -1, 1 },
1681167514Skmacy		{ 0 }
1682167514Skmacy        };
1683167514Skmacy
1684167514Skmacy	if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
1685167514Skmacy				  pmrx_intr_info, NULL))
1686167514Skmacy		t3_fatal_err(adapter);
1687167514Skmacy}
1688167514Skmacy
1689167514Skmacy/*
1690167514Skmacy * CPL switch interrupt handler.
1691167514Skmacy */
1692167514Skmacystatic void cplsw_intr_handler(adapter_t *adapter)
1693167514Skmacy{
1694167514Skmacy	static struct intr_info cplsw_intr_info[] = {
1695176472Skmacy		{ F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1 },
1696176472Skmacy		{ F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1 },
1697167514Skmacy		{ F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1 },
1698167514Skmacy		{ F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1 },
1699167514Skmacy		{ F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1 },
1700167514Skmacy		{ F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1 },
1701167514Skmacy		{ 0 }
1702167514Skmacy        };
1703167514Skmacy
1704167514Skmacy	if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
1705167514Skmacy				  cplsw_intr_info, NULL))
1706167514Skmacy		t3_fatal_err(adapter);
1707167514Skmacy}
1708167514Skmacy
1709167514Skmacy/*
1710167514Skmacy * MPS interrupt handler.
1711167514Skmacy */
1712167514Skmacystatic void mps_intr_handler(adapter_t *adapter)
1713167514Skmacy{
1714167514Skmacy	static struct intr_info mps_intr_info[] = {
1715167514Skmacy		{ 0x1ff, "MPS parity error", -1, 1 },
1716167514Skmacy		{ 0 }
1717167514Skmacy	};
1718167514Skmacy
1719167514Skmacy	if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
1720167514Skmacy				  mps_intr_info, NULL))
1721167514Skmacy		t3_fatal_err(adapter);
1722167514Skmacy}
1723167514Skmacy
1724167514Skmacy#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
1725167514Skmacy
1726167514Skmacy/*
1727167514Skmacy * MC7 interrupt handler.
1728167514Skmacy */
1729167514Skmacystatic void mc7_intr_handler(struct mc7 *mc7)
1730167514Skmacy{
1731167514Skmacy	adapter_t *adapter = mc7->adapter;
1732167514Skmacy	u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
1733167514Skmacy
1734167514Skmacy	if (cause & F_CE) {
1735167514Skmacy		mc7->stats.corr_err++;
1736167514Skmacy		CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
1737167514Skmacy			"data 0x%x 0x%x 0x%x\n", mc7->name,
1738167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
1739167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
1740167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
1741167514Skmacy			t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
1742167514Skmacy	}
1743167514Skmacy
1744167514Skmacy	if (cause & F_UE) {
1745167514Skmacy		mc7->stats.uncorr_err++;
1746167514Skmacy		CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
1747167514Skmacy			 "data 0x%x 0x%x 0x%x\n", mc7->name,
1748167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
1749167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
1750167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
1751167514Skmacy			 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
1752167514Skmacy	}
1753167514Skmacy
1754167514Skmacy	if (G_PE(cause)) {
1755167514Skmacy		mc7->stats.parity_err++;
1756167514Skmacy		CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
1757167514Skmacy			 mc7->name, G_PE(cause));
1758167514Skmacy	}
1759167514Skmacy
1760167514Skmacy	if (cause & F_AE) {
1761167514Skmacy		u32 addr = 0;
1762167514Skmacy
1763167514Skmacy		if (adapter->params.rev > 0)
1764167514Skmacy			addr = t3_read_reg(adapter,
1765167514Skmacy					   mc7->offset + A_MC7_ERR_ADDR);
1766167514Skmacy		mc7->stats.addr_err++;
1767167514Skmacy		CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
1768167514Skmacy			 mc7->name, addr);
1769167514Skmacy	}
1770167514Skmacy
1771167514Skmacy	if (cause & MC7_INTR_FATAL)
1772167514Skmacy		t3_fatal_err(adapter);
1773167514Skmacy
1774167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
1775167514Skmacy}
1776167514Skmacy
1777167514Skmacy#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1778167514Skmacy			V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
1779167514Skmacy/*
1780167514Skmacy * XGMAC interrupt handler.
1781167514Skmacy */
1782167514Skmacystatic int mac_intr_handler(adapter_t *adap, unsigned int idx)
1783167514Skmacy{
1784170654Skmacy	u32 cause;
1785170654Skmacy	struct cmac *mac;
1786167514Skmacy
1787170654Skmacy	idx = idx == 0 ? 0 : adapter_info(adap)->nports0; /* MAC idx -> port */
1788170654Skmacy	mac = &adap2pinfo(adap, idx)->mac;
1789170654Skmacy	cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
1790170654Skmacy
1791167514Skmacy	if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
1792167514Skmacy		mac->stats.tx_fifo_parity_err++;
1793167514Skmacy		CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
1794167514Skmacy	}
1795167514Skmacy	if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
1796167514Skmacy		mac->stats.rx_fifo_parity_err++;
1797167514Skmacy		CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
1798167514Skmacy	}
1799167514Skmacy	if (cause & F_TXFIFO_UNDERRUN)
1800167514Skmacy		mac->stats.tx_fifo_urun++;
1801167514Skmacy	if (cause & F_RXFIFO_OVERFLOW)
1802167514Skmacy		mac->stats.rx_fifo_ovfl++;
1803167514Skmacy	if (cause & V_SERDES_LOS(M_SERDES_LOS))
1804167514Skmacy		mac->stats.serdes_signal_loss++;
1805167514Skmacy	if (cause & F_XAUIPCSCTCERR)
1806167514Skmacy		mac->stats.xaui_pcs_ctc_err++;
1807167514Skmacy	if (cause & F_XAUIPCSALIGNCHANGE)
1808167514Skmacy		mac->stats.xaui_pcs_align_change++;
1809167514Skmacy
1810167514Skmacy	t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
1811167514Skmacy	if (cause & XGM_INTR_FATAL)
1812167514Skmacy		t3_fatal_err(adap);
1813167514Skmacy	return cause != 0;
1814167514Skmacy}
1815167514Skmacy
1816167514Skmacy/*
1817167514Skmacy * Interrupt handler for PHY events.
1818167514Skmacy */
1819167514Skmacyint t3_phy_intr_handler(adapter_t *adapter)
1820167514Skmacy{
1821167514Skmacy	u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
1822167514Skmacy
1823167514Skmacy	for_each_port(adapter, i) {
1824170654Skmacy		struct port_info *p = adap2pinfo(adapter, i);
1825167514Skmacy
1826176472Skmacy		if (!(p->phy.caps & SUPPORTED_IRQ))
1827167514Skmacy			continue;
1828167514Skmacy
1829180583Skmacy		if (cause & (1 << adapter_info(adapter)->gpio_intr[i])) {
1830167514Skmacy			int phy_cause = p->phy.ops->intr_handler(&p->phy);
1831167514Skmacy
1832167514Skmacy			if (phy_cause & cphy_cause_link_change)
1833167514Skmacy				t3_link_changed(adapter, i);
1834167514Skmacy			if (phy_cause & cphy_cause_fifo_error)
1835167514Skmacy				p->phy.fifo_errors++;
1836181614Skmacy			if (phy_cause & cphy_cause_module_change)
1837181614Skmacy				t3_os_phymod_changed(adapter, i);
1838167514Skmacy		}
1839167514Skmacy	}
1840167514Skmacy
1841167514Skmacy	t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
1842167514Skmacy	return 0;
1843167514Skmacy}
1844167514Skmacy
1845172096Skmacy/**
1846172096Skmacy *	t3_slow_intr_handler - control path interrupt handler
1847172096Skmacy *	@adapter: the adapter
1848172096Skmacy *
1849172096Skmacy *	T3 interrupt handler for non-data interrupt events, e.g., errors.
1850172096Skmacy *	The designation 'slow' is because it involves register reads, while
1851172096Skmacy *	data interrupts typically don't involve any MMIOs.
1852167514Skmacy */
1853167514Skmacyint t3_slow_intr_handler(adapter_t *adapter)
1854167514Skmacy{
1855167514Skmacy	u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
1856167514Skmacy
1857167514Skmacy	cause &= adapter->slow_intr_mask;
1858167514Skmacy	if (!cause)
1859167514Skmacy		return 0;
1860167514Skmacy	if (cause & F_PCIM0) {
1861167514Skmacy		if (is_pcie(adapter))
1862167514Skmacy			pcie_intr_handler(adapter);
1863167514Skmacy		else
1864167514Skmacy			pci_intr_handler(adapter);
1865167514Skmacy	}
1866167514Skmacy	if (cause & F_SGE3)
1867167514Skmacy		t3_sge_err_intr_handler(adapter);
1868167514Skmacy	if (cause & F_MC7_PMRX)
1869167514Skmacy		mc7_intr_handler(&adapter->pmrx);
1870167514Skmacy	if (cause & F_MC7_PMTX)
1871167514Skmacy		mc7_intr_handler(&adapter->pmtx);
1872167514Skmacy	if (cause & F_MC7_CM)
1873167514Skmacy		mc7_intr_handler(&adapter->cm);
1874167514Skmacy	if (cause & F_CIM)
1875167514Skmacy		cim_intr_handler(adapter);
1876167514Skmacy	if (cause & F_TP1)
1877167514Skmacy		tp_intr_handler(adapter);
1878167514Skmacy	if (cause & F_ULP2_RX)
1879167514Skmacy		ulprx_intr_handler(adapter);
1880167514Skmacy	if (cause & F_ULP2_TX)
1881167514Skmacy		ulptx_intr_handler(adapter);
1882167514Skmacy	if (cause & F_PM1_RX)
1883167514Skmacy		pmrx_intr_handler(adapter);
1884167514Skmacy	if (cause & F_PM1_TX)
1885167514Skmacy		pmtx_intr_handler(adapter);
1886167514Skmacy	if (cause & F_CPL_SWITCH)
1887167514Skmacy		cplsw_intr_handler(adapter);
1888167514Skmacy	if (cause & F_MPS0)
1889167514Skmacy		mps_intr_handler(adapter);
1890167514Skmacy	if (cause & F_MC5A)
1891167514Skmacy		t3_mc5_intr_handler(&adapter->mc5);
1892167514Skmacy	if (cause & F_XGMAC0_0)
1893167514Skmacy		mac_intr_handler(adapter, 0);
1894167514Skmacy	if (cause & F_XGMAC0_1)
1895167514Skmacy		mac_intr_handler(adapter, 1);
1896167514Skmacy	if (cause & F_T3DBG)
1897167514Skmacy		t3_os_ext_intr_handler(adapter);
1898167514Skmacy
1899167514Skmacy	/* Clear the interrupts just processed. */
1900167514Skmacy	t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
1901167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
1902167514Skmacy	return 1;
1903167514Skmacy}
1904167514Skmacy
1905180583Skmacystatic unsigned int calc_gpio_intr(adapter_t *adap)
1906180583Skmacy{
1907180583Skmacy	unsigned int i, gpi_intr = 0;
1908180583Skmacy
1909180583Skmacy	for_each_port(adap, i)
1910180583Skmacy		if ((adap2pinfo(adap, i)->phy.caps & SUPPORTED_IRQ) &&
1911180583Skmacy		    adapter_info(adap)->gpio_intr[i])
1912180583Skmacy			gpi_intr |= 1 << adapter_info(adap)->gpio_intr[i];
1913180583Skmacy	return gpi_intr;
1914180583Skmacy}
1915180583Skmacy
1916167514Skmacy/**
1917167514Skmacy *	t3_intr_enable - enable interrupts
1918167514Skmacy *	@adapter: the adapter whose interrupts should be enabled
1919167514Skmacy *
1920167514Skmacy *	Enable interrupts by setting the interrupt enable registers of the
1921167514Skmacy *	various HW modules and then enabling the top-level interrupt
1922167514Skmacy *	concentrator.
1923167514Skmacy */
1924167514Skmacyvoid t3_intr_enable(adapter_t *adapter)
1925167514Skmacy{
1926167514Skmacy	static struct addr_val_pair intr_en_avp[] = {
1927167514Skmacy		{ A_MC7_INT_ENABLE, MC7_INTR_MASK },
1928167514Skmacy		{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
1929167514Skmacy			MC7_INTR_MASK },
1930167514Skmacy		{ A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
1931167514Skmacy			MC7_INTR_MASK },
1932167514Skmacy		{ A_MC5_DB_INT_ENABLE, MC5_INTR_MASK },
1933167514Skmacy		{ A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK },
1934167514Skmacy		{ A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK },
1935167514Skmacy		{ A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK },
1936167514Skmacy		{ A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK },
1937167514Skmacy		{ A_MPS_INT_ENABLE, MPS_INTR_MASK },
1938167514Skmacy	};
1939167514Skmacy
1940167514Skmacy	adapter->slow_intr_mask = PL_INTR_MASK;
1941167514Skmacy
1942167514Skmacy	t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
1943176472Skmacy	t3_write_reg(adapter, A_TP_INT_ENABLE,
1944176472Skmacy		     adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff);
1945181614Skmacy	t3_write_reg(adapter, A_SG_INT_ENABLE,
1946181614Skmacy		     adapter->params.rev >= T3_REV_C ?
1947181614Skmacy		     SGE_INTR_MASK | F_FLEMPTY : SGE_INTR_MASK);
1948167514Skmacy
1949167514Skmacy	if (adapter->params.rev > 0) {
1950167514Skmacy		t3_write_reg(adapter, A_CPL_INTR_ENABLE,
1951167514Skmacy			     CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
1952167514Skmacy		t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
1953167514Skmacy			     ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
1954167514Skmacy			     F_PBL_BOUND_ERR_CH1);
1955167514Skmacy	} else {
1956167514Skmacy		t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
1957167514Skmacy		t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
1958167514Skmacy	}
1959167514Skmacy
1960180583Skmacy	t3_write_reg(adapter, A_T3DBG_INT_ENABLE, calc_gpio_intr(adapter));
1961180583Skmacy
1962170654Skmacy	if (is_pcie(adapter))
1963167514Skmacy		t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
1964170654Skmacy	else
1965167514Skmacy		t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
1966167514Skmacy	t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
1967167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_ENABLE0);          /* flush */
1968167514Skmacy}
1969167514Skmacy
1970167514Skmacy/**
1971167514Skmacy *	t3_intr_disable - disable a card's interrupts
1972167514Skmacy *	@adapter: the adapter whose interrupts should be disabled
1973167514Skmacy *
1974167514Skmacy *	Disable interrupts.  We only disable the top-level interrupt
1975167514Skmacy *	concentrator and the SGE data interrupts.
1976167514Skmacy */
1977167514Skmacyvoid t3_intr_disable(adapter_t *adapter)
1978167514Skmacy{
1979167514Skmacy	t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
1980167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_ENABLE0);  /* flush */
1981167514Skmacy	adapter->slow_intr_mask = 0;
1982167514Skmacy}
1983167514Skmacy
1984167514Skmacy/**
1985167514Skmacy *	t3_intr_clear - clear all interrupts
1986167514Skmacy *	@adapter: the adapter whose interrupts should be cleared
1987167514Skmacy *
1988167514Skmacy *	Clears all interrupts.
1989167514Skmacy */
1990167514Skmacyvoid t3_intr_clear(adapter_t *adapter)
1991167514Skmacy{
1992167514Skmacy	static const unsigned int cause_reg_addr[] = {
1993167514Skmacy		A_SG_INT_CAUSE,
1994167514Skmacy		A_SG_RSPQ_FL_STATUS,
1995167514Skmacy		A_PCIX_INT_CAUSE,
1996167514Skmacy		A_MC7_INT_CAUSE,
1997167514Skmacy		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
1998167514Skmacy		A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
1999167514Skmacy		A_CIM_HOST_INT_CAUSE,
2000167514Skmacy		A_TP_INT_CAUSE,
2001167514Skmacy		A_MC5_DB_INT_CAUSE,
2002167514Skmacy		A_ULPRX_INT_CAUSE,
2003167514Skmacy		A_ULPTX_INT_CAUSE,
2004167514Skmacy		A_CPL_INTR_CAUSE,
2005167514Skmacy		A_PM1_TX_INT_CAUSE,
2006167514Skmacy		A_PM1_RX_INT_CAUSE,
2007167514Skmacy		A_MPS_INT_CAUSE,
2008167514Skmacy		A_T3DBG_INT_CAUSE,
2009167514Skmacy	};
2010167514Skmacy	unsigned int i;
2011167514Skmacy
2012167514Skmacy	/* Clear PHY and MAC interrupts for each port. */
2013167514Skmacy	for_each_port(adapter, i)
2014167514Skmacy		t3_port_intr_clear(adapter, i);
2015167514Skmacy
2016167514Skmacy	for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
2017167514Skmacy		t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
2018167514Skmacy
2019172096Skmacy	if (is_pcie(adapter))
2020172096Skmacy		t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
2021167514Skmacy	t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
2022167514Skmacy	(void) t3_read_reg(adapter, A_PL_INT_CAUSE0);          /* flush */
2023167514Skmacy}
2024167514Skmacy
2025167514Skmacy/**
2026167514Skmacy *	t3_port_intr_enable - enable port-specific interrupts
2027167514Skmacy *	@adapter: associated adapter
2028167514Skmacy *	@idx: index of port whose interrupts should be enabled
2029167514Skmacy *
2030167514Skmacy *	Enable port-specific (i.e., MAC and PHY) interrupts for the given
2031167514Skmacy *	adapter port.
2032167514Skmacy */
2033167514Skmacyvoid t3_port_intr_enable(adapter_t *adapter, int idx)
2034167514Skmacy{
2035170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2036170654Skmacy
2037170654Skmacy	t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, XGM_INTR_MASK);
2038170654Skmacy	pi->phy.ops->intr_enable(&pi->phy);
2039167514Skmacy}
2040167514Skmacy
2041167514Skmacy/**
2042167514Skmacy *	t3_port_intr_disable - disable port-specific interrupts
2043167514Skmacy *	@adapter: associated adapter
2044167514Skmacy *	@idx: index of port whose interrupts should be disabled
2045167514Skmacy *
2046167514Skmacy *	Disable port-specific (i.e., MAC and PHY) interrupts for the given
2047167514Skmacy *	adapter port.
2048167514Skmacy */
2049167514Skmacyvoid t3_port_intr_disable(adapter_t *adapter, int idx)
2050167514Skmacy{
2051170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2052170654Skmacy
2053170654Skmacy	t3_write_reg(adapter, A_XGM_INT_ENABLE + pi->mac.offset, 0);
2054170654Skmacy	pi->phy.ops->intr_disable(&pi->phy);
2055167514Skmacy}
2056167514Skmacy
2057167514Skmacy/**
2058167514Skmacy *	t3_port_intr_clear - clear port-specific interrupts
2059167514Skmacy *	@adapter: associated adapter
2060167514Skmacy *	@idx: index of port whose interrupts to clear
2061167514Skmacy *
2062167514Skmacy *	Clear port-specific (i.e., MAC and PHY) interrupts for the given
2063167514Skmacy *	adapter port.
2064167514Skmacy */
2065167514Skmacyvoid t3_port_intr_clear(adapter_t *adapter, int idx)
2066167514Skmacy{
2067170654Skmacy	struct port_info *pi = adap2pinfo(adapter, idx);
2068170654Skmacy
2069170654Skmacy	t3_write_reg(adapter, A_XGM_INT_CAUSE + pi->mac.offset, 0xffffffff);
2070170654Skmacy	pi->phy.ops->intr_clear(&pi->phy);
2071167514Skmacy}
2072167514Skmacy
2073172096Skmacy#define SG_CONTEXT_CMD_ATTEMPTS 100
2074172096Skmacy
2075167514Skmacy/**
2076167514Skmacy * 	t3_sge_write_context - write an SGE context
2077167514Skmacy * 	@adapter: the adapter
2078167514Skmacy * 	@id: the context id
2079167514Skmacy * 	@type: the context type
2080167514Skmacy *
2081167514Skmacy * 	Program an SGE context with the values already loaded in the
2082167514Skmacy * 	CONTEXT_DATA? registers.
2083167514Skmacy */
2084167514Skmacystatic int t3_sge_write_context(adapter_t *adapter, unsigned int id,
2085167514Skmacy				unsigned int type)
2086167514Skmacy{
2087167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
2088167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
2089167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
2090167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
2091167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2092167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
2093167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2094172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2095167514Skmacy}
2096167514Skmacy
2097176472Skmacystatic int clear_sge_ctxt(adapter_t *adap, unsigned int id, unsigned int type)
2098176472Skmacy{
2099176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0);
2100176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0);
2101176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0);
2102176472Skmacy	t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0);
2103176472Skmacy	return t3_sge_write_context(adap, id, type);
2104176472Skmacy}
2105176472Skmacy
2106167514Skmacy/**
2107167514Skmacy *	t3_sge_init_ecntxt - initialize an SGE egress context
2108167514Skmacy *	@adapter: the adapter to configure
2109167514Skmacy *	@id: the context id
2110167514Skmacy *	@gts_enable: whether to enable GTS for the context
2111167514Skmacy *	@type: the egress context type
2112167514Skmacy *	@respq: associated response queue
2113167514Skmacy *	@base_addr: base address of queue
2114167514Skmacy *	@size: number of queue entries
2115167514Skmacy *	@token: uP token
2116167514Skmacy *	@gen: initial generation value for the context
2117167514Skmacy *	@cidx: consumer pointer
2118167514Skmacy *
2119167514Skmacy *	Initialize an SGE egress context and make it ready for use.  If the
2120167514Skmacy *	platform allows concurrent context operations, the caller is
2121167514Skmacy *	responsible for appropriate locking.
2122167514Skmacy */
2123167514Skmacyint t3_sge_init_ecntxt(adapter_t *adapter, unsigned int id, int gts_enable,
2124167514Skmacy		       enum sge_context_type type, int respq, u64 base_addr,
2125167514Skmacy		       unsigned int size, unsigned int token, int gen,
2126167514Skmacy		       unsigned int cidx)
2127167514Skmacy{
2128167514Skmacy	unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
2129167514Skmacy
2130167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2131167514Skmacy		return -EINVAL;
2132167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2133167514Skmacy		return -EBUSY;
2134167514Skmacy
2135167514Skmacy	base_addr >>= 12;
2136167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
2137167514Skmacy		     V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
2138167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
2139167514Skmacy		     V_EC_BASE_LO((u32)base_addr & 0xffff));
2140167514Skmacy	base_addr >>= 16;
2141167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, (u32)base_addr);
2142167514Skmacy	base_addr >>= 32;
2143167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2144167514Skmacy		     V_EC_BASE_HI((u32)base_addr & 0xf) | V_EC_RESPQ(respq) |
2145167514Skmacy		     V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
2146167514Skmacy		     F_EC_VALID);
2147167514Skmacy	return t3_sge_write_context(adapter, id, F_EGRESS);
2148167514Skmacy}
2149167514Skmacy
2150167514Skmacy/**
2151167514Skmacy *	t3_sge_init_flcntxt - initialize an SGE free-buffer list context
2152167514Skmacy *	@adapter: the adapter to configure
2153167514Skmacy *	@id: the context id
2154167514Skmacy *	@gts_enable: whether to enable GTS for the context
2155167514Skmacy *	@base_addr: base address of queue
2156167514Skmacy *	@size: number of queue entries
2157167514Skmacy *	@bsize: size of each buffer for this queue
2158167514Skmacy *	@cong_thres: threshold to signal congestion to upstream producers
2159167514Skmacy *	@gen: initial generation value for the context
2160167514Skmacy *	@cidx: consumer pointer
2161167514Skmacy *
2162167514Skmacy *	Initialize an SGE free list context and make it ready for use.  The
2163167514Skmacy *	caller is responsible for ensuring only one context operation occurs
2164167514Skmacy *	at a time.
2165167514Skmacy */
2166167514Skmacyint t3_sge_init_flcntxt(adapter_t *adapter, unsigned int id, int gts_enable,
2167167514Skmacy			u64 base_addr, unsigned int size, unsigned int bsize,
2168167514Skmacy			unsigned int cong_thres, int gen, unsigned int cidx)
2169167514Skmacy{
2170167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2171167514Skmacy		return -EINVAL;
2172167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2173167514Skmacy		return -EBUSY;
2174167514Skmacy
2175167514Skmacy	base_addr >>= 12;
2176167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, (u32)base_addr);
2177167514Skmacy	base_addr >>= 32;
2178167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
2179167514Skmacy		     V_FL_BASE_HI((u32)base_addr) |
2180167514Skmacy		     V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
2181167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
2182167514Skmacy		     V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
2183167514Skmacy		     V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
2184167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2185167514Skmacy		     V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
2186167514Skmacy		     V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
2187167514Skmacy	return t3_sge_write_context(adapter, id, F_FREELIST);
2188167514Skmacy}
2189167514Skmacy
2190167514Skmacy/**
2191167514Skmacy *	t3_sge_init_rspcntxt - initialize an SGE response queue context
2192167514Skmacy *	@adapter: the adapter to configure
2193167514Skmacy *	@id: the context id
2194167514Skmacy *	@irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
2195167514Skmacy *	@base_addr: base address of queue
2196167514Skmacy *	@size: number of queue entries
2197167514Skmacy *	@fl_thres: threshold for selecting the normal or jumbo free list
2198167514Skmacy *	@gen: initial generation value for the context
2199167514Skmacy *	@cidx: consumer pointer
2200167514Skmacy *
2201167514Skmacy *	Initialize an SGE response queue context and make it ready for use.
2202167514Skmacy *	The caller is responsible for ensuring only one context operation
2203167514Skmacy *	occurs at a time.
2204167514Skmacy */
2205167514Skmacyint t3_sge_init_rspcntxt(adapter_t *adapter, unsigned int id, int irq_vec_idx,
2206167514Skmacy			 u64 base_addr, unsigned int size,
2207167514Skmacy			 unsigned int fl_thres, int gen, unsigned int cidx)
2208167514Skmacy{
2209167514Skmacy	unsigned int intr = 0;
2210167514Skmacy
2211167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2212167514Skmacy		return -EINVAL;
2213167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2214167514Skmacy		return -EBUSY;
2215167514Skmacy
2216167514Skmacy	base_addr >>= 12;
2217167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
2218167514Skmacy		     V_CQ_INDEX(cidx));
2219167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr);
2220167514Skmacy	base_addr >>= 32;
2221167514Skmacy	if (irq_vec_idx >= 0)
2222167514Skmacy		intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
2223167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2224167514Skmacy		     V_CQ_BASE_HI((u32)base_addr) | intr | V_RQ_GEN(gen));
2225167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
2226167514Skmacy	return t3_sge_write_context(adapter, id, F_RESPONSEQ);
2227167514Skmacy}
2228167514Skmacy
2229167514Skmacy/**
2230167514Skmacy *	t3_sge_init_cqcntxt - initialize an SGE completion queue context
2231167514Skmacy *	@adapter: the adapter to configure
2232167514Skmacy *	@id: the context id
2233167514Skmacy *	@base_addr: base address of queue
2234167514Skmacy *	@size: number of queue entries
2235167514Skmacy *	@rspq: response queue for async notifications
2236167514Skmacy *	@ovfl_mode: CQ overflow mode
2237167514Skmacy *	@credits: completion queue credits
2238167514Skmacy *	@credit_thres: the credit threshold
2239167514Skmacy *
2240167514Skmacy *	Initialize an SGE completion queue context and make it ready for use.
2241167514Skmacy *	The caller is responsible for ensuring only one context operation
2242167514Skmacy *	occurs at a time.
2243167514Skmacy */
2244167514Skmacyint t3_sge_init_cqcntxt(adapter_t *adapter, unsigned int id, u64 base_addr,
2245167514Skmacy			unsigned int size, int rspq, int ovfl_mode,
2246167514Skmacy			unsigned int credits, unsigned int credit_thres)
2247167514Skmacy{
2248167514Skmacy	if (base_addr & 0xfff)     /* must be 4K aligned */
2249167514Skmacy		return -EINVAL;
2250167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2251167514Skmacy		return -EBUSY;
2252167514Skmacy
2253167514Skmacy	base_addr >>= 12;
2254167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
2255167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA1, (u32)base_addr);
2256167514Skmacy	base_addr >>= 32;
2257167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2258167514Skmacy		     V_CQ_BASE_HI((u32)base_addr) | V_CQ_RSPQ(rspq) |
2259172096Skmacy		     V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
2260172096Skmacy		     V_CQ_ERR(ovfl_mode));
2261167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
2262167514Skmacy		     V_CQ_CREDIT_THRES(credit_thres));
2263167514Skmacy	return t3_sge_write_context(adapter, id, F_CQ);
2264167514Skmacy}
2265167514Skmacy
2266167514Skmacy/**
2267167514Skmacy *	t3_sge_enable_ecntxt - enable/disable an SGE egress context
2268167514Skmacy *	@adapter: the adapter
2269167514Skmacy *	@id: the egress context id
2270167514Skmacy *	@enable: enable (1) or disable (0) the context
2271167514Skmacy *
2272167514Skmacy *	Enable or disable an SGE egress context.  The caller is responsible for
2273167514Skmacy *	ensuring only one context operation occurs at a time.
2274167514Skmacy */
2275167514Skmacyint t3_sge_enable_ecntxt(adapter_t *adapter, unsigned int id, int enable)
2276167514Skmacy{
2277167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2278167514Skmacy		return -EBUSY;
2279167514Skmacy
2280167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2281167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2282167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2283167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
2284167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
2285167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2286167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
2287167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2288172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2289167514Skmacy}
2290167514Skmacy
2291167514Skmacy/**
2292167514Skmacy *	t3_sge_disable_fl - disable an SGE free-buffer list
2293167514Skmacy *	@adapter: the adapter
2294167514Skmacy *	@id: the free list context id
2295167514Skmacy *
2296167514Skmacy *	Disable an SGE free-buffer list.  The caller is responsible for
2297167514Skmacy *	ensuring only one context operation occurs at a time.
2298167514Skmacy */
2299167514Skmacyint t3_sge_disable_fl(adapter_t *adapter, unsigned int id)
2300167514Skmacy{
2301167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2302167514Skmacy		return -EBUSY;
2303167514Skmacy
2304167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2305167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2306167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
2307167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2308167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
2309167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2310167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
2311167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2312172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2313167514Skmacy}
2314167514Skmacy
2315167514Skmacy/**
2316167514Skmacy *	t3_sge_disable_rspcntxt - disable an SGE response queue
2317167514Skmacy *	@adapter: the adapter
2318167514Skmacy *	@id: the response queue context id
2319167514Skmacy *
2320167514Skmacy *	Disable an SGE response queue.  The caller is responsible for
2321167514Skmacy *	ensuring only one context operation occurs at a time.
2322167514Skmacy */
2323167514Skmacyint t3_sge_disable_rspcntxt(adapter_t *adapter, unsigned int id)
2324167514Skmacy{
2325167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2326167514Skmacy		return -EBUSY;
2327167514Skmacy
2328167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2329167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2330167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2331167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2332167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2333167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2334167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
2335167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2336172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2337167514Skmacy}
2338167514Skmacy
2339167514Skmacy/**
2340167514Skmacy *	t3_sge_disable_cqcntxt - disable an SGE completion queue
2341167514Skmacy *	@adapter: the adapter
2342167514Skmacy *	@id: the completion queue context id
2343167514Skmacy *
2344167514Skmacy *	Disable an SGE completion queue.  The caller is responsible for
2345167514Skmacy *	ensuring only one context operation occurs at a time.
2346167514Skmacy */
2347167514Skmacyint t3_sge_disable_cqcntxt(adapter_t *adapter, unsigned int id)
2348167514Skmacy{
2349167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2350167514Skmacy		return -EBUSY;
2351167514Skmacy
2352167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2353167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2354167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2355167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2356167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2357167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2358167514Skmacy		     V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
2359167514Skmacy	return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2360172096Skmacy			       0, SG_CONTEXT_CMD_ATTEMPTS, 1);
2361167514Skmacy}
2362167514Skmacy
2363167514Skmacy/**
2364167514Skmacy *	t3_sge_cqcntxt_op - perform an operation on a completion queue context
2365167514Skmacy *	@adapter: the adapter
2366167514Skmacy *	@id: the context id
2367167514Skmacy *	@op: the operation to perform
2368172096Skmacy *	@credits: credits to return to the CQ
2369167514Skmacy *
2370167514Skmacy *	Perform the selected operation on an SGE completion queue context.
2371167514Skmacy *	The caller is responsible for ensuring only one context operation
2372167514Skmacy *	occurs at a time.
2373172096Skmacy *
2374172096Skmacy *	For most operations the function returns the current HW position in
2375172096Skmacy *	the completion queue.
2376167514Skmacy */
2377167514Skmacyint t3_sge_cqcntxt_op(adapter_t *adapter, unsigned int id, unsigned int op,
2378167514Skmacy		      unsigned int credits)
2379167514Skmacy{
2380167514Skmacy	u32 val;
2381167514Skmacy
2382167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2383167514Skmacy		return -EBUSY;
2384167514Skmacy
2385167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
2386167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
2387167514Skmacy		     V_CONTEXT(id) | F_CQ);
2388167514Skmacy	if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
2389172096Skmacy				0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
2390167514Skmacy		return -EIO;
2391167514Skmacy
2392167514Skmacy	if (op >= 2 && op < 7) {
2393167514Skmacy		if (adapter->params.rev > 0)
2394167514Skmacy			return G_CQ_INDEX(val);
2395167514Skmacy
2396167514Skmacy		t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2397167514Skmacy			     V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
2398167514Skmacy		if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
2399172096Skmacy				    F_CONTEXT_CMD_BUSY, 0,
2400172096Skmacy				    SG_CONTEXT_CMD_ATTEMPTS, 1))
2401167514Skmacy			return -EIO;
2402167514Skmacy		return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
2403167514Skmacy	}
2404167514Skmacy	return 0;
2405167514Skmacy}
2406167514Skmacy
2407167514Skmacy/**
2408167514Skmacy * 	t3_sge_read_context - read an SGE context
2409167514Skmacy * 	@type: the context type
2410167514Skmacy * 	@adapter: the adapter
2411167514Skmacy * 	@id: the context id
2412167514Skmacy * 	@data: holds the retrieved context
2413167514Skmacy *
2414167514Skmacy * 	Read an SGE egress context.  The caller is responsible for ensuring
2415167514Skmacy * 	only one context operation occurs at a time.
2416167514Skmacy */
2417167514Skmacystatic int t3_sge_read_context(unsigned int type, adapter_t *adapter,
2418167514Skmacy			       unsigned int id, u32 data[4])
2419167514Skmacy{
2420167514Skmacy	if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2421167514Skmacy		return -EBUSY;
2422167514Skmacy
2423167514Skmacy	t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2424167514Skmacy		     V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
2425167514Skmacy	if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
2426172096Skmacy			    SG_CONTEXT_CMD_ATTEMPTS, 1))
2427167514Skmacy		return -EIO;
2428167514Skmacy	data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
2429167514Skmacy	data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
2430167514Skmacy	data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
2431167514Skmacy	data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
2432167514Skmacy	return 0;
2433167514Skmacy}
2434167514Skmacy
2435167514Skmacy/**
2436167514Skmacy * 	t3_sge_read_ecntxt - read an SGE egress context
2437167514Skmacy * 	@adapter: the adapter
2438167514Skmacy * 	@id: the context id
2439167514Skmacy * 	@data: holds the retrieved context
2440167514Skmacy *
2441167514Skmacy * 	Read an SGE egress context.  The caller is responsible for ensuring
2442167514Skmacy * 	only one context operation occurs at a time.
2443167514Skmacy */
2444167514Skmacyint t3_sge_read_ecntxt(adapter_t *adapter, unsigned int id, u32 data[4])
2445167514Skmacy{
2446167514Skmacy	if (id >= 65536)
2447167514Skmacy		return -EINVAL;
2448167514Skmacy	return t3_sge_read_context(F_EGRESS, adapter, id, data);
2449167514Skmacy}
2450167514Skmacy
2451167514Skmacy/**
2452167514Skmacy * 	t3_sge_read_cq - read an SGE CQ context
2453167514Skmacy * 	@adapter: the adapter
2454167514Skmacy * 	@id: the context id
2455167514Skmacy * 	@data: holds the retrieved context
2456167514Skmacy *
2457167514Skmacy * 	Read an SGE CQ context.  The caller is responsible for ensuring
2458167514Skmacy * 	only one context operation occurs at a time.
2459167514Skmacy */
2460167514Skmacyint t3_sge_read_cq(adapter_t *adapter, unsigned int id, u32 data[4])
2461167514Skmacy{
2462167514Skmacy	if (id >= 65536)
2463167514Skmacy		return -EINVAL;
2464167514Skmacy	return t3_sge_read_context(F_CQ, adapter, id, data);
2465167514Skmacy}
2466167514Skmacy
2467167514Skmacy/**
2468167514Skmacy * 	t3_sge_read_fl - read an SGE free-list context
2469167514Skmacy * 	@adapter: the adapter
2470167514Skmacy * 	@id: the context id
2471167514Skmacy * 	@data: holds the retrieved context
2472167514Skmacy *
2473167514Skmacy * 	Read an SGE free-list context.  The caller is responsible for ensuring
2474167514Skmacy * 	only one context operation occurs at a time.
2475167514Skmacy */
2476167514Skmacyint t3_sge_read_fl(adapter_t *adapter, unsigned int id, u32 data[4])
2477167514Skmacy{
2478167514Skmacy	if (id >= SGE_QSETS * 2)
2479167514Skmacy		return -EINVAL;
2480167514Skmacy	return t3_sge_read_context(F_FREELIST, adapter, id, data);
2481167514Skmacy}
2482167514Skmacy
2483167514Skmacy/**
2484167514Skmacy * 	t3_sge_read_rspq - read an SGE response queue context
2485167514Skmacy * 	@adapter: the adapter
2486167514Skmacy * 	@id: the context id
2487167514Skmacy * 	@data: holds the retrieved context
2488167514Skmacy *
2489167514Skmacy * 	Read an SGE response queue context.  The caller is responsible for
2490167514Skmacy * 	ensuring only one context operation occurs at a time.
2491167514Skmacy */
2492167514Skmacyint t3_sge_read_rspq(adapter_t *adapter, unsigned int id, u32 data[4])
2493167514Skmacy{
2494167514Skmacy	if (id >= SGE_QSETS)
2495167514Skmacy		return -EINVAL;
2496167514Skmacy	return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
2497167514Skmacy}
2498167514Skmacy
2499167514Skmacy/**
2500167514Skmacy *	t3_config_rss - configure Rx packet steering
2501167514Skmacy *	@adapter: the adapter
2502167514Skmacy *	@rss_config: RSS settings (written to TP_RSS_CONFIG)
2503167514Skmacy *	@cpus: values for the CPU lookup table (0xff terminated)
2504167514Skmacy *	@rspq: values for the response queue lookup table (0xffff terminated)
2505167514Skmacy *
2506167514Skmacy *	Programs the receive packet steering logic.  @cpus and @rspq provide
2507167514Skmacy *	the values for the CPU and response queue lookup tables.  If they
2508167514Skmacy *	provide fewer values than the size of the tables the supplied values
2509167514Skmacy *	are used repeatedly until the tables are fully populated.
2510167514Skmacy */
2511167514Skmacyvoid t3_config_rss(adapter_t *adapter, unsigned int rss_config, const u8 *cpus,
2512167514Skmacy		   const u16 *rspq)
2513167514Skmacy{
2514167514Skmacy	int i, j, cpu_idx = 0, q_idx = 0;
2515167514Skmacy
2516167514Skmacy	if (cpus)
2517167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2518167514Skmacy			u32 val = i << 16;
2519167514Skmacy
2520167514Skmacy			for (j = 0; j < 2; ++j) {
2521167514Skmacy				val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
2522167514Skmacy				if (cpus[cpu_idx] == 0xff)
2523167514Skmacy					cpu_idx = 0;
2524167514Skmacy			}
2525167514Skmacy			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
2526167514Skmacy		}
2527167514Skmacy
2528167514Skmacy	if (rspq)
2529167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2530167514Skmacy			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
2531167514Skmacy				     (i << 16) | rspq[q_idx++]);
2532167514Skmacy			if (rspq[q_idx] == 0xffff)
2533167514Skmacy				q_idx = 0;
2534167514Skmacy		}
2535167514Skmacy
2536167514Skmacy	t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
2537167514Skmacy}
2538167514Skmacy
2539167514Skmacy/**
2540167514Skmacy *	t3_read_rss - read the contents of the RSS tables
2541167514Skmacy *	@adapter: the adapter
2542167514Skmacy *	@lkup: holds the contents of the RSS lookup table
2543167514Skmacy *	@map: holds the contents of the RSS map table
2544167514Skmacy *
2545167514Skmacy *	Reads the contents of the receive packet steering tables.
2546167514Skmacy */
2547167514Skmacyint t3_read_rss(adapter_t *adapter, u8 *lkup, u16 *map)
2548167514Skmacy{
2549167514Skmacy	int i;
2550167514Skmacy	u32 val;
2551167514Skmacy
2552167514Skmacy	if (lkup)
2553167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2554167514Skmacy			t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
2555167514Skmacy				     0xffff0000 | i);
2556167514Skmacy			val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
2557167514Skmacy			if (!(val & 0x80000000))
2558167514Skmacy				return -EAGAIN;
2559167514Skmacy			*lkup++ = (u8)val;
2560167514Skmacy			*lkup++ = (u8)(val >> 8);
2561167514Skmacy		}
2562167514Skmacy
2563167514Skmacy	if (map)
2564167514Skmacy		for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2565167514Skmacy			t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
2566167514Skmacy				     0xffff0000 | i);
2567167514Skmacy			val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
2568167514Skmacy			if (!(val & 0x80000000))
2569167514Skmacy				return -EAGAIN;
2570167514Skmacy			*map++ = (u16)val;
2571167514Skmacy		}
2572167514Skmacy	return 0;
2573167514Skmacy}
2574167514Skmacy
2575167514Skmacy/**
2576167514Skmacy *	t3_tp_set_offload_mode - put TP in NIC/offload mode
2577167514Skmacy *	@adap: the adapter
2578167514Skmacy *	@enable: 1 to select offload mode, 0 for regular NIC
2579167514Skmacy *
2580167514Skmacy *	Switches TP to NIC/offload mode.
2581167514Skmacy */
2582167514Skmacyvoid t3_tp_set_offload_mode(adapter_t *adap, int enable)
2583167514Skmacy{
2584167514Skmacy	if (is_offload(adap) || !enable)
2585167514Skmacy		t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
2586167514Skmacy				 V_NICMODE(!enable));
2587167514Skmacy}
2588167514Skmacy
2589172096Skmacy/**
2590172096Skmacy *	tp_wr_bits_indirect - set/clear bits in an indirect TP register
2591172096Skmacy *	@adap: the adapter
2592172096Skmacy *	@addr: the indirect TP register address
2593172096Skmacy *	@mask: specifies the field within the register to modify
2594172096Skmacy *	@val: new value for the field
2595172096Skmacy *
2596172096Skmacy *	Sets a field of an indirect TP register to the given value.
2597172096Skmacy */
2598171471Skmacystatic void tp_wr_bits_indirect(adapter_t *adap, unsigned int addr,
2599171471Skmacy				unsigned int mask, unsigned int val)
2600171471Skmacy{
2601171471Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
2602171471Skmacy	val |= t3_read_reg(adap, A_TP_PIO_DATA) & ~mask;
2603171471Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, val);
2604171471Skmacy}
2605171471Skmacy
2606167514Skmacy/**
2607180583Skmacy *	t3_enable_filters - enable the HW filters
2608180583Skmacy *	@adap: the adapter
2609180583Skmacy *
2610180583Skmacy *	Enables the HW filters for NIC traffic.
2611180583Skmacy */
2612180583Skmacyvoid t3_enable_filters(adapter_t *adap)
2613180583Skmacy{
2614180583Skmacy	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE, 0);
2615180583Skmacy	t3_set_reg_field(adap, A_MC5_DB_CONFIG, 0, F_FILTEREN);
2616180583Skmacy	t3_set_reg_field(adap, A_TP_GLOBAL_CONFIG, 0, V_FIVETUPLELOOKUP(3));
2617180583Skmacy	tp_wr_bits_indirect(adap, A_TP_INGRESS_CONFIG, 0, F_LOOKUPEVERYPKT);
2618180583Skmacy}
2619180583Skmacy
2620180583Skmacy/**
2621167514Skmacy *	pm_num_pages - calculate the number of pages of the payload memory
2622167514Skmacy *	@mem_size: the size of the payload memory
2623167514Skmacy *	@pg_size: the size of each payload memory page
2624167514Skmacy *
2625167514Skmacy *	Calculate the number of pages, each of the given size, that fit in a
2626167514Skmacy *	memory of the specified size, respecting the HW requirement that the
2627167514Skmacy *	number of pages must be a multiple of 24.
2628167514Skmacy */
2629167514Skmacystatic inline unsigned int pm_num_pages(unsigned int mem_size,
2630167514Skmacy					unsigned int pg_size)
2631167514Skmacy{
2632167514Skmacy	unsigned int n = mem_size / pg_size;
2633167514Skmacy
2634167514Skmacy	return n - n % 24;
2635167514Skmacy}
2636167514Skmacy
2637167514Skmacy#define mem_region(adap, start, size, reg) \
2638167514Skmacy	t3_write_reg((adap), A_ ## reg, (start)); \
2639167514Skmacy	start += size
2640167514Skmacy
2641172096Skmacy/**
2642167514Skmacy *	partition_mem - partition memory and configure TP memory settings
2643167514Skmacy *	@adap: the adapter
2644167514Skmacy *	@p: the TP parameters
2645167514Skmacy *
2646167514Skmacy *	Partitions context and payload memory and configures TP's memory
2647167514Skmacy *	registers.
2648167514Skmacy */
2649167514Skmacystatic void partition_mem(adapter_t *adap, const struct tp_params *p)
2650167514Skmacy{
2651167514Skmacy	unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
2652167514Skmacy	unsigned int timers = 0, timers_shift = 22;
2653167514Skmacy
2654167514Skmacy	if (adap->params.rev > 0) {
2655167514Skmacy		if (tids <= 16 * 1024) {
2656167514Skmacy			timers = 1;
2657167514Skmacy			timers_shift = 16;
2658167514Skmacy		} else if (tids <= 64 * 1024) {
2659167514Skmacy			timers = 2;
2660167514Skmacy			timers_shift = 18;
2661167514Skmacy		} else if (tids <= 256 * 1024) {
2662167514Skmacy			timers = 3;
2663167514Skmacy			timers_shift = 20;
2664167514Skmacy		}
2665167514Skmacy	}
2666167514Skmacy
2667167514Skmacy	t3_write_reg(adap, A_TP_PMM_SIZE,
2668167514Skmacy		     p->chan_rx_size | (p->chan_tx_size >> 16));
2669167514Skmacy
2670167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
2671167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
2672167514Skmacy	t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
2673167514Skmacy	t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
2674167514Skmacy			 V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
2675167514Skmacy
2676167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
2677167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
2678167514Skmacy	t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
2679167514Skmacy
2680167514Skmacy	pstructs = p->rx_num_pgs + p->tx_num_pgs;
2681167514Skmacy	/* Add a bit of headroom and make multiple of 24 */
2682167514Skmacy	pstructs += 48;
2683167514Skmacy	pstructs -= pstructs % 24;
2684167514Skmacy	t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
2685167514Skmacy
2686167514Skmacy	m = tids * TCB_SIZE;
2687167514Skmacy	mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
2688167514Skmacy	mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
2689167514Skmacy	t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
2690167514Skmacy	m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
2691167514Skmacy	mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
2692167514Skmacy	mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
2693167514Skmacy	mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
2694167514Skmacy	mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
2695167514Skmacy
2696167514Skmacy	m = (m + 4095) & ~0xfff;
2697167514Skmacy	t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
2698167514Skmacy	t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
2699167514Skmacy
2700167514Skmacy	tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
2701167514Skmacy	m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
2702167514Skmacy	    adap->params.mc5.nfilters - adap->params.mc5.nroutes;
2703167514Skmacy	if (tids < m)
2704167514Skmacy		adap->params.mc5.nservers += m - tids;
2705167514Skmacy}
2706167514Skmacy
2707167514Skmacystatic inline void tp_wr_indirect(adapter_t *adap, unsigned int addr, u32 val)
2708167514Skmacy{
2709167514Skmacy	t3_write_reg(adap, A_TP_PIO_ADDR, addr);
2710167514Skmacy	t3_write_reg(adap, A_TP_PIO_DATA, val);
2711167514Skmacy}
2712167514Skmacy
2713167514Skmacystatic void tp_config(adapter_t *adap, const struct tp_params *p)
2714167514Skmacy{
2715167514Skmacy	t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
2716167514Skmacy		     F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
2717167514Skmacy		     F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
2718167514Skmacy	t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
2719167514Skmacy		     F_MTUENABLE | V_WINDOWSCALEMODE(1) |
2720180583Skmacy		     V_TIMESTAMPSMODE(1) | V_SACKMODE(1) | V_SACKRX(1));
2721167514Skmacy	t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
2722167514Skmacy		     V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
2723180583Skmacy		     V_BYTETHRESHOLD(26880) | V_MSSTHRESHOLD(2) |
2724167514Skmacy		     F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
2725176472Skmacy	t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO,
2726167514Skmacy			 F_IPV6ENABLE | F_NICMODE);
2727167514Skmacy	t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
2728167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
2729170654Skmacy	t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
2730170654Skmacy			 adap->params.rev > 0 ? F_ENABLEESND :
2731170654Skmacy			 			F_T3A_ENABLEESND);
2732167514Skmacy	t3_set_reg_field(adap, A_TP_PC_CONFIG,
2733170654Skmacy			 F_ENABLEEPCMDAFULL,
2734170654Skmacy			 F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
2735170654Skmacy			 F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
2736176472Skmacy	t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL,
2737176472Skmacy			 F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN |
2738176472Skmacy			 F_ENABLEARPMISS | F_DISBLEDAPARBIT0);
2739170654Skmacy	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
2740170654Skmacy	t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
2741167514Skmacy
2742167514Skmacy	if (adap->params.rev > 0) {
2743167514Skmacy		tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
2744171471Skmacy		t3_set_reg_field(adap, A_TP_PARA_REG3, 0,
2745171471Skmacy				 F_TXPACEAUTO | F_TXPACEAUTOSTRICT);
2746167514Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
2747171471Skmacy		tp_wr_indirect(adap, A_TP_VLAN_PRI_MAP, 0xfa50);
2748171471Skmacy		tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP0, 0xfac688);
2749171471Skmacy		tp_wr_indirect(adap, A_TP_MAC_MATCH_MAP1, 0xfac688);
2750167514Skmacy	} else
2751167514Skmacy		t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
2752167514Skmacy
2753176472Skmacy	if (adap->params.rev == T3_REV_C)
2754176472Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG,
2755176472Skmacy				 V_TABLELATENCYDELTA(M_TABLELATENCYDELTA),
2756176472Skmacy				 V_TABLELATENCYDELTA(4));
2757176472Skmacy
2758167746Skmacy	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
2759167746Skmacy	t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
2760167746Skmacy	t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
2761170654Skmacy	t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
2762170654Skmacy
2763170654Skmacy	if (adap->params.nports > 2) {
2764170654Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG2, 0,
2765180583Skmacy				 F_ENABLETXPORTFROMDA2 | F_ENABLETXPORTFROMDA |
2766180583Skmacy				 F_ENABLERXPORTFROMADDR);
2767170654Skmacy		tp_wr_bits_indirect(adap, A_TP_QOS_RX_MAP_MODE,
2768170654Skmacy				    V_RXMAPMODE(M_RXMAPMODE), 0);
2769170654Skmacy		tp_wr_indirect(adap, A_TP_INGRESS_CONFIG, V_BITPOS0(48) |
2770170654Skmacy			       V_BITPOS1(49) | V_BITPOS2(50) | V_BITPOS3(51) |
2771170654Skmacy			       F_ENABLEEXTRACT | F_ENABLEEXTRACTIONSFD |
2772170654Skmacy			       F_ENABLEINSERTION | F_ENABLEINSERTIONSFD);
2773170654Skmacy		tp_wr_indirect(adap, A_TP_PREAMBLE_MSB, 0xfb000000);
2774170654Skmacy		tp_wr_indirect(adap, A_TP_PREAMBLE_LSB, 0xd5);
2775170654Skmacy		tp_wr_indirect(adap, A_TP_INTF_FROM_TX_PKT, F_INTFFROMTXPKT);
2776170654Skmacy	}
2777167514Skmacy}
2778167514Skmacy
2779167514Skmacy/* TCP timer values in ms */
2780167514Skmacy#define TP_DACK_TIMER 50
2781167514Skmacy#define TP_RTO_MIN    250
2782167514Skmacy
2783167514Skmacy/**
2784167514Skmacy *	tp_set_timers - set TP timing parameters
2785167514Skmacy *	@adap: the adapter to set
2786167514Skmacy *	@core_clk: the core clock frequency in Hz
2787167514Skmacy *
2788167514Skmacy *	Set TP's timing parameters, such as the various timer resolutions and
2789167514Skmacy *	the TCP timer values.
2790167514Skmacy */
2791167514Skmacystatic void tp_set_timers(adapter_t *adap, unsigned int core_clk)
2792167514Skmacy{
2793170654Skmacy	unsigned int tre = adap->params.tp.tre;
2794167746Skmacy	unsigned int dack_re = adap->params.tp.dack_re;
2795167514Skmacy	unsigned int tstamp_re = fls(core_clk / 1000);     /* 1ms, at least */
2796167514Skmacy	unsigned int tps = core_clk >> tre;
2797167514Skmacy
2798167514Skmacy	t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
2799167514Skmacy		     V_DELAYEDACKRESOLUTION(dack_re) |
2800167514Skmacy		     V_TIMESTAMPRESOLUTION(tstamp_re));
2801167514Skmacy	t3_write_reg(adap, A_TP_DACK_TIMER,
2802167514Skmacy		     (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
2803167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
2804167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
2805167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
2806167514Skmacy	t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
2807167514Skmacy	t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
2808167514Skmacy		     V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
2809167514Skmacy		     V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
2810167514Skmacy		     V_KEEPALIVEMAX(9));
2811167514Skmacy
2812167514Skmacy#define SECONDS * tps
2813167514Skmacy
2814167514Skmacy	t3_write_reg(adap, A_TP_MSL,
2815167514Skmacy		     adap->params.rev > 0 ? 0 : 2 SECONDS);
2816167514Skmacy	t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
2817167514Skmacy	t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
2818167514Skmacy	t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
2819167514Skmacy	t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
2820167514Skmacy	t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
2821167514Skmacy	t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
2822167514Skmacy	t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
2823167514Skmacy	t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
2824167514Skmacy
2825167514Skmacy#undef SECONDS
2826167514Skmacy}
2827167514Skmacy
2828167514Skmacy#ifdef CONFIG_CHELSIO_T3_CORE
2829167514Skmacy/**
2830167514Skmacy *	t3_tp_set_coalescing_size - set receive coalescing size
2831167514Skmacy *	@adap: the adapter
2832167514Skmacy *	@size: the receive coalescing size
2833167514Skmacy *	@psh: whether a set PSH bit should deliver coalesced data
2834167514Skmacy *
2835167514Skmacy *	Set the receive coalescing size and PSH bit handling.
2836167514Skmacy */
2837167514Skmacyint t3_tp_set_coalescing_size(adapter_t *adap, unsigned int size, int psh)
2838167514Skmacy{
2839167514Skmacy	u32 val;
2840167514Skmacy
2841167514Skmacy	if (size > MAX_RX_COALESCING_LEN)
2842167514Skmacy		return -EINVAL;
2843167514Skmacy
2844167514Skmacy	val = t3_read_reg(adap, A_TP_PARA_REG3);
2845167514Skmacy	val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
2846167514Skmacy
2847167514Skmacy	if (size) {
2848167514Skmacy		val |= F_RXCOALESCEENABLE;
2849167514Skmacy		if (psh)
2850167514Skmacy			val |= F_RXCOALESCEPSHEN;
2851170654Skmacy		size = min(MAX_RX_COALESCING_LEN, size);
2852167514Skmacy		t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
2853167514Skmacy			     V_MAXRXDATA(MAX_RX_COALESCING_LEN));
2854167514Skmacy	}
2855167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG3, val);
2856167514Skmacy	return 0;
2857167514Skmacy}
2858167514Skmacy
2859167514Skmacy/**
2860167514Skmacy *	t3_tp_set_max_rxsize - set the max receive size
2861167514Skmacy *	@adap: the adapter
2862167514Skmacy *	@size: the max receive size
2863167514Skmacy *
2864167514Skmacy *	Set TP's max receive size.  This is the limit that applies when
2865167514Skmacy *	receive coalescing is disabled.
2866167514Skmacy */
2867167514Skmacyvoid t3_tp_set_max_rxsize(adapter_t *adap, unsigned int size)
2868167514Skmacy{
2869167514Skmacy	t3_write_reg(adap, A_TP_PARA_REG7,
2870167514Skmacy		     V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
2871167514Skmacy}
2872167514Skmacy
2873167514Skmacystatic void __devinit init_mtus(unsigned short mtus[])
2874167514Skmacy{
2875167514Skmacy	/*
2876167514Skmacy	 * See draft-mathis-plpmtud-00.txt for the values.  The min is 88 so
2877167514Skmacy	 * it can accomodate max size TCP/IP headers when SACK and timestamps
2878167514Skmacy	 * are enabled and still have at least 8 bytes of payload.
2879167514Skmacy	 */
2880167514Skmacy	mtus[0] = 88;
2881170654Skmacy	mtus[1] = 88;
2882167746Skmacy	mtus[2] = 256;
2883167746Skmacy	mtus[3] = 512;
2884167746Skmacy	mtus[4] = 576;
2885167514Skmacy	mtus[5] = 1024;
2886167514Skmacy	mtus[6] = 1280;
2887167514Skmacy	mtus[7] = 1492;
2888167514Skmacy	mtus[8] = 1500;
2889167514Skmacy	mtus[9] = 2002;
2890167514Skmacy	mtus[10] = 2048;
2891167514Skmacy	mtus[11] = 4096;
2892167514Skmacy	mtus[12] = 4352;
2893167514Skmacy	mtus[13] = 8192;
2894167514Skmacy	mtus[14] = 9000;
2895167514Skmacy	mtus[15] = 9600;
2896167514Skmacy}
2897167514Skmacy
2898172096Skmacy/**
2899172096Skmacy *	init_cong_ctrl - initialize congestion control parameters
2900172096Skmacy *	@a: the alpha values for congestion control
2901172096Skmacy *	@b: the beta values for congestion control
2902172096Skmacy *
2903172096Skmacy *	Initialize the congestion control parameters.
2904167514Skmacy */
2905167514Skmacystatic void __devinit init_cong_ctrl(unsigned short *a, unsigned short *b)
2906167514Skmacy{
2907167514Skmacy	a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
2908167514Skmacy	a[9] = 2;
2909167514Skmacy	a[10] = 3;
2910167514Skmacy	a[11] = 4;
2911167514Skmacy	a[12] = 5;
2912167514Skmacy	a[13] = 6;
2913167514Skmacy	a[14] = 7;
2914167514Skmacy	a[15] = 8;
2915167514Skmacy	a[16] = 9;
2916167514Skmacy	a[17] = 10;
2917167514Skmacy	a[18] = 14;
2918167514Skmacy	a[19] = 17;
2919167514Skmacy	a[20] = 21;
2920167514Skmacy	a[21] = 25;
2921167514Skmacy	a[22] = 30;
2922167514Skmacy	a[23] = 35;
2923167514Skmacy	a[24] = 45;
2924167514Skmacy	a[25] = 60;
2925167514Skmacy	a[26] = 80;
2926167514Skmacy	a[27] = 100;
2927167514Skmacy	a[28] = 200;
2928167514Skmacy	a[29] = 300;
2929167514Skmacy	a[30] = 400;
2930167514Skmacy	a[31] = 500;
2931167514Skmacy
2932167514Skmacy	b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
2933167514Skmacy	b[9] = b[10] = 1;
2934167514Skmacy	b[11] = b[12] = 2;
2935167514Skmacy	b[13] = b[14] = b[15] = b[16] = 3;
2936167514Skmacy	b[17] = b[18] = b[19] = b[20] = b[21] = 4;
2937167514Skmacy	b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
2938167514Skmacy	b[28] = b[29] = 6;
2939167514Skmacy	b[30] = b[31] = 7;
2940167514Skmacy}
2941167514Skmacy
2942167514Skmacy/* The minimum additive increment value for the congestion control table */
2943167514Skmacy#define CC_MIN_INCR 2U
2944167514Skmacy
2945167514Skmacy/**
2946167514Skmacy *	t3_load_mtus - write the MTU and congestion control HW tables
2947167514Skmacy *	@adap: the adapter
2948167514Skmacy *	@mtus: the unrestricted values for the MTU table
2949172096Skmacy *	@alpha: the values for the congestion control alpha parameter
2950167514Skmacy *	@beta: the values for the congestion control beta parameter
2951167514Skmacy *	@mtu_cap: the maximum permitted effective MTU
2952167514Skmacy *
2953167514Skmacy *	Write the MTU table with the supplied MTUs capping each at &mtu_cap.
2954167514Skmacy *	Update the high-speed congestion control table with the supplied alpha,
2955167514Skmacy * 	beta, and MTUs.
2956167514Skmacy */
2957167514Skmacyvoid t3_load_mtus(adapter_t *adap, unsigned short mtus[NMTUS],
2958167514Skmacy		  unsigned short alpha[NCCTRL_WIN],
2959167514Skmacy		  unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
2960167514Skmacy{
2961167514Skmacy	static const unsigned int avg_pkts[NCCTRL_WIN] = {
2962167514Skmacy		2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
2963167514Skmacy		896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
2964167514Skmacy		28672, 40960, 57344, 81920, 114688, 163840, 229376 };
2965167514Skmacy
2966167514Skmacy	unsigned int i, w;
2967167514Skmacy
2968167514Skmacy	for (i = 0; i < NMTUS; ++i) {
2969167514Skmacy		unsigned int mtu = min(mtus[i], mtu_cap);
2970167514Skmacy		unsigned int log2 = fls(mtu);
2971167514Skmacy
2972167514Skmacy		if (!(mtu & ((1 << log2) >> 2)))     /* round */
2973167514Skmacy			log2--;
2974167514Skmacy		t3_write_reg(adap, A_TP_MTU_TABLE,
2975167514Skmacy			     (i << 24) | (log2 << 16) | mtu);
2976167514Skmacy
2977167514Skmacy		for (w = 0; w < NCCTRL_WIN; ++w) {
2978167514Skmacy			unsigned int inc;
2979167514Skmacy
2980167514Skmacy			inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
2981167514Skmacy				  CC_MIN_INCR);
2982167514Skmacy
2983167514Skmacy			t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
2984167514Skmacy				     (w << 16) | (beta[w] << 13) | inc);
2985167514Skmacy		}
2986167514Skmacy	}
2987167514Skmacy}
2988167514Skmacy
2989167514Skmacy/**
2990167514Skmacy *	t3_read_hw_mtus - returns the values in the HW MTU table
2991167514Skmacy *	@adap: the adapter
2992167514Skmacy *	@mtus: where to store the HW MTU values
2993167514Skmacy *
2994167514Skmacy *	Reads the HW MTU table.
2995167514Skmacy */
2996167514Skmacyvoid t3_read_hw_mtus(adapter_t *adap, unsigned short mtus[NMTUS])
2997167514Skmacy{
2998167514Skmacy	int i;
2999167514Skmacy
3000167514Skmacy	for (i = 0; i < NMTUS; ++i) {
3001167514Skmacy		unsigned int val;
3002167514Skmacy
3003167514Skmacy		t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
3004167514Skmacy		val = t3_read_reg(adap, A_TP_MTU_TABLE);
3005167514Skmacy		mtus[i] = val & 0x3fff;
3006167514Skmacy	}
3007167514Skmacy}
3008167514Skmacy
3009167514Skmacy/**
3010167514Skmacy *	t3_get_cong_cntl_tab - reads the congestion control table
3011167514Skmacy *	@adap: the adapter
3012167514Skmacy *	@incr: where to store the alpha values
3013167514Skmacy *
3014167514Skmacy *	Reads the additive increments programmed into the HW congestion
3015167514Skmacy *	control table.
3016167514Skmacy */
3017167514Skmacyvoid t3_get_cong_cntl_tab(adapter_t *adap,
3018167514Skmacy			  unsigned short incr[NMTUS][NCCTRL_WIN])
3019167514Skmacy{
3020167514Skmacy	unsigned int mtu, w;
3021167514Skmacy
3022167514Skmacy	for (mtu = 0; mtu < NMTUS; ++mtu)
3023167514Skmacy		for (w = 0; w < NCCTRL_WIN; ++w) {
3024167514Skmacy			t3_write_reg(adap, A_TP_CCTRL_TABLE,
3025167514Skmacy				     0xffff0000 | (mtu << 5) | w);
3026167514Skmacy			incr[mtu][w] = (unsigned short)t3_read_reg(adap,
3027167514Skmacy				        A_TP_CCTRL_TABLE) & 0x1fff;
3028167514Skmacy		}
3029167514Skmacy}
3030167514Skmacy
3031167514Skmacy/**
3032167514Skmacy *	t3_tp_get_mib_stats - read TP's MIB counters
3033167514Skmacy *	@adap: the adapter
3034167514Skmacy *	@tps: holds the returned counter values
3035167514Skmacy *
3036167514Skmacy *	Returns the values of TP's MIB counters.
3037167514Skmacy */
3038167514Skmacyvoid t3_tp_get_mib_stats(adapter_t *adap, struct tp_mib_stats *tps)
3039167514Skmacy{
3040167514Skmacy	t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *)tps,
3041167514Skmacy			 sizeof(*tps) / sizeof(u32), 0);
3042167514Skmacy}
3043167514Skmacy
3044167746Skmacy/**
3045167746Skmacy *	t3_read_pace_tbl - read the pace table
3046167746Skmacy *	@adap: the adapter
3047167746Skmacy *	@pace_vals: holds the returned values
3048167746Skmacy *
3049167746Skmacy *	Returns the values of TP's pace table in nanoseconds.
3050167746Skmacy */
3051167746Skmacyvoid t3_read_pace_tbl(adapter_t *adap, unsigned int pace_vals[NTX_SCHED])
3052167746Skmacy{
3053167746Skmacy	unsigned int i, tick_ns = dack_ticks_to_usec(adap, 1000);
3054167746Skmacy
3055167746Skmacy	for (i = 0; i < NTX_SCHED; i++) {
3056167746Skmacy		t3_write_reg(adap, A_TP_PACE_TABLE, 0xffff0000 + i);
3057167746Skmacy		pace_vals[i] = t3_read_reg(adap, A_TP_PACE_TABLE) * tick_ns;
3058167746Skmacy	}
3059167746Skmacy}
3060167746Skmacy
3061167746Skmacy/**
3062167746Skmacy *	t3_set_pace_tbl - set the pace table
3063167746Skmacy *	@adap: the adapter
3064167746Skmacy *	@pace_vals: the pace values in nanoseconds
3065167746Skmacy *	@start: index of the first entry in the HW pace table to set
3066167746Skmacy *	@n: how many entries to set
3067167746Skmacy *
3068167746Skmacy *	Sets (a subset of the) HW pace table.
3069167746Skmacy */
3070167746Skmacyvoid t3_set_pace_tbl(adapter_t *adap, unsigned int *pace_vals,
3071167746Skmacy		     unsigned int start, unsigned int n)
3072167746Skmacy{
3073167746Skmacy	unsigned int tick_ns = dack_ticks_to_usec(adap, 1000);
3074167746Skmacy
3075167746Skmacy	for ( ; n; n--, start++, pace_vals++)
3076167746Skmacy		t3_write_reg(adap, A_TP_PACE_TABLE, (start << 16) |
3077167746Skmacy			     ((*pace_vals + tick_ns / 2) / tick_ns));
3078167746Skmacy}
3079167746Skmacy
3080167514Skmacy#define ulp_region(adap, name, start, len) \
3081167514Skmacy	t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
3082167514Skmacy	t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
3083167514Skmacy		     (start) + (len) - 1); \
3084167514Skmacy	start += len
3085167514Skmacy
3086167514Skmacy#define ulptx_region(adap, name, start, len) \
3087167514Skmacy	t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
3088167514Skmacy	t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
3089167514Skmacy		     (start) + (len) - 1)
3090167514Skmacy
3091167514Skmacystatic void ulp_config(adapter_t *adap, const struct tp_params *p)
3092167514Skmacy{
3093167514Skmacy	unsigned int m = p->chan_rx_size;
3094167514Skmacy
3095167514Skmacy	ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
3096167514Skmacy	ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
3097167514Skmacy	ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
3098167514Skmacy	ulp_region(adap, STAG, m, p->chan_rx_size / 4);
3099167514Skmacy	ulp_region(adap, RQ, m, p->chan_rx_size / 4);
3100167514Skmacy	ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
3101167514Skmacy	ulp_region(adap, PBL, m, p->chan_rx_size / 4);
3102167514Skmacy	t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
3103167514Skmacy}
3104170654Skmacy
3105170654Skmacy
3106170654Skmacy/**
3107170654Skmacy *	t3_set_proto_sram - set the contents of the protocol sram
3108170654Skmacy *	@adapter: the adapter
3109170654Skmacy *	@data: the protocol image
3110170654Skmacy *
3111170654Skmacy *	Write the contents of the protocol SRAM.
3112170654Skmacy */
3113171471Skmacyint t3_set_proto_sram(adapter_t *adap, const u8 *data)
3114170654Skmacy{
3115170654Skmacy	int i;
3116172096Skmacy	const u32 *buf = (const u32 *)data;
3117170654Skmacy
3118170654Skmacy	for (i = 0; i < PROTO_SRAM_LINES; i++) {
3119171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, cpu_to_be32(*buf++));
3120171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, cpu_to_be32(*buf++));
3121171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, cpu_to_be32(*buf++));
3122171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, cpu_to_be32(*buf++));
3123171471Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, cpu_to_be32(*buf++));
3124170654Skmacy
3125170654Skmacy		t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
3126170654Skmacy		if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
3127170654Skmacy			return -EIO;
3128170654Skmacy	}
3129170654Skmacy	return 0;
3130170654Skmacy}
3131167514Skmacy#endif
3132167514Skmacy
3133172096Skmacy/**
3134172096Skmacy *	t3_config_trace_filter - configure one of the tracing filters
3135172096Skmacy *	@adapter: the adapter
3136172096Skmacy *	@tp: the desired trace filter parameters
3137172096Skmacy *	@filter_index: which filter to configure
3138172096Skmacy *	@invert: if set non-matching packets are traced instead of matching ones
3139172096Skmacy *	@enable: whether to enable or disable the filter
3140172096Skmacy *
3141172096Skmacy *	Configures one of the tracing filters available in HW.
3142172096Skmacy */
3143167514Skmacyvoid t3_config_trace_filter(adapter_t *adapter, const struct trace_params *tp,
3144167514Skmacy			    int filter_index, int invert, int enable)
3145167514Skmacy{
3146167514Skmacy	u32 addr, key[4], mask[4];
3147167514Skmacy
3148167514Skmacy	key[0] = tp->sport | (tp->sip << 16);
3149167514Skmacy	key[1] = (tp->sip >> 16) | (tp->dport << 16);
3150167514Skmacy	key[2] = tp->dip;
3151167514Skmacy	key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
3152167514Skmacy
3153167514Skmacy	mask[0] = tp->sport_mask | (tp->sip_mask << 16);
3154167514Skmacy	mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
3155167514Skmacy	mask[2] = tp->dip_mask;
3156167514Skmacy	mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
3157167514Skmacy
3158167514Skmacy	if (invert)
3159167514Skmacy		key[3] |= (1 << 29);
3160167514Skmacy	if (enable)
3161167514Skmacy		key[3] |= (1 << 28);
3162167514Skmacy
3163167514Skmacy	addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
3164167514Skmacy	tp_wr_indirect(adapter, addr++, key[0]);
3165167514Skmacy	tp_wr_indirect(adapter, addr++, mask[0]);
3166167514Skmacy	tp_wr_indirect(adapter, addr++, key[1]);
3167167514Skmacy	tp_wr_indirect(adapter, addr++, mask[1]);
3168167514Skmacy	tp_wr_indirect(adapter, addr++, key[2]);
3169167514Skmacy	tp_wr_indirect(adapter, addr++, mask[2]);
3170167514Skmacy	tp_wr_indirect(adapter, addr++, key[3]);
3171167514Skmacy	tp_wr_indirect(adapter, addr,   mask[3]);
3172167514Skmacy	(void) t3_read_reg(adapter, A_TP_PIO_DATA);
3173167514Skmacy}
3174167514Skmacy
3175167514Skmacy/**
3176167514Skmacy *	t3_config_sched - configure a HW traffic scheduler
3177167514Skmacy *	@adap: the adapter
3178167514Skmacy *	@kbps: target rate in Kbps
3179167514Skmacy *	@sched: the scheduler index
3180167514Skmacy *
3181167746Skmacy *	Configure a Tx HW scheduler for the target rate.
3182167514Skmacy */
3183167514Skmacyint t3_config_sched(adapter_t *adap, unsigned int kbps, int sched)
3184167514Skmacy{
3185167514Skmacy	unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
3186167514Skmacy	unsigned int clk = adap->params.vpd.cclk * 1000;
3187167514Skmacy	unsigned int selected_cpt = 0, selected_bpt = 0;
3188167514Skmacy
3189167514Skmacy	if (kbps > 0) {
3190167514Skmacy		kbps *= 125;     /* -> bytes */
3191167514Skmacy		for (cpt = 1; cpt <= 255; cpt++) {
3192167514Skmacy			tps = clk / cpt;
3193167514Skmacy			bpt = (kbps + tps / 2) / tps;
3194167514Skmacy			if (bpt > 0 && bpt <= 255) {
3195167514Skmacy				v = bpt * tps;
3196167514Skmacy				delta = v >= kbps ? v - kbps : kbps - v;
3197176472Skmacy				if (delta < mindelta) {
3198167514Skmacy					mindelta = delta;
3199167514Skmacy					selected_cpt = cpt;
3200167514Skmacy					selected_bpt = bpt;
3201167514Skmacy				}
3202167514Skmacy			} else if (selected_cpt)
3203167514Skmacy				break;
3204167514Skmacy		}
3205167514Skmacy		if (!selected_cpt)
3206167514Skmacy			return -EINVAL;
3207167514Skmacy	}
3208167514Skmacy	t3_write_reg(adap, A_TP_TM_PIO_ADDR,
3209167514Skmacy		     A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
3210167514Skmacy	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3211167514Skmacy	if (sched & 1)
3212167514Skmacy		v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
3213167514Skmacy	else
3214167514Skmacy		v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
3215167514Skmacy	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
3216167514Skmacy	return 0;
3217167514Skmacy}
3218167514Skmacy
3219167746Skmacy/**
3220167746Skmacy *	t3_set_sched_ipg - set the IPG for a Tx HW packet rate scheduler
3221167746Skmacy *	@adap: the adapter
3222167746Skmacy *	@sched: the scheduler index
3223167746Skmacy *	@ipg: the interpacket delay in tenths of nanoseconds
3224167746Skmacy *
3225167746Skmacy *	Set the interpacket delay for a HW packet rate scheduler.
3226167746Skmacy */
3227167746Skmacyint t3_set_sched_ipg(adapter_t *adap, int sched, unsigned int ipg)
3228167746Skmacy{
3229167746Skmacy	unsigned int v, addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3230167746Skmacy
3231167746Skmacy	/* convert ipg to nearest number of core clocks */
3232167746Skmacy	ipg *= core_ticks_per_usec(adap);
3233167746Skmacy	ipg = (ipg + 5000) / 10000;
3234167746Skmacy	if (ipg > 0xffff)
3235167746Skmacy		return -EINVAL;
3236167746Skmacy
3237167746Skmacy	t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3238167746Skmacy	v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3239167746Skmacy	if (sched & 1)
3240167746Skmacy		v = (v & 0xffff) | (ipg << 16);
3241167746Skmacy	else
3242167746Skmacy		v = (v & 0xffff0000) | ipg;
3243167746Skmacy	t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
3244167746Skmacy	t3_read_reg(adap, A_TP_TM_PIO_DATA);
3245167746Skmacy	return 0;
3246167746Skmacy}
3247167746Skmacy
3248167746Skmacy/**
3249167746Skmacy *	t3_get_tx_sched - get the configuration of a Tx HW traffic scheduler
3250167746Skmacy *	@adap: the adapter
3251167746Skmacy *	@sched: the scheduler index
3252167746Skmacy *	@kbps: the byte rate in Kbps
3253167746Skmacy *	@ipg: the interpacket delay in tenths of nanoseconds
3254167746Skmacy *
3255167746Skmacy *	Return the current configuration of a HW Tx scheduler.
3256167746Skmacy */
3257167746Skmacyvoid t3_get_tx_sched(adapter_t *adap, unsigned int sched, unsigned int *kbps,
3258167746Skmacy		     unsigned int *ipg)
3259167746Skmacy{
3260167746Skmacy	unsigned int v, addr, bpt, cpt;
3261167746Skmacy
3262167746Skmacy	if (kbps) {
3263167746Skmacy		addr = A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2;
3264167746Skmacy		t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3265167746Skmacy		v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3266167746Skmacy		if (sched & 1)
3267167746Skmacy			v >>= 16;
3268167746Skmacy		bpt = (v >> 8) & 0xff;
3269167746Skmacy		cpt = v & 0xff;
3270167746Skmacy		if (!cpt)
3271167746Skmacy			*kbps = 0;        /* scheduler disabled */
3272167746Skmacy		else {
3273167746Skmacy			v = (adap->params.vpd.cclk * 1000) / cpt;
3274167746Skmacy			*kbps = (v * bpt) / 125;
3275167746Skmacy		}
3276167746Skmacy	}
3277167746Skmacy	if (ipg) {
3278167746Skmacy		addr = A_TP_TX_MOD_Q1_Q0_TIMER_SEPARATOR - sched / 2;
3279167746Skmacy		t3_write_reg(adap, A_TP_TM_PIO_ADDR, addr);
3280167746Skmacy		v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
3281167746Skmacy		if (sched & 1)
3282167746Skmacy			v >>= 16;
3283167746Skmacy		v &= 0xffff;
3284167746Skmacy		*ipg = (10000 * v) / core_ticks_per_usec(adap);
3285167746Skmacy	}
3286167746Skmacy}
3287167746Skmacy
3288172096Skmacy/**
3289172096Skmacy *	tp_init - configure TP
3290172096Skmacy *	@adap: the adapter
3291172096Skmacy *	@p: TP configuration parameters
3292172096Skmacy *
3293172096Skmacy *	Initializes the TP HW module.
3294172096Skmacy */
3295167514Skmacystatic int tp_init(adapter_t *adap, const struct tp_params *p)
3296167514Skmacy{
3297167514Skmacy	int busy = 0;
3298167514Skmacy
3299167514Skmacy	tp_config(adap, p);
3300167514Skmacy	t3_set_vlan_accel(adap, 3, 0);
3301167514Skmacy
3302167514Skmacy	if (is_offload(adap)) {
3303167514Skmacy		tp_set_timers(adap, adap->params.vpd.cclk * 1000);
3304167514Skmacy		t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
3305167514Skmacy		busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
3306167514Skmacy				       0, 1000, 5);
3307167514Skmacy		if (busy)
3308167514Skmacy			CH_ERR(adap, "TP initialization timed out\n");
3309167514Skmacy	}
3310167514Skmacy
3311167514Skmacy	if (!busy)
3312167514Skmacy		t3_write_reg(adap, A_TP_RESET, F_TPRESET);
3313167514Skmacy	return busy;
3314167514Skmacy}
3315167514Skmacy
3316172096Skmacy/**
3317172096Skmacy *	t3_mps_set_active_ports - configure port failover
3318172096Skmacy *	@adap: the adapter
3319172096Skmacy *	@port_mask: bitmap of active ports
3320172096Skmacy *
3321172096Skmacy *	Sets the active ports according to the supplied bitmap.
3322172096Skmacy */
3323167514Skmacyint t3_mps_set_active_ports(adapter_t *adap, unsigned int port_mask)
3324167514Skmacy{
3325167514Skmacy	if (port_mask & ~((1 << adap->params.nports) - 1))
3326167514Skmacy		return -EINVAL;
3327167514Skmacy	t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
3328167514Skmacy			 port_mask << S_PORT0ACTIVE);
3329167514Skmacy	return 0;
3330167514Skmacy}
3331167514Skmacy
3332172096Skmacy/**
3333172096Skmacy * 	chan_init_hw - channel-dependent HW initialization
3334172096Skmacy *	@adap: the adapter
3335172096Skmacy *	@chan_map: bitmap of Tx channels being used
3336172096Skmacy *
3337172096Skmacy *	Perform the bits of HW initialization that are dependent on the Tx
3338172096Skmacy *	channels being used.
3339167514Skmacy */
3340170654Skmacystatic void chan_init_hw(adapter_t *adap, unsigned int chan_map)
3341167514Skmacy{
3342167514Skmacy	int i;
3343167514Skmacy
3344170654Skmacy	if (chan_map != 3) {                                 /* one channel */
3345167514Skmacy		t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
3346167514Skmacy		t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
3347170654Skmacy		t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_ENFORCEPKT |
3348170654Skmacy			     (chan_map == 1 ? F_TPTXPORT0EN | F_PORT0ACTIVE :
3349170654Skmacy					      F_TPTXPORT1EN | F_PORT1ACTIVE));
3350170654Skmacy		t3_write_reg(adap, A_PM1_TX_CFG,
3351170654Skmacy			     chan_map == 1 ? 0xffffffff : 0);
3352172096Skmacy		if (chan_map == 2)
3353172096Skmacy			t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3354172096Skmacy				     V_TX_MOD_QUEUE_REQ_MAP(0xff));
3355172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xd9c8);
3356172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfbea);
3357170654Skmacy	} else {                                             /* two channels */
3358167514Skmacy		t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
3359167514Skmacy		t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
3360167514Skmacy		t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
3361167514Skmacy			     V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
3362167514Skmacy		t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
3363167514Skmacy			     F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
3364167514Skmacy			     F_ENFORCEPKT);
3365167514Skmacy		t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
3366167514Skmacy		t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
3367167514Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3368167514Skmacy			     V_TX_MOD_QUEUE_REQ_MAP(0xaa));
3369167514Skmacy		for (i = 0; i < 16; i++)
3370167514Skmacy			t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
3371167514Skmacy				     (i << 16) | 0x1010);
3372172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (12 << 16) | 0xba98);
3373172096Skmacy		t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE, (13 << 16) | 0xfedc);
3374167514Skmacy	}
3375167514Skmacy}
3376167514Skmacy
3377167514Skmacystatic int calibrate_xgm(adapter_t *adapter)
3378167514Skmacy{
3379167514Skmacy	if (uses_xaui(adapter)) {
3380167514Skmacy		unsigned int v, i;
3381167514Skmacy
3382167514Skmacy		for (i = 0; i < 5; ++i) {
3383167514Skmacy			t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
3384167514Skmacy			(void) t3_read_reg(adapter, A_XGM_XAUI_IMP);
3385171471Skmacy			msleep(1);
3386167514Skmacy			v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
3387167514Skmacy			if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
3388167514Skmacy				t3_write_reg(adapter, A_XGM_XAUI_IMP,
3389167514Skmacy					     V_XAUIIMP(G_CALIMP(v) >> 2));
3390167514Skmacy				return 0;
3391167514Skmacy			}
3392167514Skmacy		}
3393167514Skmacy		CH_ERR(adapter, "MAC calibration failed\n");
3394167514Skmacy		return -1;
3395167514Skmacy	} else {
3396167514Skmacy		t3_write_reg(adapter, A_XGM_RGMII_IMP,
3397167514Skmacy			     V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3398167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3399167514Skmacy				 F_XGM_IMPSETUPDATE);
3400167514Skmacy	}
3401167514Skmacy	return 0;
3402167514Skmacy}
3403167514Skmacy
3404167514Skmacystatic void calibrate_xgm_t3b(adapter_t *adapter)
3405167514Skmacy{
3406167514Skmacy	if (!uses_xaui(adapter)) {
3407167514Skmacy		t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
3408167514Skmacy			     F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3409167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
3410167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
3411167514Skmacy				 F_XGM_IMPSETUPDATE);
3412167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3413167514Skmacy				 0);
3414167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
3415167514Skmacy		t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
3416167514Skmacy	}
3417167514Skmacy}
3418167514Skmacy
3419167514Skmacystruct mc7_timing_params {
3420167514Skmacy	unsigned char ActToPreDly;
3421167514Skmacy	unsigned char ActToRdWrDly;
3422167514Skmacy	unsigned char PreCyc;
3423167514Skmacy	unsigned char RefCyc[5];
3424167514Skmacy	unsigned char BkCyc;
3425167514Skmacy	unsigned char WrToRdDly;
3426167514Skmacy	unsigned char RdToWrDly;
3427167514Skmacy};
3428167514Skmacy
3429167514Skmacy/*
3430167514Skmacy * Write a value to a register and check that the write completed.  These
3431167514Skmacy * writes normally complete in a cycle or two, so one read should suffice.
3432167514Skmacy * The very first read exists to flush the posted write to the device.
3433167514Skmacy */
3434167514Skmacystatic int wrreg_wait(adapter_t *adapter, unsigned int addr, u32 val)
3435167514Skmacy{
3436167514Skmacy	t3_write_reg(adapter,	addr, val);
3437167514Skmacy	(void) t3_read_reg(adapter, addr);                   /* flush */
3438167514Skmacy	if (!(t3_read_reg(adapter, addr) & F_BUSY))
3439167514Skmacy		return 0;
3440167514Skmacy	CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
3441167514Skmacy	return -EIO;
3442167514Skmacy}
3443167514Skmacy
3444167514Skmacystatic int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
3445167514Skmacy{
3446167514Skmacy	static const unsigned int mc7_mode[] = {
3447167514Skmacy		0x632, 0x642, 0x652, 0x432, 0x442
3448167514Skmacy	};
3449167514Skmacy	static const struct mc7_timing_params mc7_timings[] = {
3450167514Skmacy		{ 12, 3, 4, { 20, 28, 34, 52, 0 }, 15, 6, 4 },
3451167514Skmacy		{ 12, 4, 5, { 20, 28, 34, 52, 0 }, 16, 7, 4 },
3452167514Skmacy		{ 12, 5, 6, { 20, 28, 34, 52, 0 }, 17, 8, 4 },
3453167514Skmacy		{ 9,  3, 4, { 15, 21, 26, 39, 0 }, 12, 6, 4 },
3454167514Skmacy		{ 9,  4, 5, { 15, 21, 26, 39, 0 }, 13, 7, 4 }
3455167514Skmacy	};
3456167514Skmacy
3457167514Skmacy	u32 val;
3458167514Skmacy	unsigned int width, density, slow, attempts;
3459167514Skmacy	adapter_t *adapter = mc7->adapter;
3460167514Skmacy	const struct mc7_timing_params *p = &mc7_timings[mem_type];
3461167514Skmacy
3462170654Skmacy	if (!mc7->size)
3463169978Skmacy		return 0;
3464170654Skmacy
3465167514Skmacy	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
3466167514Skmacy	slow = val & F_SLOW;
3467167514Skmacy	width = G_WIDTH(val);
3468167514Skmacy	density = G_DEN(val);
3469167514Skmacy
3470167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
3471167514Skmacy	val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);  /* flush */
3472171471Skmacy	msleep(1);
3473167514Skmacy
3474167514Skmacy	if (!slow) {
3475167514Skmacy		t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
3476167514Skmacy		(void) t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
3477171471Skmacy		msleep(1);
3478167514Skmacy		if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
3479167514Skmacy		    (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
3480167514Skmacy			CH_ERR(adapter, "%s MC7 calibration timed out\n",
3481167514Skmacy			       mc7->name);
3482167514Skmacy			goto out_fail;
3483167514Skmacy		}
3484167514Skmacy	}
3485167514Skmacy
3486167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
3487167514Skmacy		     V_ACTTOPREDLY(p->ActToPreDly) |
3488167514Skmacy		     V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
3489167514Skmacy		     V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
3490167514Skmacy		     V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
3491167514Skmacy
3492167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
3493167514Skmacy		     val | F_CLKEN | F_TERM150);
3494167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
3495167514Skmacy
3496167514Skmacy	if (!slow)
3497167514Skmacy		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
3498167514Skmacy				 F_DLLENB);
3499167514Skmacy	udelay(1);
3500167514Skmacy
3501167514Skmacy	val = slow ? 3 : 6;
3502167514Skmacy	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
3503167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
3504167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
3505167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
3506167514Skmacy		goto out_fail;
3507167514Skmacy
3508167514Skmacy	if (!slow) {
3509167514Skmacy		t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
3510167514Skmacy		t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL,
3511167514Skmacy				 F_DLLRST, 0);
3512167514Skmacy		udelay(5);
3513167514Skmacy	}
3514167514Skmacy
3515167514Skmacy	if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
3516167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
3517167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
3518167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
3519167514Skmacy		       mc7_mode[mem_type]) ||
3520167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
3521167514Skmacy	    wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
3522167514Skmacy		goto out_fail;
3523167514Skmacy
3524167514Skmacy	/* clock value is in KHz */
3525167514Skmacy	mc7_clock = mc7_clock * 7812 + mc7_clock / 2;  /* ns */
3526167514Skmacy	mc7_clock /= 1000000;                          /* KHz->MHz, ns->us */
3527167514Skmacy
3528167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_REF,
3529167514Skmacy		     F_PERREFEN | V_PREREFDIV(mc7_clock));
3530167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */
3531167514Skmacy
3532167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_ECC,
3533167514Skmacy		     F_ECCGENEN | F_ECCCHKEN);
3534167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
3535167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
3536167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
3537167514Skmacy		     (mc7->size << width) - 1);
3538167514Skmacy	t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
3539167514Skmacy	(void) t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */
3540167514Skmacy
3541167514Skmacy	attempts = 50;
3542167514Skmacy	do {
3543171471Skmacy		msleep(250);
3544167514Skmacy		val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
3545167514Skmacy	} while ((val & F_BUSY) && --attempts);
3546167514Skmacy	if (val & F_BUSY) {
3547167514Skmacy		CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
3548167514Skmacy		goto out_fail;
3549167514Skmacy	}
3550167514Skmacy
3551167514Skmacy	/* Enable normal memory accesses. */
3552167514Skmacy	t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
3553167514Skmacy	return 0;
3554167514Skmacy
3555167514Skmacy out_fail:
3556167514Skmacy	return -1;
3557167514Skmacy}
3558167514Skmacy
3559167514Skmacystatic void config_pcie(adapter_t *adap)
3560167514Skmacy{
3561167514Skmacy	static const u16 ack_lat[4][6] = {
3562167514Skmacy		{ 237, 416, 559, 1071, 2095, 4143 },
3563167514Skmacy		{ 128, 217, 289, 545, 1057, 2081 },
3564167514Skmacy		{ 73, 118, 154, 282, 538, 1050 },
3565167514Skmacy		{ 67, 107, 86, 150, 278, 534 }
3566167514Skmacy	};
3567167514Skmacy	static const u16 rpl_tmr[4][6] = {
3568167514Skmacy		{ 711, 1248, 1677, 3213, 6285, 12429 },
3569167514Skmacy		{ 384, 651, 867, 1635, 3171, 6243 },
3570167514Skmacy		{ 219, 354, 462, 846, 1614, 3150 },
3571167514Skmacy		{ 201, 321, 258, 450, 834, 1602 }
3572167514Skmacy	};
3573167514Skmacy
3574167514Skmacy	u16 val;
3575167514Skmacy	unsigned int log2_width, pldsize;
3576167514Skmacy	unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
3577167514Skmacy
3578167514Skmacy	t3_os_pci_read_config_2(adap,
3579167514Skmacy				adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
3580167514Skmacy				&val);
3581167514Skmacy	pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
3582167514Skmacy
3583167514Skmacy	t3_os_pci_read_config_2(adap,
3584167514Skmacy				adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
3585167514Skmacy			       	&val);
3586167514Skmacy
3587167514Skmacy	fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
3588167514Skmacy	fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
3589167514Skmacy			G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
3590167514Skmacy	log2_width = fls(adap->params.pci.width) - 1;
3591167514Skmacy	acklat = ack_lat[log2_width][pldsize];
3592167514Skmacy	if (val & 1)                            /* check LOsEnable */
3593167514Skmacy		acklat += fst_trn_tx * 4;
3594167514Skmacy	rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
3595167514Skmacy
3596167514Skmacy	if (adap->params.rev == 0)
3597167514Skmacy		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
3598167514Skmacy				 V_T3A_ACKLAT(M_T3A_ACKLAT),
3599167514Skmacy				 V_T3A_ACKLAT(acklat));
3600167514Skmacy	else
3601167514Skmacy		t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
3602167514Skmacy				 V_ACKLAT(acklat));
3603167514Skmacy
3604167514Skmacy	t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
3605167514Skmacy			 V_REPLAYLMT(rpllmt));
3606167514Skmacy
3607167514Skmacy	t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
3608176472Skmacy	t3_set_reg_field(adap, A_PCIE_CFG, 0,
3609176472Skmacy			 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
3610167514Skmacy}
3611167514Skmacy
3612172096Skmacy/**
3613172096Skmacy * 	t3_init_hw - initialize and configure T3 HW modules
3614172096Skmacy * 	@adapter: the adapter
3615172096Skmacy * 	@fw_params: initial parameters to pass to firmware (optional)
3616167514Skmacy *
3617172096Skmacy *	Initialize and configure T3 HW modules.  This performs the
3618172096Skmacy *	initialization steps that need to be done once after a card is reset.
3619172096Skmacy *	MAC and PHY initialization is handled separarely whenever a port is
3620172096Skmacy *	enabled.
3621172096Skmacy *
3622172096Skmacy *	@fw_params are passed to FW and their value is platform dependent.
3623172096Skmacy *	Only the top 8 bits are available for use, the rest must be 0.
3624167514Skmacy */
3625167514Skmacyint t3_init_hw(adapter_t *adapter, u32 fw_params)
3626167514Skmacy{
3627176472Skmacy	int err = -EIO, attempts, i;
3628167514Skmacy	const struct vpd_params *vpd = &adapter->params.vpd;
3629167514Skmacy
3630167514Skmacy	if (adapter->params.rev > 0)
3631167514Skmacy		calibrate_xgm_t3b(adapter);
3632167514Skmacy	else if (calibrate_xgm(adapter))
3633167514Skmacy		goto out_err;
3634167514Skmacy
3635171471Skmacy	if (adapter->params.nports > 2)
3636170654Skmacy		t3_mac_reset(&adap2pinfo(adapter, 0)->mac);
3637170654Skmacy
3638167514Skmacy	if (vpd->mclk) {
3639167514Skmacy		partition_mem(adapter, &adapter->params.tp);
3640167514Skmacy
3641167514Skmacy		if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
3642167514Skmacy		    mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
3643167514Skmacy		    mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
3644167514Skmacy		    t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
3645167514Skmacy			        adapter->params.mc5.nfilters,
3646167514Skmacy			       	adapter->params.mc5.nroutes))
3647167514Skmacy			goto out_err;
3648176472Skmacy
3649176472Skmacy		for (i = 0; i < 32; i++)
3650176472Skmacy			if (clear_sge_ctxt(adapter, i, F_CQ))
3651176472Skmacy				goto out_err;
3652167514Skmacy	}
3653167514Skmacy
3654167514Skmacy	if (tp_init(adapter, &adapter->params.tp))
3655167514Skmacy		goto out_err;
3656167514Skmacy
3657167514Skmacy#ifdef CONFIG_CHELSIO_T3_CORE
3658167514Skmacy	t3_tp_set_coalescing_size(adapter,
3659167514Skmacy				  min(adapter->params.sge.max_pkt_size,
3660167514Skmacy				      MAX_RX_COALESCING_LEN), 1);
3661167514Skmacy	t3_tp_set_max_rxsize(adapter,
3662167514Skmacy			     min(adapter->params.sge.max_pkt_size, 16384U));
3663167514Skmacy	ulp_config(adapter, &adapter->params.tp);
3664167514Skmacy#endif
3665167514Skmacy	if (is_pcie(adapter))
3666167514Skmacy		config_pcie(adapter);
3667167514Skmacy	else
3668176472Skmacy		t3_set_reg_field(adapter, A_PCIX_CFG, 0,
3669176472Skmacy				 F_DMASTOPEN | F_CLIDECEN);
3670167514Skmacy
3671176472Skmacy	if (adapter->params.rev == T3_REV_C)
3672176472Skmacy		t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0,
3673176472Skmacy				 F_CFG_CQE_SOP_MASK);
3674176472Skmacy
3675170654Skmacy	t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
3676172096Skmacy	t3_write_reg(adapter, A_PM1_RX_MODE, 0);
3677172096Skmacy	t3_write_reg(adapter, A_PM1_TX_MODE, 0);
3678170654Skmacy	chan_init_hw(adapter, adapter->params.chan_map);
3679167514Skmacy	t3_sge_init(adapter, &adapter->params.sge);
3680167514Skmacy
3681180583Skmacy	t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW, calc_gpio_intr(adapter));
3682180583Skmacy
3683167514Skmacy	t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
3684167514Skmacy	t3_write_reg(adapter, A_CIM_BOOT_CFG,
3685167514Skmacy		     V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
3686167514Skmacy	(void) t3_read_reg(adapter, A_CIM_BOOT_CFG);    /* flush */
3687167514Skmacy
3688176472Skmacy	attempts = 100;
3689167514Skmacy	do {                          /* wait for uP to initialize */
3690171471Skmacy		msleep(20);
3691167514Skmacy	} while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
3692169978Skmacy	if (!attempts) {
3693169978Skmacy		CH_ERR(adapter, "uP initialization timed out\n");
3694167514Skmacy		goto out_err;
3695169978Skmacy	}
3696170654Skmacy
3697167514Skmacy	err = 0;
3698167514Skmacy out_err:
3699167514Skmacy	return err;
3700167514Skmacy}
3701167514Skmacy
3702167514Skmacy/**
3703167514Skmacy *	get_pci_mode - determine a card's PCI mode
3704167514Skmacy *	@adapter: the adapter
3705167514Skmacy *	@p: where to store the PCI settings
3706167514Skmacy *
3707167514Skmacy *	Determines a card's PCI mode and associated parameters, such as speed
3708167514Skmacy *	and width.
3709167514Skmacy */
3710167514Skmacystatic void __devinit get_pci_mode(adapter_t *adapter, struct pci_params *p)
3711167514Skmacy{
3712167514Skmacy	static unsigned short speed_map[] = { 33, 66, 100, 133 };
3713167514Skmacy	u32 pci_mode, pcie_cap;
3714167514Skmacy
3715167514Skmacy	pcie_cap = t3_os_find_pci_capability(adapter, PCI_CAP_ID_EXP);
3716167514Skmacy	if (pcie_cap) {
3717167514Skmacy		u16 val;
3718167514Skmacy
3719167514Skmacy		p->variant = PCI_VARIANT_PCIE;
3720167514Skmacy		p->pcie_cap_addr = pcie_cap;
3721167514Skmacy		t3_os_pci_read_config_2(adapter, pcie_cap + PCI_EXP_LNKSTA,
3722167514Skmacy					&val);
3723167514Skmacy		p->width = (val >> 4) & 0x3f;
3724167514Skmacy		return;
3725167514Skmacy	}
3726167514Skmacy
3727167514Skmacy	pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
3728167514Skmacy	p->speed = speed_map[G_PCLKRANGE(pci_mode)];
3729167514Skmacy	p->width = (pci_mode & F_64BIT) ? 64 : 32;
3730167514Skmacy	pci_mode = G_PCIXINITPAT(pci_mode);
3731167514Skmacy	if (pci_mode == 0)
3732167514Skmacy		p->variant = PCI_VARIANT_PCI;
3733167514Skmacy	else if (pci_mode < 4)
3734167514Skmacy		p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
3735167514Skmacy	else if (pci_mode < 8)
3736167514Skmacy		p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
3737167514Skmacy	else
3738167514Skmacy		p->variant = PCI_VARIANT_PCIX_266_MODE2;
3739167514Skmacy}
3740167514Skmacy
3741167514Skmacy/**
3742167514Skmacy *	init_link_config - initialize a link's SW state
3743167514Skmacy *	@lc: structure holding the link state
3744172096Skmacy *	@caps: link capabilities
3745167514Skmacy *
3746167514Skmacy *	Initializes the SW state maintained for each link, including the link's
3747167514Skmacy *	capabilities and default speed/duplex/flow-control/autonegotiation
3748167514Skmacy *	settings.
3749167514Skmacy */
3750167514Skmacystatic void __devinit init_link_config(struct link_config *lc,
3751167514Skmacy				       unsigned int caps)
3752167514Skmacy{
3753167514Skmacy	lc->supported = caps;
3754167514Skmacy	lc->requested_speed = lc->speed = SPEED_INVALID;
3755167514Skmacy	lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
3756167514Skmacy	lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
3757167514Skmacy	if (lc->supported & SUPPORTED_Autoneg) {
3758167514Skmacy		lc->advertising = lc->supported;
3759167514Skmacy		lc->autoneg = AUTONEG_ENABLE;
3760167514Skmacy		lc->requested_fc |= PAUSE_AUTONEG;
3761167514Skmacy	} else {
3762167514Skmacy		lc->advertising = 0;
3763167514Skmacy		lc->autoneg = AUTONEG_DISABLE;
3764167514Skmacy	}
3765167514Skmacy}
3766167514Skmacy
3767167514Skmacy/**
3768167514Skmacy *	mc7_calc_size - calculate MC7 memory size
3769167514Skmacy *	@cfg: the MC7 configuration
3770167514Skmacy *
3771167514Skmacy *	Calculates the size of an MC7 memory in bytes from the value of its
3772167514Skmacy *	configuration register.
3773167514Skmacy */
3774167514Skmacystatic unsigned int __devinit mc7_calc_size(u32 cfg)
3775167514Skmacy{
3776167514Skmacy	unsigned int width = G_WIDTH(cfg);
3777167514Skmacy	unsigned int banks = !!(cfg & F_BKS) + 1;
3778167514Skmacy	unsigned int org = !!(cfg & F_ORG) + 1;
3779167514Skmacy	unsigned int density = G_DEN(cfg);
3780167514Skmacy	unsigned int MBs = ((256 << density) * banks) / (org << width);
3781167514Skmacy
3782167514Skmacy	return MBs << 20;
3783167514Skmacy}
3784167514Skmacy
3785167514Skmacystatic void __devinit mc7_prep(adapter_t *adapter, struct mc7 *mc7,
3786167514Skmacy			       unsigned int base_addr, const char *name)
3787167514Skmacy{
3788167514Skmacy	u32 cfg;
3789167514Skmacy
3790167514Skmacy	mc7->adapter = adapter;
3791167514Skmacy	mc7->name = name;
3792167514Skmacy	mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
3793167514Skmacy	cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
3794169978Skmacy	mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
3795167514Skmacy	mc7->width = G_WIDTH(cfg);
3796167514Skmacy}
3797167514Skmacy
3798167514Skmacyvoid mac_prep(struct cmac *mac, adapter_t *adapter, int index)
3799167514Skmacy{
3800167514Skmacy	mac->adapter = adapter;
3801170654Skmacy	mac->multiport = adapter->params.nports > 2;
3802170654Skmacy	if (mac->multiport) {
3803170654Skmacy		mac->ext_port = (unsigned char)index;
3804170654Skmacy		mac->nucast = 8;
3805170654Skmacy		index = 0;
3806170654Skmacy	} else
3807170654Skmacy		mac->nucast = 1;
3808170654Skmacy
3809167514Skmacy	mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
3810167514Skmacy
3811167514Skmacy	if (adapter->params.rev == 0 && uses_xaui(adapter)) {
3812167514Skmacy		t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
3813167514Skmacy			     is_10G(adapter) ? 0x2901c04 : 0x2301c04);
3814167514Skmacy		t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
3815167514Skmacy				 F_ENRGMII, 0);
3816167514Skmacy	}
3817167514Skmacy}
3818167514Skmacy
3819172096Skmacy/**
3820172096Skmacy *	early_hw_init - HW initialization done at card detection time
3821172096Skmacy *	@adapter: the adapter
3822172096Skmacy *	@ai: contains information about the adapter type and properties
3823172096Skmacy *
3824172096Skmacy *	Perfoms the part of HW initialization that is done early on when the
3825172096Skmacy *	driver first detecs the card.  Most of the HW state is initialized
3826172096Skmacy *	lazily later on when a port or an offload function are first used.
3827172096Skmacy */
3828167514Skmacyvoid early_hw_init(adapter_t *adapter, const struct adapter_info *ai)
3829167514Skmacy{
3830170654Skmacy	u32 val = V_PORTSPEED(is_10G(adapter) || adapter->params.nports > 2 ?
3831170654Skmacy			      3 : 2);
3832167514Skmacy
3833167514Skmacy	mi1_init(adapter, ai);
3834167514Skmacy	t3_write_reg(adapter, A_I2C_CFG,                  /* set for 80KHz */
3835167514Skmacy		     V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
3836167514Skmacy	t3_write_reg(adapter, A_T3DBG_GPIO_EN,
3837167514Skmacy		     ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
3838169978Skmacy	t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
3839176472Skmacy	t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff));
3840170654Skmacy
3841167514Skmacy	if (adapter->params.rev == 0 || !uses_xaui(adapter))
3842167514Skmacy		val |= F_ENRGMII;
3843167514Skmacy
3844167514Skmacy	/* Enable MAC clocks so we can access the registers */
3845167514Skmacy	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
3846167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
3847167514Skmacy
3848167514Skmacy	val |= F_CLKDIVRESET_;
3849167514Skmacy	t3_write_reg(adapter, A_XGM_PORT_CFG, val);
3850167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
3851167514Skmacy	t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
3852167514Skmacy	(void) t3_read_reg(adapter, A_XGM_PORT_CFG);
3853167514Skmacy}
3854167514Skmacy
3855172096Skmacy/**
3856172096Skmacy *	t3_reset_adapter - reset the adapter
3857172096Skmacy *	@adapter: the adapter
3858172096Skmacy *
3859172096Skmacy * 	Reset the adapter.
3860167514Skmacy */
3861170654Skmacystatic int t3_reset_adapter(adapter_t *adapter)
3862167514Skmacy{
3863170654Skmacy	int i, save_and_restore_pcie =
3864167746Skmacy	    adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
3865167746Skmacy	uint16_t devid = 0;
3866167514Skmacy
3867167746Skmacy	if (save_and_restore_pcie)
3868167514Skmacy		t3_os_pci_save_state(adapter);
3869167514Skmacy	t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
3870167514Skmacy
3871167514Skmacy 	/*
3872167514Skmacy	 * Delay. Give Some time to device to reset fully.
3873167514Skmacy	 * XXX The delay time should be modified.
3874167514Skmacy	 */
3875167514Skmacy	for (i = 0; i < 10; i++) {
3876171471Skmacy		msleep(50);
3877167514Skmacy		t3_os_pci_read_config_2(adapter, 0x00, &devid);
3878167514Skmacy		if (devid == 0x1425)
3879167514Skmacy			break;
3880167514Skmacy	}
3881167514Skmacy
3882167514Skmacy	if (devid != 0x1425)
3883167514Skmacy		return -1;
3884167514Skmacy
3885167746Skmacy	if (save_and_restore_pcie)
3886167514Skmacy		t3_os_pci_restore_state(adapter);
3887167514Skmacy	return 0;
3888167514Skmacy}
3889167514Skmacy
3890181614Skmacystatic int init_parity(adapter_t *adap)
3891176472Skmacy{
3892176472Skmacy	int i, err, addr;
3893176472Skmacy
3894176472Skmacy	if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
3895176472Skmacy		return -EBUSY;
3896176472Skmacy
3897176472Skmacy	for (err = i = 0; !err && i < 16; i++)
3898176472Skmacy		err = clear_sge_ctxt(adap, i, F_EGRESS);
3899176472Skmacy	for (i = 0xfff0; !err && i <= 0xffff; i++)
3900176472Skmacy		err = clear_sge_ctxt(adap, i, F_EGRESS);
3901176472Skmacy	for (i = 0; !err && i < SGE_QSETS; i++)
3902176472Skmacy		err = clear_sge_ctxt(adap, i, F_RESPONSEQ);
3903176472Skmacy	if (err)
3904176472Skmacy		return err;
3905176472Skmacy
3906176472Skmacy	t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0);
3907176472Skmacy	for (i = 0; i < 4; i++)
3908176472Skmacy		for (addr = 0; addr <= M_IBQDBGADDR; addr++) {
3909176472Skmacy			t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN |
3910176472Skmacy				     F_IBQDBGWR | V_IBQDBGQID(i) |
3911176472Skmacy				     V_IBQDBGADDR(addr));
3912176472Skmacy			err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG,
3913176472Skmacy					      F_IBQDBGBUSY, 0, 2, 1);
3914176472Skmacy			if (err)
3915176472Skmacy				return err;
3916176472Skmacy		}
3917176472Skmacy	return 0;
3918176472Skmacy}
3919176472Skmacy
3920172096Skmacy/**
3921172096Skmacy *	t3_prep_adapter - prepare SW and HW for operation
3922172096Skmacy *	@adapter: the adapter
3923172096Skmacy *	@ai: contains information about the adapter type and properties
3924172096Skmacy *
3925172096Skmacy *	Initialize adapter SW state for the various HW modules, set initial
3926172096Skmacy *	values for some adapter tunables, take PHYs out of reset, and
3927172096Skmacy *	initialize the MDIO interface.
3928167514Skmacy */
3929167514Skmacyint __devinit t3_prep_adapter(adapter_t *adapter,
3930167514Skmacy			      const struct adapter_info *ai, int reset)
3931167514Skmacy{
3932167514Skmacy	int ret;
3933167514Skmacy	unsigned int i, j = 0;
3934167514Skmacy
3935167514Skmacy	get_pci_mode(adapter, &adapter->params.pci);
3936167514Skmacy
3937167514Skmacy	adapter->params.info = ai;
3938170654Skmacy	adapter->params.nports = ai->nports0 + ai->nports1;
3939170654Skmacy	adapter->params.chan_map = !!ai->nports0 | (!!ai->nports1 << 1);
3940167514Skmacy	adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
3941167514Skmacy	adapter->params.linkpoll_period = 0;
3942171471Skmacy	if (adapter->params.nports > 2)
3943171471Skmacy		adapter->params.stats_update_period = VSC_STATS_ACCUM_SECS;
3944171471Skmacy	else
3945171471Skmacy		adapter->params.stats_update_period = is_10G(adapter) ?
3946171471Skmacy			MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
3947167514Skmacy	adapter->params.pci.vpd_cap_addr =
3948167514Skmacy		t3_os_find_pci_capability(adapter, PCI_CAP_ID_VPD);
3949167514Skmacy
3950167514Skmacy	ret = get_vpd_params(adapter, &adapter->params.vpd);
3951171471Skmacy	if (ret < 0)
3952167514Skmacy		return ret;
3953171471Skmacy
3954167514Skmacy	if (reset && t3_reset_adapter(adapter))
3955167514Skmacy		return -1;
3956167514Skmacy
3957167514Skmacy	t3_sge_prep(adapter, &adapter->params.sge);
3958167514Skmacy
3959167514Skmacy	if (adapter->params.vpd.mclk) {
3960167514Skmacy		struct tp_params *p = &adapter->params.tp;
3961167514Skmacy
3962167514Skmacy		mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
3963167514Skmacy		mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
3964167514Skmacy		mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
3965167514Skmacy
3966170654Skmacy		p->nchan = adapter->params.chan_map == 3 ? 2 : 1;
3967167514Skmacy		p->pmrx_size = t3_mc7_size(&adapter->pmrx);
3968167514Skmacy		p->pmtx_size = t3_mc7_size(&adapter->pmtx);
3969167514Skmacy		p->cm_size = t3_mc7_size(&adapter->cm);
3970167514Skmacy		p->chan_rx_size = p->pmrx_size / 2;     /* only 1 Rx channel */
3971167514Skmacy		p->chan_tx_size = p->pmtx_size / p->nchan;
3972167514Skmacy		p->rx_pg_size = 64 * 1024;
3973167514Skmacy		p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
3974167514Skmacy		p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
3975167514Skmacy		p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
3976167514Skmacy		p->ntimer_qs = p->cm_size >= (128 << 20) ||
3977167514Skmacy			       adapter->params.rev > 0 ? 12 : 6;
3978170654Skmacy		p->tre = fls(adapter->params.vpd.cclk / (1000 / TP_TMR_RES)) -
3979170654Skmacy			 1;
3980167746Skmacy		p->dack_re = fls(adapter->params.vpd.cclk / 10) - 1; /* 100us */
3981169978Skmacy	}
3982170654Skmacy
3983169978Skmacy	adapter->params.offload = t3_mc7_size(&adapter->pmrx) &&
3984170654Skmacy				  t3_mc7_size(&adapter->pmtx) &&
3985170654Skmacy				  t3_mc7_size(&adapter->cm);
3986167514Skmacy
3987169978Skmacy	if (is_offload(adapter)) {
3988167514Skmacy		adapter->params.mc5.nservers = DEFAULT_NSERVERS;
3989167514Skmacy		adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
3990167514Skmacy					       DEFAULT_NFILTERS : 0;
3991167514Skmacy		adapter->params.mc5.nroutes = 0;
3992167514Skmacy		t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
3993167514Skmacy
3994167514Skmacy#ifdef CONFIG_CHELSIO_T3_CORE
3995167514Skmacy		init_mtus(adapter->params.mtus);
3996167514Skmacy		init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
3997167514Skmacy#endif
3998167514Skmacy	}
3999167514Skmacy
4000167514Skmacy	early_hw_init(adapter, ai);
4001176472Skmacy	ret = init_parity(adapter);
4002176472Skmacy	if (ret)
4003176472Skmacy		return ret;
4004167514Skmacy
4005171471Skmacy	if (adapter->params.nports > 2 &&
4006171471Skmacy	    (ret = t3_vsc7323_init(adapter, adapter->params.nports)))
4007171471Skmacy		return ret;
4008171471Skmacy
4009167514Skmacy	for_each_port(adapter, i) {
4010167514Skmacy		u8 hw_addr[6];
4011176472Skmacy		const struct port_type_info *pti;
4012170654Skmacy		struct port_info *p = adap2pinfo(adapter, i);
4013167514Skmacy
4014171471Skmacy		while (!adapter->params.vpd.port_type[j])
4015167514Skmacy			++j;
4016167514Skmacy
4017176472Skmacy		pti = &port_types[adapter->params.vpd.port_type[j]];
4018176472Skmacy		ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
4019176472Skmacy				    ai->mdio_ops);
4020176472Skmacy		if (ret)
4021176472Skmacy			return ret;
4022167514Skmacy		mac_prep(&p->mac, adapter, j);
4023167514Skmacy		++j;
4024167514Skmacy
4025167514Skmacy		/*
4026167514Skmacy		 * The VPD EEPROM stores the base Ethernet address for the
4027167514Skmacy		 * card.  A port's address is derived from the base by adding
4028167514Skmacy		 * the port's index to the base's low octet.
4029167514Skmacy		 */
4030167514Skmacy		memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
4031167514Skmacy		hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
4032167514Skmacy
4033167514Skmacy		t3_os_set_hw_addr(adapter, i, hw_addr);
4034176472Skmacy		init_link_config(&p->link_config, p->phy.caps);
4035167514Skmacy		p->phy.ops->power_down(&p->phy, 1);
4036176472Skmacy		if (!(p->phy.caps & SUPPORTED_IRQ))
4037167514Skmacy			adapter->params.linkpoll_period = 10;
4038167514Skmacy	}
4039167514Skmacy
4040167514Skmacy	return 0;
4041167514Skmacy}
4042167514Skmacy
4043181614Skmacy/**
4044181614Skmacy *	t3_reinit_adapter - prepare HW for operation again
4045181614Skmacy *	@adapter: the adapter
4046181614Skmacy *
4047181614Skmacy *	Put HW in the same state as @t3_prep_adapter without any changes to
4048181614Skmacy *	SW state.  This is a cut down version of @t3_prep_adapter intended
4049181614Skmacy *	to be used after events that wipe out HW state but preserve SW state,
4050181614Skmacy *	e.g., EEH.  The device must be reset before calling this.
4051181614Skmacy */
4052181614Skmacyint t3_reinit_adapter(adapter_t *adap)
4053181614Skmacy{
4054181614Skmacy	unsigned int i;
4055181614Skmacy	int ret, j = -1;
4056181614Skmacy
4057181614Skmacy	early_hw_init(adap, adap->params.info);
4058181614Skmacy	ret = init_parity(adap);
4059181614Skmacy	if (ret)
4060181614Skmacy		return ret;
4061181614Skmacy
4062181614Skmacy	if (adap->params.nports > 2 &&
4063181614Skmacy	    (ret = t3_vsc7323_init(adap, adap->params.nports)))
4064181614Skmacy		return ret;
4065181614Skmacy
4066181614Skmacy	for_each_port(adap, i) {
4067181614Skmacy		const struct port_type_info *pti;
4068181614Skmacy		struct port_info *p = adap2pinfo(adap, i);
4069181614Skmacy
4070181614Skmacy		while (!adap->params.vpd.port_type[++j])
4071181614Skmacy			;
4072181614Skmacy
4073181614Skmacy		pti = &port_types[adap->params.vpd.port_type[j]];
4074181614Skmacy		ret = pti->phy_prep(&p->phy, adap, p->phy.addr, NULL);
4075181614Skmacy		if (ret)
4076181614Skmacy			return ret;
4077181614Skmacy		p->phy.ops->power_down(&p->phy, 1);
4078181614Skmacy	}
4079181614Skmacy	return 0;
4080181614Skmacy}
4081181614Skmacy
4082167514Skmacyvoid t3_led_ready(adapter_t *adapter)
4083167514Skmacy{
4084167514Skmacy	t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
4085167514Skmacy			 F_GPIO0_OUT_VAL);
4086167514Skmacy}
4087167514Skmacy
4088167514Skmacyvoid t3_port_failover(adapter_t *adapter, int port)
4089167514Skmacy{
4090167514Skmacy	u32 val;
4091167514Skmacy
4092167514Skmacy	val = port ? F_PORT1ACTIVE : F_PORT0ACTIVE;
4093167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4094167514Skmacy			 val);
4095167514Skmacy}
4096167514Skmacy
4097167514Skmacyvoid t3_failover_done(adapter_t *adapter, int port)
4098167514Skmacy{
4099167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4100167514Skmacy			 F_PORT0ACTIVE | F_PORT1ACTIVE);
4101167514Skmacy}
4102167514Skmacy
4103167514Skmacyvoid t3_failover_clear(adapter_t *adapter)
4104167514Skmacy{
4105167514Skmacy	t3_set_reg_field(adapter, A_MPS_CFG, F_PORT0ACTIVE | F_PORT1ACTIVE,
4106167514Skmacy			 F_PORT0ACTIVE | F_PORT1ACTIVE);
4107167514Skmacy}
4108