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