blob: f7ced324227d02c839497c560a83aeb6fccca9c6 [file] [log] [blame]
Divy Le Ray4d22de32007-01-18 22:04:14 -05001/*
Divy Le Ray1d68e932007-01-30 19:44:35 -08002 * Copyright (c) 2003-2007 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/**
411 * t3_set_phy_speed_duplex - force PHY speed and duplex
412 * @phy: the PHY to operate on
413 * @speed: requested PHY speed
414 * @duplex: requested PHY duplex
415 *
416 * Force a 10/100/1000 PHY's speed and duplex. This also disables
417 * auto-negotiation except for GigE, where auto-negotiation is mandatory.
418 */
419int t3_set_phy_speed_duplex(struct cphy *phy, int speed, int duplex)
420{
421 int err;
422 unsigned int ctl;
423
424 err = mdio_read(phy, 0, MII_BMCR, &ctl);
425 if (err)
426 return err;
427
428 if (speed >= 0) {
429 ctl &= ~(BMCR_SPEED100 | BMCR_SPEED1000 | BMCR_ANENABLE);
430 if (speed == SPEED_100)
431 ctl |= BMCR_SPEED100;
432 else if (speed == SPEED_1000)
433 ctl |= BMCR_SPEED1000;
434 }
435 if (duplex >= 0) {
436 ctl &= ~(BMCR_FULLDPLX | BMCR_ANENABLE);
437 if (duplex == DUPLEX_FULL)
438 ctl |= BMCR_FULLDPLX;
439 }
440 if (ctl & BMCR_SPEED1000) /* auto-negotiation required for GigE */
441 ctl |= BMCR_ANENABLE;
442 return mdio_write(phy, 0, MII_BMCR, ctl);
443}
444
445static const struct adapter_info t3_adap_info[] = {
Divy Le Ray04497982008-10-08 17:38:29 -0700446 {2, 0,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500447 F_GPIO2_OEN | F_GPIO4_OEN |
448 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700449 0,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500450 &mi1_mdio_ops, "Chelsio PE9000"},
Divy Le Ray04497982008-10-08 17:38:29 -0700451 {2, 0,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500452 F_GPIO2_OEN | F_GPIO4_OEN |
453 F_GPIO2_OUT_VAL | F_GPIO4_OUT_VAL, F_GPIO3 | F_GPIO5,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700454 0,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500455 &mi1_mdio_ops, "Chelsio T302"},
Divy Le Ray04497982008-10-08 17:38:29 -0700456 {1, 0,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500457 F_GPIO1_OEN | F_GPIO6_OEN | F_GPIO7_OEN | F_GPIO10_OEN |
Divy Le Ray75758e82007-12-05 10:15:01 -0800458 F_GPIO11_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
459 0, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500460 &mi1_mdio_ext_ops, "Chelsio T310"},
Divy Le Ray04497982008-10-08 17:38:29 -0700461 {2, 0,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500462 F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO5_OEN | F_GPIO6_OEN |
463 F_GPIO7_OEN | F_GPIO10_OEN | F_GPIO11_OEN | F_GPIO1_OUT_VAL |
464 F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL, 0,
Divy Le Ray8ac3ba62007-03-31 00:23:19 -0700465 SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
Divy Le Ray4d22de32007-01-18 22:04:14 -0500466 &mi1_mdio_ext_ops, "Chelsio T320"},
467};
468
469/*
470 * Return the adapter_info structure with a given index. Out-of-range indices
471 * return NULL.
472 */
473const struct adapter_info *t3_get_adapter_info(unsigned int id)
474{
475 return id < ARRAY_SIZE(t3_adap_info) ? &t3_adap_info[id] : NULL;
476}
477
Divy Le Ray04497982008-10-08 17:38:29 -0700478struct port_type_info {
479 int (*phy_prep)(struct cphy *phy, struct adapter *adapter,
480 int phy_addr, const struct mdio_ops *ops);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500481};
482
Divy Le Ray04497982008-10-08 17:38:29 -0700483static const struct port_type_info port_types[] = {
484 { NULL },
485 { t3_ael1002_phy_prep },
486 { t3_vsc8211_phy_prep },
487 { NULL},
488 { t3_xaui_direct_phy_prep },
489 { NULL },
490 { t3_qt2045_phy_prep },
491 { t3_ael1006_phy_prep },
492 { NULL },
493};
Divy Le Ray4d22de32007-01-18 22:04:14 -0500494
495#define VPD_ENTRY(name, len) \
496 u8 name##_kword[2]; u8 name##_len; u8 name##_data[len]
497
498/*
499 * Partial EEPROM Vital Product Data structure. Includes only the ID and
500 * VPD-R sections.
501 */
502struct t3_vpd {
503 u8 id_tag;
504 u8 id_len[2];
505 u8 id_data[16];
506 u8 vpdr_tag;
507 u8 vpdr_len[2];
508 VPD_ENTRY(pn, 16); /* part number */
509 VPD_ENTRY(ec, 16); /* EC level */
Divy Le Ray167cdf52007-08-21 20:49:36 -0700510 VPD_ENTRY(sn, SERNUM_LEN); /* serial number */
Divy Le Ray4d22de32007-01-18 22:04:14 -0500511 VPD_ENTRY(na, 12); /* MAC address base */
512 VPD_ENTRY(cclk, 6); /* core clock */
513 VPD_ENTRY(mclk, 6); /* mem clock */
514 VPD_ENTRY(uclk, 6); /* uP clk */
515 VPD_ENTRY(mdc, 6); /* MDIO clk */
516 VPD_ENTRY(mt, 2); /* mem timing */
517 VPD_ENTRY(xaui0cfg, 6); /* XAUI0 config */
518 VPD_ENTRY(xaui1cfg, 6); /* XAUI1 config */
519 VPD_ENTRY(port0, 2); /* PHY0 complex */
520 VPD_ENTRY(port1, 2); /* PHY1 complex */
521 VPD_ENTRY(port2, 2); /* PHY2 complex */
522 VPD_ENTRY(port3, 2); /* PHY3 complex */
523 VPD_ENTRY(rv, 1); /* csum */
524 u32 pad; /* for multiple-of-4 sizing and alignment */
525};
526
527#define EEPROM_MAX_POLL 4
528#define EEPROM_STAT_ADDR 0x4000
529#define VPD_BASE 0xc00
530
531/**
532 * t3_seeprom_read - read a VPD EEPROM location
533 * @adapter: adapter to read
534 * @addr: EEPROM address
535 * @data: where to store the read data
536 *
537 * Read a 32-bit word from a location in VPD EEPROM using the card's PCI
538 * VPD ROM capability. A zero is written to the flag bit when the
539 * addres is written to the control register. The hardware device will
540 * set the flag to 1 when 4 bytes have been read into the data register.
541 */
Al Viro05e5c112007-12-22 18:56:23 +0000542int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500543{
544 u16 val;
545 int attempts = EEPROM_MAX_POLL;
Al Viro05e5c112007-12-22 18:56:23 +0000546 u32 v;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500547 unsigned int base = adapter->params.pci.vpd_cap_addr;
548
549 if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
550 return -EINVAL;
551
552 pci_write_config_word(adapter->pdev, base + PCI_VPD_ADDR, addr);
553 do {
554 udelay(10);
555 pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
556 } while (!(val & PCI_VPD_ADDR_F) && --attempts);
557
558 if (!(val & PCI_VPD_ADDR_F)) {
559 CH_ERR(adapter, "reading EEPROM address 0x%x failed\n", addr);
560 return -EIO;
561 }
Al Viro05e5c112007-12-22 18:56:23 +0000562 pci_read_config_dword(adapter->pdev, base + PCI_VPD_DATA, &v);
563 *data = cpu_to_le32(v);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500564 return 0;
565}
566
567/**
568 * t3_seeprom_write - write a VPD EEPROM location
569 * @adapter: adapter to write
570 * @addr: EEPROM address
571 * @data: value to write
572 *
573 * Write a 32-bit word to a location in VPD EEPROM using the card's PCI
574 * VPD ROM capability.
575 */
Al Viro05e5c112007-12-22 18:56:23 +0000576int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500577{
578 u16 val;
579 int attempts = EEPROM_MAX_POLL;
580 unsigned int base = adapter->params.pci.vpd_cap_addr;
581
582 if ((addr >= EEPROMSIZE && addr != EEPROM_STAT_ADDR) || (addr & 3))
583 return -EINVAL;
584
585 pci_write_config_dword(adapter->pdev, base + PCI_VPD_DATA,
Al Viro05e5c112007-12-22 18:56:23 +0000586 le32_to_cpu(data));
Divy Le Ray4d22de32007-01-18 22:04:14 -0500587 pci_write_config_word(adapter->pdev,base + PCI_VPD_ADDR,
588 addr | PCI_VPD_ADDR_F);
589 do {
590 msleep(1);
591 pci_read_config_word(adapter->pdev, base + PCI_VPD_ADDR, &val);
592 } while ((val & PCI_VPD_ADDR_F) && --attempts);
593
594 if (val & PCI_VPD_ADDR_F) {
595 CH_ERR(adapter, "write to EEPROM address 0x%x failed\n", addr);
596 return -EIO;
597 }
598 return 0;
599}
600
601/**
602 * t3_seeprom_wp - enable/disable EEPROM write protection
603 * @adapter: the adapter
604 * @enable: 1 to enable write protection, 0 to disable it
605 *
606 * Enables or disables write protection on the serial EEPROM.
607 */
608int t3_seeprom_wp(struct adapter *adapter, int enable)
609{
610 return t3_seeprom_write(adapter, EEPROM_STAT_ADDR, enable ? 0xc : 0);
611}
612
613/*
614 * Convert a character holding a hex digit to a number.
615 */
616static unsigned int hex2int(unsigned char c)
617{
618 return isdigit(c) ? c - '0' : toupper(c) - 'A' + 10;
619}
620
621/**
622 * get_vpd_params - read VPD parameters from VPD EEPROM
623 * @adapter: adapter to read
624 * @p: where to store the parameters
625 *
626 * Reads card parameters stored in VPD EEPROM.
627 */
628static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
629{
630 int i, addr, ret;
631 struct t3_vpd vpd;
632
633 /*
634 * Card information is normally at VPD_BASE but some early cards had
635 * it at 0.
636 */
Al Viro05e5c112007-12-22 18:56:23 +0000637 ret = t3_seeprom_read(adapter, VPD_BASE, (__le32 *)&vpd);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500638 if (ret)
639 return ret;
640 addr = vpd.id_tag == 0x82 ? VPD_BASE : 0;
641
642 for (i = 0; i < sizeof(vpd); i += 4) {
643 ret = t3_seeprom_read(adapter, addr + i,
Al Viro05e5c112007-12-22 18:56:23 +0000644 (__le32 *)((u8 *)&vpd + i));
Divy Le Ray4d22de32007-01-18 22:04:14 -0500645 if (ret)
646 return ret;
647 }
648
649 p->cclk = simple_strtoul(vpd.cclk_data, NULL, 10);
650 p->mclk = simple_strtoul(vpd.mclk_data, NULL, 10);
651 p->uclk = simple_strtoul(vpd.uclk_data, NULL, 10);
652 p->mdc = simple_strtoul(vpd.mdc_data, NULL, 10);
653 p->mem_timing = simple_strtoul(vpd.mt_data, NULL, 10);
Divy Le Ray167cdf52007-08-21 20:49:36 -0700654 memcpy(p->sn, vpd.sn_data, SERNUM_LEN);
Divy Le Ray4d22de32007-01-18 22:04:14 -0500655
656 /* Old eeproms didn't have port information */
657 if (adapter->params.rev == 0 && !vpd.port0_data[0]) {
658 p->port_type[0] = uses_xaui(adapter) ? 1 : 2;
659 p->port_type[1] = uses_xaui(adapter) ? 6 : 2;
660 } else {
661 p->port_type[0] = hex2int(vpd.port0_data[0]);
662 p->port_type[1] = hex2int(vpd.port1_data[0]);
663 p->xauicfg[0] = simple_strtoul(vpd.xaui0cfg_data, NULL, 16);
664 p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
665 }
666
667 for (i = 0; i < 6; i++)
668 p->eth_base[i] = hex2int(vpd.na_data[2 * i]) * 16 +
669 hex2int(vpd.na_data[2 * i + 1]);
670 return 0;
671}
672
673/* serial flash and firmware constants */
674enum {
675 SF_ATTEMPTS = 5, /* max retries for SF1 operations */
676 SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
677 SF_SIZE = SF_SEC_SIZE * 8, /* serial flash size */
678
679 /* flash command opcodes */
680 SF_PROG_PAGE = 2, /* program page */
681 SF_WR_DISABLE = 4, /* disable writes */
682 SF_RD_STATUS = 5, /* read status register */
683 SF_WR_ENABLE = 6, /* enable writes */
684 SF_RD_DATA_FAST = 0xb, /* read flash */
685 SF_ERASE_SECTOR = 0xd8, /* erase sector */
686
687 FW_FLASH_BOOT_ADDR = 0x70000, /* start address of FW in flash */
Steve Wise80513672008-07-26 15:40:56 -0500688 FW_VERS_ADDR = 0x7fffc, /* flash address holding FW version */
Divy Le Ray2e283962007-03-18 13:10:06 -0700689 FW_MIN_SIZE = 8 /* at least version and csum */
Divy Le Ray4d22de32007-01-18 22:04:14 -0500690};
691
692/**
693 * sf1_read - read data from the serial flash
694 * @adapter: the adapter
695 * @byte_cnt: number of bytes to read
696 * @cont: whether another operation will be chained
697 * @valp: where to store the read data
698 *
699 * Reads up to 4 bytes of data from the serial flash. The location of
700 * the read needs to be specified prior to calling this by issuing the
701 * appropriate commands to the serial flash.
702 */
703static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
704 u32 *valp)
705{
706 int ret;
707
708 if (!byte_cnt || byte_cnt > 4)
709 return -EINVAL;
710 if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
711 return -EBUSY;
712 t3_write_reg(adapter, A_SF_OP, V_CONT(cont) | V_BYTECNT(byte_cnt - 1));
713 ret = t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
714 if (!ret)
715 *valp = t3_read_reg(adapter, A_SF_DATA);
716 return ret;
717}
718
719/**
720 * sf1_write - write data to the serial flash
721 * @adapter: the adapter
722 * @byte_cnt: number of bytes to write
723 * @cont: whether another operation will be chained
724 * @val: value to write
725 *
726 * Writes up to 4 bytes of data to the serial flash. The location of
727 * the write needs to be specified prior to calling this by issuing the
728 * appropriate commands to the serial flash.
729 */
730static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
731 u32 val)
732{
733 if (!byte_cnt || byte_cnt > 4)
734 return -EINVAL;
735 if (t3_read_reg(adapter, A_SF_OP) & F_BUSY)
736 return -EBUSY;
737 t3_write_reg(adapter, A_SF_DATA, val);
738 t3_write_reg(adapter, A_SF_OP,
739 V_CONT(cont) | V_BYTECNT(byte_cnt - 1) | V_OP(1));
740 return t3_wait_op_done(adapter, A_SF_OP, F_BUSY, 0, SF_ATTEMPTS, 10);
741}
742
743/**
744 * flash_wait_op - wait for a flash operation to complete
745 * @adapter: the adapter
746 * @attempts: max number of polls of the status register
747 * @delay: delay between polls in ms
748 *
749 * Wait for a flash operation to complete by polling the status register.
750 */
751static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
752{
753 int ret;
754 u32 status;
755
756 while (1) {
757 if ((ret = sf1_write(adapter, 1, 1, SF_RD_STATUS)) != 0 ||
758 (ret = sf1_read(adapter, 1, 0, &status)) != 0)
759 return ret;
760 if (!(status & 1))
761 return 0;
762 if (--attempts == 0)
763 return -EAGAIN;
764 if (delay)
765 msleep(delay);
766 }
767}
768
769/**
770 * t3_read_flash - read words from serial flash
771 * @adapter: the adapter
772 * @addr: the start address for the read
773 * @nwords: how many 32-bit words to read
774 * @data: where to store the read data
775 * @byte_oriented: whether to store data as bytes or as words
776 *
777 * Read the specified number of 32-bit words from the serial flash.
778 * If @byte_oriented is set the read data is stored as a byte array
779 * (i.e., big-endian), otherwise as 32-bit words in the platform's
780 * natural endianess.
781 */
782int t3_read_flash(struct adapter *adapter, unsigned int addr,
783 unsigned int nwords, u32 *data, int byte_oriented)
784{
785 int ret;
786
787 if (addr + nwords * sizeof(u32) > SF_SIZE || (addr & 3))
788 return -EINVAL;
789
790 addr = swab32(addr) | SF_RD_DATA_FAST;
791
792 if ((ret = sf1_write(adapter, 4, 1, addr)) != 0 ||
793 (ret = sf1_read(adapter, 1, 1, data)) != 0)
794 return ret;
795
796 for (; nwords; nwords--, data++) {
797 ret = sf1_read(adapter, 4, nwords > 1, data);
798 if (ret)
799 return ret;
800 if (byte_oriented)
801 *data = htonl(*data);
802 }
803 return 0;
804}
805
806/**
807 * t3_write_flash - write up to a page of data to the serial flash
808 * @adapter: the adapter
809 * @addr: the start address to write
810 * @n: length of data to write
811 * @data: the data to write
812 *
813 * Writes up to a page of data (256 bytes) to the serial flash starting
814 * at the given address.
815 */
816static int t3_write_flash(struct adapter *adapter, unsigned int addr,
817 unsigned int n, const u8 *data)
818{
819 int ret;
820 u32 buf[64];
821 unsigned int i, c, left, val, offset = addr & 0xff;
822
823 if (addr + n > SF_SIZE || offset + n > 256)
824 return -EINVAL;
825
826 val = swab32(addr) | SF_PROG_PAGE;
827
828 if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
829 (ret = sf1_write(adapter, 4, 1, val)) != 0)
830 return ret;
831
832 for (left = n; left; left -= c) {
833 c = min(left, 4U);
834 for (val = 0, i = 0; i < c; ++i)
835 val = (val << 8) + *data++;
836
837 ret = sf1_write(adapter, c, c != left, val);
838 if (ret)
839 return ret;
840 }
841 if ((ret = flash_wait_op(adapter, 5, 1)) != 0)
842 return ret;
843
844 /* Read the page to verify the write succeeded */
845 ret = t3_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
846 if (ret)
847 return ret;
848
849 if (memcmp(data - n, (u8 *) buf + offset, n))
850 return -EIO;
851 return 0;
852}
853
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700854/**
Divy Le Ray47330072007-08-29 19:15:52 -0700855 * t3_get_tp_version - read the tp sram version
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700856 * @adapter: the adapter
Divy Le Ray47330072007-08-29 19:15:52 -0700857 * @vers: where to place the version
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700858 *
Divy Le Ray47330072007-08-29 19:15:52 -0700859 * Reads the protocol sram version from sram.
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700860 */
Divy Le Ray47330072007-08-29 19:15:52 -0700861int t3_get_tp_version(struct adapter *adapter, u32 *vers)
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700862{
863 int ret;
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700864
865 /* Get version loaded in SRAM */
866 t3_write_reg(adapter, A_TP_EMBED_OP_FIELD0, 0);
867 ret = t3_wait_op_done(adapter, A_TP_EMBED_OP_FIELD0,
868 1, 1, 5, 1);
869 if (ret)
870 return ret;
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500871
Divy Le Ray47330072007-08-29 19:15:52 -0700872 *vers = t3_read_reg(adapter, A_TP_EMBED_OP_FIELD1);
873
874 return 0;
875}
876
877/**
878 * t3_check_tpsram_version - read the tp sram version
879 * @adapter: the adapter
880 * @must_load: set to 1 if loading a new microcode image is required
881 *
882 * Reads the protocol sram version from flash.
883 */
884int t3_check_tpsram_version(struct adapter *adapter, int *must_load)
885{
886 int ret;
887 u32 vers;
888 unsigned int major, minor;
889
890 if (adapter->params.rev == T3_REV_A)
891 return 0;
892
893 *must_load = 1;
894
895 ret = t3_get_tp_version(adapter, &vers);
896 if (ret)
897 return ret;
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700898
899 major = G_TP_VERSION_MAJOR(vers);
900 minor = G_TP_VERSION_MINOR(vers);
901
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500902 if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR)
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700903 return 0;
904
Divy Le Ray47330072007-08-29 19:15:52 -0700905 if (major != TP_VERSION_MAJOR)
906 CH_ERR(adapter, "found wrong TP version (%u.%u), "
907 "driver needs version %d.%d\n", major, minor,
908 TP_VERSION_MAJOR, TP_VERSION_MINOR);
909 else {
910 *must_load = 0;
911 CH_ERR(adapter, "found wrong TP version (%u.%u), "
912 "driver compiled for version %d.%d\n", major, minor,
913 TP_VERSION_MAJOR, TP_VERSION_MINOR);
914 }
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700915 return -EINVAL;
916}
917
918/**
Jeff Garzik2eab17a2007-11-23 21:59:45 -0500919 * t3_check_tpsram - check if provided protocol SRAM
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700920 * is compatible with this driver
921 * @adapter: the adapter
922 * @tp_sram: the firmware image to write
923 * @size: image size
924 *
925 * Checks if an adapter's tp sram is compatible with the driver.
926 * Returns 0 if the versions are compatible, a negative error otherwise.
927 */
David Woodhouse2c733a12008-05-24 00:10:55 +0100928int t3_check_tpsram(struct adapter *adapter, const u8 *tp_sram,
929 unsigned int size)
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700930{
931 u32 csum;
932 unsigned int i;
Al Viro05e5c112007-12-22 18:56:23 +0000933 const __be32 *p = (const __be32 *)tp_sram;
Divy Le Ray480fe1a2007-05-30 21:10:58 -0700934
935 /* Verify checksum */
936 for (csum = 0, i = 0; i < size / sizeof(csum); i++)
937 csum += ntohl(p[i]);
938 if (csum != 0xffffffff) {
939 CH_ERR(adapter, "corrupted protocol SRAM image, checksum %u\n",
940 csum);
941 return -EINVAL;
942 }
943
944 return 0;
945}
946
Divy Le Ray4aac3892007-01-30 19:43:45 -0800947enum fw_version_type {
948 FW_VERSION_N3,
949 FW_VERSION_T3
950};
951
Divy Le Ray4d22de32007-01-18 22:04:14 -0500952/**
953 * t3_get_fw_version - read the firmware version
954 * @adapter: the adapter
955 * @vers: where to place the version
956 *
957 * Reads the FW version from flash.
958 */
959int t3_get_fw_version(struct adapter *adapter, u32 *vers)
960{
961 return t3_read_flash(adapter, FW_VERS_ADDR, 1, vers, 0);
962}
963
964/**
965 * t3_check_fw_version - check if the FW is compatible with this driver
966 * @adapter: the adapter
Divy Le Raya5a3b462007-09-05 15:58:09 -0700967 * @must_load: set to 1 if loading a new FW image is required
968
Divy Le Ray4d22de32007-01-18 22:04:14 -0500969 * Checks if an adapter's FW is compatible with the driver. Returns 0
970 * if the versions are compatible, a negative error otherwise.
971 */
Divy Le Raya5a3b462007-09-05 15:58:09 -0700972int t3_check_fw_version(struct adapter *adapter, int *must_load)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500973{
974 int ret;
975 u32 vers;
Divy Le Ray4aac3892007-01-30 19:43:45 -0800976 unsigned int type, major, minor;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500977
Divy Le Raya5a3b462007-09-05 15:58:09 -0700978 *must_load = 1;
Divy Le Ray4d22de32007-01-18 22:04:14 -0500979 ret = t3_get_fw_version(adapter, &vers);
980 if (ret)
981 return ret;
982
Divy Le Ray4aac3892007-01-30 19:43:45 -0800983 type = G_FW_VERSION_TYPE(vers);
984 major = G_FW_VERSION_MAJOR(vers);
985 minor = G_FW_VERSION_MINOR(vers);
986
Divy Le Ray75d86262007-02-25 16:32:37 -0800987 if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR &&
988 minor == FW_VERSION_MINOR)
Divy Le Ray4d22de32007-01-18 22:04:14 -0500989 return 0;
990
Divy Le Raya5a3b462007-09-05 15:58:09 -0700991 if (major != FW_VERSION_MAJOR)
992 CH_ERR(adapter, "found wrong FW version(%u.%u), "
993 "driver needs version %u.%u\n", major, minor,
994 FW_VERSION_MAJOR, FW_VERSION_MINOR);
Divy Le Ray273fa902007-11-16 11:22:00 -0800995 else if (minor < FW_VERSION_MINOR) {
Divy Le Raya5a3b462007-09-05 15:58:09 -0700996 *must_load = 0;
Divy Le Ray273fa902007-11-16 11:22:00 -0800997 CH_WARN(adapter, "found old FW minor version(%u.%u), "
Divy Le Raya5a3b462007-09-05 15:58:09 -0700998 "driver compiled for version %u.%u\n", major, minor,
999 FW_VERSION_MAJOR, FW_VERSION_MINOR);
Divy Le Ray273fa902007-11-16 11:22:00 -08001000 } else {
1001 CH_WARN(adapter, "found newer FW version(%u.%u), "
1002 "driver compiled for version %u.%u\n", major, minor,
1003 FW_VERSION_MAJOR, FW_VERSION_MINOR);
1004 return 0;
Divy Le Raya5a3b462007-09-05 15:58:09 -07001005 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05001006 return -EINVAL;
1007}
1008
1009/**
1010 * t3_flash_erase_sectors - erase a range of flash sectors
1011 * @adapter: the adapter
1012 * @start: the first sector to erase
1013 * @end: the last sector to erase
1014 *
1015 * Erases the sectors in the given range.
1016 */
1017static int t3_flash_erase_sectors(struct adapter *adapter, int start, int end)
1018{
1019 while (start <= end) {
1020 int ret;
1021
1022 if ((ret = sf1_write(adapter, 1, 0, SF_WR_ENABLE)) != 0 ||
1023 (ret = sf1_write(adapter, 4, 0,
1024 SF_ERASE_SECTOR | (start << 8))) != 0 ||
1025 (ret = flash_wait_op(adapter, 5, 500)) != 0)
1026 return ret;
1027 start++;
1028 }
1029 return 0;
1030}
1031
1032/*
1033 * t3_load_fw - download firmware
1034 * @adapter: the adapter
Divy Le Ray8a9fab22007-05-30 21:10:52 -07001035 * @fw_data: the firmware image to write
Divy Le Ray4d22de32007-01-18 22:04:14 -05001036 * @size: image size
1037 *
1038 * Write the supplied firmware image to the card's serial flash.
1039 * The FW image has the following sections: @size - 8 bytes of code and
1040 * data, followed by 4 bytes of FW version, followed by the 32-bit
1041 * 1's complement checksum of the whole image.
1042 */
1043int t3_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size)
1044{
1045 u32 csum;
1046 unsigned int i;
Al Viro05e5c112007-12-22 18:56:23 +00001047 const __be32 *p = (const __be32 *)fw_data;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001048 int ret, addr, fw_sector = FW_FLASH_BOOT_ADDR >> 16;
1049
Divy Le Ray2e283962007-03-18 13:10:06 -07001050 if ((size & 3) || size < FW_MIN_SIZE)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001051 return -EINVAL;
1052 if (size > FW_VERS_ADDR + 8 - FW_FLASH_BOOT_ADDR)
1053 return -EFBIG;
1054
1055 for (csum = 0, i = 0; i < size / sizeof(csum); i++)
1056 csum += ntohl(p[i]);
1057 if (csum != 0xffffffff) {
1058 CH_ERR(adapter, "corrupted firmware image, checksum %u\n",
1059 csum);
1060 return -EINVAL;
1061 }
1062
1063 ret = t3_flash_erase_sectors(adapter, fw_sector, fw_sector);
1064 if (ret)
1065 goto out;
1066
1067 size -= 8; /* trim off version and checksum */
1068 for (addr = FW_FLASH_BOOT_ADDR; size;) {
1069 unsigned int chunk_size = min(size, 256U);
1070
1071 ret = t3_write_flash(adapter, addr, chunk_size, fw_data);
1072 if (ret)
1073 goto out;
1074
1075 addr += chunk_size;
1076 fw_data += chunk_size;
1077 size -= chunk_size;
1078 }
1079
1080 ret = t3_write_flash(adapter, FW_VERS_ADDR, 4, fw_data);
1081out:
1082 if (ret)
1083 CH_ERR(adapter, "firmware download failed, error %d\n", ret);
1084 return ret;
1085}
1086
1087#define CIM_CTL_BASE 0x2000
1088
1089/**
1090 * t3_cim_ctl_blk_read - read a block from CIM control region
1091 *
1092 * @adap: the adapter
1093 * @addr: the start address within the CIM control region
1094 * @n: number of words to read
1095 * @valp: where to store the result
1096 *
1097 * Reads a block of 4-byte words from the CIM control region.
1098 */
1099int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
1100 unsigned int n, unsigned int *valp)
1101{
1102 int ret = 0;
1103
1104 if (t3_read_reg(adap, A_CIM_HOST_ACC_CTRL) & F_HOSTBUSY)
1105 return -EBUSY;
1106
1107 for ( ; !ret && n--; addr += 4) {
1108 t3_write_reg(adap, A_CIM_HOST_ACC_CTRL, CIM_CTL_BASE + addr);
1109 ret = t3_wait_op_done(adap, A_CIM_HOST_ACC_CTRL, F_HOSTBUSY,
1110 0, 5, 2);
1111 if (!ret)
1112 *valp++ = t3_read_reg(adap, A_CIM_HOST_ACC_DATA);
1113 }
1114 return ret;
1115}
1116
1117
1118/**
1119 * t3_link_changed - handle interface link changes
1120 * @adapter: the adapter
1121 * @port_id: the port index that changed link state
1122 *
1123 * Called when a port's link settings change to propagate the new values
1124 * to the associated PHY and MAC. After performing the common tasks it
1125 * invokes an OS-specific handler.
1126 */
1127void t3_link_changed(struct adapter *adapter, int port_id)
1128{
1129 int link_ok, speed, duplex, fc;
1130 struct port_info *pi = adap2pinfo(adapter, port_id);
1131 struct cphy *phy = &pi->phy;
1132 struct cmac *mac = &pi->mac;
1133 struct link_config *lc = &pi->link_config;
1134
1135 phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
1136
1137 if (link_ok != lc->link_ok && adapter->params.rev > 0 &&
1138 uses_xaui(adapter)) {
1139 if (link_ok)
1140 t3b_pcs_reset(mac);
1141 t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
1142 link_ok ? F_TXACTENABLE | F_RXEN : 0);
1143 }
1144 lc->link_ok = link_ok;
1145 lc->speed = speed < 0 ? SPEED_INVALID : speed;
1146 lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
1147 if (lc->requested_fc & PAUSE_AUTONEG)
1148 fc &= lc->requested_fc;
1149 else
1150 fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1151
1152 if (link_ok && speed >= 0 && lc->autoneg == AUTONEG_ENABLE) {
1153 /* Set MAC speed, duplex, and flow control to match PHY. */
1154 t3_mac_set_speed_duplex_fc(mac, speed, duplex, fc);
1155 lc->fc = fc;
1156 }
1157
1158 t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
1159}
1160
1161/**
1162 * t3_link_start - apply link configuration to MAC/PHY
1163 * @phy: the PHY to setup
1164 * @mac: the MAC to setup
1165 * @lc: the requested link configuration
1166 *
1167 * Set up a port's MAC and PHY according to a desired link configuration.
1168 * - If the PHY can auto-negotiate first decide what to advertise, then
1169 * enable/disable auto-negotiation as desired, and reset.
1170 * - If the PHY does not auto-negotiate just reset it.
1171 * - If auto-negotiation is off set the MAC to the proper speed/duplex/FC,
1172 * otherwise do it later based on the outcome of auto-negotiation.
1173 */
1174int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc)
1175{
1176 unsigned int fc = lc->requested_fc & (PAUSE_RX | PAUSE_TX);
1177
1178 lc->link_ok = 0;
1179 if (lc->supported & SUPPORTED_Autoneg) {
1180 lc->advertising &= ~(ADVERTISED_Asym_Pause | ADVERTISED_Pause);
1181 if (fc) {
1182 lc->advertising |= ADVERTISED_Asym_Pause;
1183 if (fc & PAUSE_RX)
1184 lc->advertising |= ADVERTISED_Pause;
1185 }
1186 phy->ops->advertise(phy, lc->advertising);
1187
1188 if (lc->autoneg == AUTONEG_DISABLE) {
1189 lc->speed = lc->requested_speed;
1190 lc->duplex = lc->requested_duplex;
1191 lc->fc = (unsigned char)fc;
1192 t3_mac_set_speed_duplex_fc(mac, lc->speed, lc->duplex,
1193 fc);
1194 /* Also disables autoneg */
1195 phy->ops->set_speed_duplex(phy, lc->speed, lc->duplex);
1196 phy->ops->reset(phy, 0);
1197 } else
1198 phy->ops->autoneg_enable(phy);
1199 } else {
1200 t3_mac_set_speed_duplex_fc(mac, -1, -1, fc);
1201 lc->fc = (unsigned char)fc;
1202 phy->ops->reset(phy, 0);
1203 }
1204 return 0;
1205}
1206
1207/**
1208 * t3_set_vlan_accel - control HW VLAN extraction
1209 * @adapter: the adapter
1210 * @ports: bitmap of adapter ports to operate on
1211 * @on: enable (1) or disable (0) HW VLAN extraction
1212 *
1213 * Enables or disables HW extraction of VLAN tags for the given port.
1214 */
1215void t3_set_vlan_accel(struct adapter *adapter, unsigned int ports, int on)
1216{
1217 t3_set_reg_field(adapter, A_TP_OUT_CONFIG,
1218 ports << S_VLANEXTRACTIONENABLE,
1219 on ? (ports << S_VLANEXTRACTIONENABLE) : 0);
1220}
1221
1222struct intr_info {
1223 unsigned int mask; /* bits to check in interrupt status */
1224 const char *msg; /* message to print or NULL */
1225 short stat_idx; /* stat counter to increment or -1 */
Divy Le Ray20d3fc12008-10-08 17:36:03 -07001226 unsigned short fatal; /* whether the condition reported is fatal */
Divy Le Ray4d22de32007-01-18 22:04:14 -05001227};
1228
1229/**
1230 * t3_handle_intr_status - table driven interrupt handler
1231 * @adapter: the adapter that generated the interrupt
1232 * @reg: the interrupt status register to process
1233 * @mask: a mask to apply to the interrupt status
1234 * @acts: table of interrupt actions
1235 * @stats: statistics counters tracking interrupt occurences
1236 *
1237 * A table driven interrupt handler that applies a set of masks to an
1238 * interrupt status word and performs the corresponding actions if the
1239 * interrupts described by the mask have occured. The actions include
1240 * optionally printing a warning or alert message, and optionally
1241 * incrementing a stat counter. The table is terminated by an entry
1242 * specifying mask 0. Returns the number of fatal interrupt conditions.
1243 */
1244static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
1245 unsigned int mask,
1246 const struct intr_info *acts,
1247 unsigned long *stats)
1248{
1249 int fatal = 0;
1250 unsigned int status = t3_read_reg(adapter, reg) & mask;
1251
1252 for (; acts->mask; ++acts) {
1253 if (!(status & acts->mask))
1254 continue;
1255 if (acts->fatal) {
1256 fatal++;
1257 CH_ALERT(adapter, "%s (0x%x)\n",
1258 acts->msg, status & acts->mask);
1259 } else if (acts->msg)
1260 CH_WARN(adapter, "%s (0x%x)\n",
1261 acts->msg, status & acts->mask);
1262 if (acts->stat_idx >= 0)
1263 stats[acts->stat_idx]++;
1264 }
1265 if (status) /* clear processed interrupts */
1266 t3_write_reg(adapter, reg, status);
1267 return fatal;
1268}
1269
Divy Le Rayb8819552007-12-17 18:47:31 -08001270#define SGE_INTR_MASK (F_RSPQDISABLED | \
1271 F_UC_REQ_FRAMINGERROR | F_R_REQ_FRAMINGERROR | \
1272 F_CPPARITYERROR | F_OCPARITYERROR | F_RCPARITYERROR | \
1273 F_IRPARITYERROR | V_ITPARITYERROR(M_ITPARITYERROR) | \
1274 V_FLPARITYERROR(M_FLPARITYERROR) | F_LODRBPARITYERROR | \
1275 F_HIDRBPARITYERROR | F_LORCQPARITYERROR | \
1276 F_HIRCQPARITYERROR)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001277#define MC5_INTR_MASK (F_PARITYERR | F_ACTRGNFULL | F_UNKNOWNCMD | \
1278 F_REQQPARERR | F_DISPQPARERR | F_DELACTEMPTY | \
1279 F_NFASRCHFAIL)
1280#define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
1281#define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1282 V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
1283 F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
1284#define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
1285 F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
1286 F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
1287 F_DETCORECCERR | F_DETUNCECCERR | F_PIOPARERR | \
1288 V_WFPARERR(M_WFPARERR) | V_RFPARERR(M_RFPARERR) | \
1289 V_CFPARERR(M_CFPARERR) /* | V_MSIXPARERR(M_MSIXPARERR) */)
1290#define PCIE_INTR_MASK (F_UNXSPLCPLERRR | F_UNXSPLCPLERRC | F_PCIE_PIOPARERR |\
1291 F_PCIE_WFPARERR | F_PCIE_RFPARERR | F_PCIE_CFPARERR | \
1292 /* V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR) | */ \
Divy Le Rayb8819552007-12-17 18:47:31 -08001293 F_RETRYBUFPARERR | F_RETRYLUTPARERR | F_RXPARERR | \
1294 F_TXPARERR | V_BISTERR(M_BISTERR))
1295#define ULPRX_INTR_MASK (F_PARERRDATA | F_PARERRPCMD | F_ARBPF1PERR | \
1296 F_ARBPF0PERR | F_ARBFPERR | F_PCMDMUXPERR | \
1297 F_DATASELFRAMEERR1 | F_DATASELFRAMEERR0)
1298#define ULPTX_INTR_MASK 0xfc
1299#define CPLSW_INTR_MASK (F_CIM_OP_MAP_PERR | F_TP_FRAMING_ERROR | \
Divy Le Ray4d22de32007-01-18 22:04:14 -05001300 F_SGE_FRAMING_ERROR | F_CIM_FRAMING_ERROR | \
1301 F_ZERO_SWITCH_ERROR)
1302#define CIM_INTR_MASK (F_BLKWRPLINT | F_BLKRDPLINT | F_BLKWRCTLINT | \
1303 F_BLKRDCTLINT | F_BLKWRFLASHINT | F_BLKRDFLASHINT | \
1304 F_SGLWRFLASHINT | F_WRBLKFLASHINT | F_BLKWRBOOTINT | \
Divy Le Rayb8819552007-12-17 18:47:31 -08001305 F_FLASHRANGEINT | F_SDRAMRANGEINT | F_RSVDSPACEINT | \
1306 F_DRAMPARERR | F_ICACHEPARERR | F_DCACHEPARERR | \
1307 F_OBQSGEPARERR | F_OBQULPHIPARERR | F_OBQULPLOPARERR | \
1308 F_IBQSGELOPARERR | F_IBQSGEHIPARERR | F_IBQULPPARERR | \
1309 F_IBQTPPARERR | F_ITAGPARERR | F_DTAGPARERR)
Divy Le Ray4d22de32007-01-18 22:04:14 -05001310#define PMTX_INTR_MASK (F_ZERO_C_CMD_ERROR | ICSPI_FRM_ERR | OESPI_FRM_ERR | \
1311 V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR) | \
1312 V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR))
1313#define PMRX_INTR_MASK (F_ZERO_E_CMD_ERROR | IESPI_FRM_ERR | OCSPI_FRM_ERR | \
1314 V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR) | \
1315 V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR))
1316#define MPS_INTR_MASK (V_TX0TPPARERRENB(M_TX0TPPARERRENB) | \
1317 V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
1318 V_RXTPPARERRENB(M_RXTPPARERRENB) | \
1319 V_MCAPARERRENB(M_MCAPARERRENB))
1320#define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
1321 F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
1322 F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
1323 F_MPS0 | F_CPL_SWITCH)
1324
1325/*
1326 * Interrupt handler for the PCIX1 module.
1327 */
1328static void pci_intr_handler(struct adapter *adapter)
1329{
1330 static const struct intr_info pcix1_intr_info[] = {
Divy Le Ray4d22de32007-01-18 22:04:14 -05001331 {F_MSTDETPARERR, "PCI master detected parity error", -1, 1},
1332 {F_SIGTARABT, "PCI signaled target abort", -1, 1},
1333 {F_RCVTARABT, "PCI received target abort", -1, 1},
1334 {F_RCVMSTABT, "PCI received master abort", -1, 1},
1335 {F_SIGSYSERR, "PCI signaled system error", -1, 1},
1336 {F_DETPARERR, "PCI detected parity error", -1, 1},
1337 {F_SPLCMPDIS, "PCI split completion discarded", -1, 1},
1338 {F_UNXSPLCMP, "PCI unexpected split completion error", -1, 1},
1339 {F_RCVSPLCMPERR, "PCI received split completion error", -1,
1340 1},
1341 {F_DETCORECCERR, "PCI correctable ECC error",
1342 STAT_PCI_CORR_ECC, 0},
1343 {F_DETUNCECCERR, "PCI uncorrectable ECC error", -1, 1},
1344 {F_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
1345 {V_WFPARERR(M_WFPARERR), "PCI write FIFO parity error", -1,
1346 1},
1347 {V_RFPARERR(M_RFPARERR), "PCI read FIFO parity error", -1,
1348 1},
1349 {V_CFPARERR(M_CFPARERR), "PCI command FIFO parity error", -1,
1350 1},
1351 {V_MSIXPARERR(M_MSIXPARERR), "PCI MSI-X table/PBA parity "
1352 "error", -1, 1},
1353 {0}
1354 };
1355
1356 if (t3_handle_intr_status(adapter, A_PCIX_INT_CAUSE, PCIX_INTR_MASK,
1357 pcix1_intr_info, adapter->irq_stats))
1358 t3_fatal_err(adapter);
1359}
1360
1361/*
1362 * Interrupt handler for the PCIE module.
1363 */
1364static void pcie_intr_handler(struct adapter *adapter)
1365{
1366 static const struct intr_info pcie_intr_info[] = {
Divy Le Rayb5a44bc2007-01-30 19:44:01 -08001367 {F_PEXERR, "PCI PEX error", -1, 1},
Divy Le Ray4d22de32007-01-18 22:04:14 -05001368 {F_UNXSPLCPLERRR,
1369 "PCI unexpected split completion DMA read error", -1, 1},
1370 {F_UNXSPLCPLERRC,
1371 "PCI unexpected split completion DMA command error", -1, 1},
1372 {F_PCIE_PIOPARERR, "PCI PIO FIFO parity error", -1, 1},
1373 {F_PCIE_WFPARERR, "PCI write FIFO parity error", -1, 1},
1374 {F_PCIE_RFPARERR, "PCI read FIFO parity error", -1, 1},
1375 {F_PCIE_CFPARERR, "PCI command FIFO parity error", -1, 1},
1376 {V_PCIE_MSIXPARERR(M_PCIE_MSIXPARERR),
1377 "PCI MSI-X table/PBA parity error", -1, 1},
Divy Le Rayb8819552007-12-17 18:47:31 -08001378 {F_RETRYBUFPARERR, "PCI retry buffer parity error", -1, 1},
1379 {F_RETRYLUTPARERR, "PCI retry LUT parity error", -1, 1},
1380 {F_RXPARERR, "PCI Rx parity error", -1, 1},
1381 {F_TXPARERR, "PCI Tx parity error", -1, 1},
Divy Le Ray4d22de32007-01-18 22:04:14 -05001382 {V_BISTERR(M_BISTERR), "PCI BIST error", -1, 1},
1383 {0}
1384 };
1385
Divy Le Ray3eea3332007-09-05 15:58:15 -07001386 if (t3_read_reg(adapter, A_PCIE_INT_CAUSE) & F_PEXERR)
1387 CH_ALERT(adapter, "PEX error code 0x%x\n",
1388 t3_read_reg(adapter, A_PCIE_PEX_ERR));
1389
Divy Le Ray4d22de32007-01-18 22:04:14 -05001390 if (t3_handle_intr_status(adapter, A_PCIE_INT_CAUSE, PCIE_INTR_MASK,
1391 pcie_intr_info, adapter->irq_stats))
1392 t3_fatal_err(adapter);
1393}
1394
1395/*
1396 * TP interrupt handler.
1397 */
1398static void tp_intr_handler(struct adapter *adapter)
1399{
1400 static const struct intr_info tp_intr_info[] = {
1401 {0xffffff, "TP parity error", -1, 1},
1402 {0x1000000, "TP out of Rx pages", -1, 1},
1403 {0x2000000, "TP out of Tx pages", -1, 1},
1404 {0}
1405 };
1406
Divy Le Raya2604be2007-11-16 11:22:16 -08001407 static struct intr_info tp_intr_info_t3c[] = {
Divy Le Rayb8819552007-12-17 18:47:31 -08001408 {0x1fffffff, "TP parity error", -1, 1},
1409 {F_FLMRXFLSTEMPTY, "TP out of Rx pages", -1, 1},
1410 {F_FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1},
1411 {0}
Divy Le Raya2604be2007-11-16 11:22:16 -08001412 };
1413
Divy Le Ray4d22de32007-01-18 22:04:14 -05001414 if (t3_handle_intr_status(adapter, A_TP_INT_CAUSE, 0xffffffff,
Divy Le Raya2604be2007-11-16 11:22:16 -08001415 adapter->params.rev < T3_REV_C ?
Divy Le Rayb8819552007-12-17 18:47:31 -08001416 tp_intr_info : tp_intr_info_t3c, NULL))
Divy Le Ray4d22de32007-01-18 22:04:14 -05001417 t3_fatal_err(adapter);
1418}
1419
1420/*
1421 * CIM interrupt handler.
1422 */
1423static void cim_intr_handler(struct adapter *adapter)
1424{
1425 static const struct intr_info cim_intr_info[] = {
1426 {F_RSVDSPACEINT, "CIM reserved space write", -1, 1},
1427 {F_SDRAMRANGEINT, "CIM SDRAM address out of range", -1, 1},
1428 {F_FLASHRANGEINT, "CIM flash address out of range", -1, 1},
1429 {F_BLKWRBOOTINT, "CIM block write to boot space", -1, 1},
1430 {F_WRBLKFLASHINT, "CIM write to cached flash space", -1, 1},
1431 {F_SGLWRFLASHINT, "CIM single write to flash space", -1, 1},
1432 {F_BLKRDFLASHINT, "CIM block read from flash space", -1, 1},
1433 {F_BLKWRFLASHINT, "CIM block write to flash space", -1, 1},
1434 {F_BLKRDCTLINT, "CIM block read from CTL space", -1, 1},
1435 {F_BLKWRCTLINT, "CIM block write to CTL space", -1, 1},
1436 {F_BLKRDPLINT, "CIM block read from PL space", -1, 1},
1437 {F_BLKWRPLINT, "CIM block write to PL space", -1, 1},
Divy Le Rayb8819552007-12-17 18:47:31 -08001438 {F_DRAMPARERR, "CIM DRAM parity error", -1, 1},
1439 {F_ICACHEPARERR, "CIM icache parity error", -1, 1},
1440 {F_DCACHEPARERR, "CIM dcache parity error", -1, 1},
1441 {F_OBQSGEPARERR, "CIM OBQ SGE parity error", -1, 1},
1442 {F_OBQULPHIPARERR, "CIM OBQ ULPHI parity error", -1, 1},
1443 {F_OBQULPLOPARERR, "CIM OBQ ULPLO parity error", -1, 1},
1444 {F_IBQSGELOPARERR, "CIM IBQ SGELO parity error", -1, 1},
1445 {F_IBQSGEHIPARERR, "CIM IBQ SGEHI parity error", -1, 1},
1446 {F_IBQULPPARERR, "CIM IBQ ULP parity error", -1, 1},
1447 {F_IBQTPPARERR, "CIM IBQ TP parity error", -1, 1},
1448 {F_ITAGPARERR, "CIM itag parity error", -1, 1},
1449 {F_DTAGPARERR, "CIM dtag parity error", -1, 1},
Divy Le Ray4d22de32007-01-18 22:04:14 -05001450 {0}
1451 };
1452
1453 if (t3_handle_intr_status(adapter, A_CIM_HOST_INT_CAUSE, 0xffffffff,
1454 cim_intr_info, NULL))
1455 t3_fatal_err(adapter);
1456}
1457
1458/*
1459 * ULP RX interrupt handler.
1460 */
1461static void ulprx_intr_handler(struct adapter *adapter)
1462{
1463 static const struct intr_info ulprx_intr_info[] = {
Divy Le Rayb8819552007-12-17 18:47:31 -08001464 {F_PARERRDATA, "ULP RX data parity error", -1, 1},
1465 {F_PARERRPCMD, "ULP RX command parity error", -1, 1},
1466 {F_ARBPF1PERR, "ULP RX ArbPF1 parity error", -1, 1},
1467 {F_ARBPF0PERR, "ULP RX ArbPF0 parity error", -1, 1},
1468 {F_ARBFPERR, "ULP RX ArbF parity error", -1, 1},
1469 {F_PCMDMUXPERR, "ULP RX PCMDMUX parity error", -1, 1},
1470 {F_DATASELFRAMEERR1, "ULP RX frame error", -1, 1},
1471 {F_DATASELFRAMEERR0, "ULP RX frame error", -1, 1},
Divy Le Ray4d22de32007-01-18 22:04:14 -05001472 {0}
1473 };
1474
1475 if (t3_handle_intr_status(adapter, A_ULPRX_INT_CAUSE, 0xffffffff,
1476 ulprx_intr_info, NULL))
1477 t3_fatal_err(adapter);
1478}
1479
1480/*
1481 * ULP TX interrupt handler.
1482 */
1483static void ulptx_intr_handler(struct adapter *adapter)
1484{
1485 static const struct intr_info ulptx_intr_info[] = {
1486 {F_PBL_BOUND_ERR_CH0, "ULP TX channel 0 PBL out of bounds",
1487 STAT_ULP_CH0_PBL_OOB, 0},
1488 {F_PBL_BOUND_ERR_CH1, "ULP TX channel 1 PBL out of bounds",
1489 STAT_ULP_CH1_PBL_OOB, 0},
Divy Le Rayb8819552007-12-17 18:47:31 -08001490 {0xfc, "ULP TX parity error", -1, 1},
Divy Le Ray4d22de32007-01-18 22:04:14 -05001491 {0}
1492 };
1493
1494 if (t3_handle_intr_status(adapter, A_ULPTX_INT_CAUSE, 0xffffffff,
1495 ulptx_intr_info, adapter->irq_stats))
1496 t3_fatal_err(adapter);
1497}
1498
1499#define ICSPI_FRM_ERR (F_ICSPI0_FIFO2X_RX_FRAMING_ERROR | \
1500 F_ICSPI1_FIFO2X_RX_FRAMING_ERROR | F_ICSPI0_RX_FRAMING_ERROR | \
1501 F_ICSPI1_RX_FRAMING_ERROR | F_ICSPI0_TX_FRAMING_ERROR | \
1502 F_ICSPI1_TX_FRAMING_ERROR)
1503#define OESPI_FRM_ERR (F_OESPI0_RX_FRAMING_ERROR | \
1504 F_OESPI1_RX_FRAMING_ERROR | F_OESPI0_TX_FRAMING_ERROR | \
1505 F_OESPI1_TX_FRAMING_ERROR | F_OESPI0_OFIFO2X_TX_FRAMING_ERROR | \
1506 F_OESPI1_OFIFO2X_TX_FRAMING_ERROR)
1507
1508/*
1509 * PM TX interrupt handler.
1510 */
1511static void pmtx_intr_handler(struct adapter *adapter)
1512{
1513 static const struct intr_info pmtx_intr_info[] = {
1514 {F_ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1},
1515 {ICSPI_FRM_ERR, "PMTX ispi framing error", -1, 1},
1516 {OESPI_FRM_ERR, "PMTX ospi framing error", -1, 1},
1517 {V_ICSPI_PAR_ERROR(M_ICSPI_PAR_ERROR),
1518 "PMTX ispi parity error", -1, 1},
1519 {V_OESPI_PAR_ERROR(M_OESPI_PAR_ERROR),
1520 "PMTX ospi parity error", -1, 1},
1521 {0}
1522 };
1523
1524 if (t3_handle_intr_status(adapter, A_PM1_TX_INT_CAUSE, 0xffffffff,
1525 pmtx_intr_info, NULL))
1526 t3_fatal_err(adapter);
1527}
1528
1529#define IESPI_FRM_ERR (F_IESPI0_FIFO2X_RX_FRAMING_ERROR | \
1530 F_IESPI1_FIFO2X_RX_FRAMING_ERROR | F_IESPI0_RX_FRAMING_ERROR | \
1531 F_IESPI1_RX_FRAMING_ERROR | F_IESPI0_TX_FRAMING_ERROR | \
1532 F_IESPI1_TX_FRAMING_ERROR)
1533#define OCSPI_FRM_ERR (F_OCSPI0_RX_FRAMING_ERROR | \
1534 F_OCSPI1_RX_FRAMING_ERROR | F_OCSPI0_TX_FRAMING_ERROR | \
1535 F_OCSPI1_TX_FRAMING_ERROR | F_OCSPI0_OFIFO2X_TX_FRAMING_ERROR | \
1536 F_OCSPI1_OFIFO2X_TX_FRAMING_ERROR)
1537
1538/*
1539 * PM RX interrupt handler.
1540 */
1541static void pmrx_intr_handler(struct adapter *adapter)
1542{
1543 static const struct intr_info pmrx_intr_info[] = {
1544 {F_ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1},
1545 {IESPI_FRM_ERR, "PMRX ispi framing error", -1, 1},
1546 {OCSPI_FRM_ERR, "PMRX ospi framing error", -1, 1},
1547 {V_IESPI_PAR_ERROR(M_IESPI_PAR_ERROR),
1548 "PMRX ispi parity error", -1, 1},
1549 {V_OCSPI_PAR_ERROR(M_OCSPI_PAR_ERROR),
1550 "PMRX ospi parity error", -1, 1},
1551 {0}
1552 };
1553
1554 if (t3_handle_intr_status(adapter, A_PM1_RX_INT_CAUSE, 0xffffffff,
1555 pmrx_intr_info, NULL))
1556 t3_fatal_err(adapter);
1557}
1558
1559/*
1560 * CPL switch interrupt handler.
1561 */
1562static void cplsw_intr_handler(struct adapter *adapter)
1563{
1564 static const struct intr_info cplsw_intr_info[] = {
Divy Le Rayb8819552007-12-17 18:47:31 -08001565 {F_CIM_OP_MAP_PERR, "CPL switch CIM parity error", -1, 1},
1566 {F_CIM_OVFL_ERROR, "CPL switch CIM overflow", -1, 1},
Divy Le Ray4d22de32007-01-18 22:04:14 -05001567 {F_TP_FRAMING_ERROR, "CPL switch TP framing error", -1, 1},
1568 {F_SGE_FRAMING_ERROR, "CPL switch SGE framing error", -1, 1},
1569 {F_CIM_FRAMING_ERROR, "CPL switch CIM framing error", -1, 1},
1570 {F_ZERO_SWITCH_ERROR, "CPL switch no-switch error", -1, 1},
1571 {0}
1572 };
1573
1574 if (t3_handle_intr_status(adapter, A_CPL_INTR_CAUSE, 0xffffffff,
1575 cplsw_intr_info, NULL))
1576 t3_fatal_err(adapter);
1577}
1578
1579/*
1580 * MPS interrupt handler.
1581 */
1582static void mps_intr_handler(struct adapter *adapter)
1583{
1584 static const struct intr_info mps_intr_info[] = {
1585 {0x1ff, "MPS parity error", -1, 1},
1586 {0}
1587 };
1588
1589 if (t3_handle_intr_status(adapter, A_MPS_INT_CAUSE, 0xffffffff,
1590 mps_intr_info, NULL))
1591 t3_fatal_err(adapter);
1592}
1593
1594#define MC7_INTR_FATAL (F_UE | V_PE(M_PE) | F_AE)
1595
1596/*
1597 * MC7 interrupt handler.
1598 */
1599static void mc7_intr_handler(struct mc7 *mc7)
1600{
1601 struct adapter *adapter = mc7->adapter;
1602 u32 cause = t3_read_reg(adapter, mc7->offset + A_MC7_INT_CAUSE);
1603
1604 if (cause & F_CE) {
1605 mc7->stats.corr_err++;
1606 CH_WARN(adapter, "%s MC7 correctable error at addr 0x%x, "
1607 "data 0x%x 0x%x 0x%x\n", mc7->name,
1608 t3_read_reg(adapter, mc7->offset + A_MC7_CE_ADDR),
1609 t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA0),
1610 t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA1),
1611 t3_read_reg(adapter, mc7->offset + A_MC7_CE_DATA2));
1612 }
1613
1614 if (cause & F_UE) {
1615 mc7->stats.uncorr_err++;
1616 CH_ALERT(adapter, "%s MC7 uncorrectable error at addr 0x%x, "
1617 "data 0x%x 0x%x 0x%x\n", mc7->name,
1618 t3_read_reg(adapter, mc7->offset + A_MC7_UE_ADDR),
1619 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA0),
1620 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA1),
1621 t3_read_reg(adapter, mc7->offset + A_MC7_UE_DATA2));
1622 }
1623
1624 if (G_PE(cause)) {
1625 mc7->stats.parity_err++;
1626 CH_ALERT(adapter, "%s MC7 parity error 0x%x\n",
1627 mc7->name, G_PE(cause));
1628 }
1629
1630 if (cause & F_AE) {
1631 u32 addr = 0;
1632
1633 if (adapter->params.rev > 0)
1634 addr = t3_read_reg(adapter,
1635 mc7->offset + A_MC7_ERR_ADDR);
1636 mc7->stats.addr_err++;
1637 CH_ALERT(adapter, "%s MC7 address error: 0x%x\n",
1638 mc7->name, addr);
1639 }
1640
1641 if (cause & MC7_INTR_FATAL)
1642 t3_fatal_err(adapter);
1643
1644 t3_write_reg(adapter, mc7->offset + A_MC7_INT_CAUSE, cause);
1645}
1646
1647#define XGM_INTR_FATAL (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
1648 V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR))
1649/*
1650 * XGMAC interrupt handler.
1651 */
1652static int mac_intr_handler(struct adapter *adap, unsigned int idx)
1653{
1654 struct cmac *mac = &adap2pinfo(adap, idx)->mac;
1655 u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
1656
1657 if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
1658 mac->stats.tx_fifo_parity_err++;
1659 CH_ALERT(adap, "port%d: MAC TX FIFO parity error\n", idx);
1660 }
1661 if (cause & V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR)) {
1662 mac->stats.rx_fifo_parity_err++;
1663 CH_ALERT(adap, "port%d: MAC RX FIFO parity error\n", idx);
1664 }
1665 if (cause & F_TXFIFO_UNDERRUN)
1666 mac->stats.tx_fifo_urun++;
1667 if (cause & F_RXFIFO_OVERFLOW)
1668 mac->stats.rx_fifo_ovfl++;
1669 if (cause & V_SERDES_LOS(M_SERDES_LOS))
1670 mac->stats.serdes_signal_loss++;
1671 if (cause & F_XAUIPCSCTCERR)
1672 mac->stats.xaui_pcs_ctc_err++;
1673 if (cause & F_XAUIPCSALIGNCHANGE)
1674 mac->stats.xaui_pcs_align_change++;
1675
1676 t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
1677 if (cause & XGM_INTR_FATAL)
1678 t3_fatal_err(adap);
1679 return cause != 0;
1680}
1681
1682/*
1683 * Interrupt handler for PHY events.
1684 */
1685int t3_phy_intr_handler(struct adapter *adapter)
1686{
Divy Le Ray1ca03cb2007-04-17 11:06:36 -07001687 u32 mask, gpi = adapter_info(adapter)->gpio_intr;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001688 u32 i, cause = t3_read_reg(adapter, A_T3DBG_INT_CAUSE);
1689
1690 for_each_port(adapter, i) {
Divy Le Ray1ca03cb2007-04-17 11:06:36 -07001691 struct port_info *p = adap2pinfo(adapter, i);
1692
1693 mask = gpi - (gpi & (gpi - 1));
1694 gpi -= mask;
1695
Divy Le Ray04497982008-10-08 17:38:29 -07001696 if (!(p->phy.caps & SUPPORTED_IRQ))
Divy Le Ray1ca03cb2007-04-17 11:06:36 -07001697 continue;
1698
1699 if (cause & mask) {
1700 int phy_cause = p->phy.ops->intr_handler(&p->phy);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001701
1702 if (phy_cause & cphy_cause_link_change)
1703 t3_link_changed(adapter, i);
1704 if (phy_cause & cphy_cause_fifo_error)
Divy Le Ray1ca03cb2007-04-17 11:06:36 -07001705 p->phy.fifo_errors++;
Divy Le Ray4d22de32007-01-18 22:04:14 -05001706 }
1707 }
1708
1709 t3_write_reg(adapter, A_T3DBG_INT_CAUSE, cause);
1710 return 0;
1711}
1712
1713/*
1714 * T3 slow path (non-data) interrupt handler.
1715 */
1716int t3_slow_intr_handler(struct adapter *adapter)
1717{
1718 u32 cause = t3_read_reg(adapter, A_PL_INT_CAUSE0);
1719
1720 cause &= adapter->slow_intr_mask;
1721 if (!cause)
1722 return 0;
1723 if (cause & F_PCIM0) {
1724 if (is_pcie(adapter))
1725 pcie_intr_handler(adapter);
1726 else
1727 pci_intr_handler(adapter);
1728 }
1729 if (cause & F_SGE3)
1730 t3_sge_err_intr_handler(adapter);
1731 if (cause & F_MC7_PMRX)
1732 mc7_intr_handler(&adapter->pmrx);
1733 if (cause & F_MC7_PMTX)
1734 mc7_intr_handler(&adapter->pmtx);
1735 if (cause & F_MC7_CM)
1736 mc7_intr_handler(&adapter->cm);
1737 if (cause & F_CIM)
1738 cim_intr_handler(adapter);
1739 if (cause & F_TP1)
1740 tp_intr_handler(adapter);
1741 if (cause & F_ULP2_RX)
1742 ulprx_intr_handler(adapter);
1743 if (cause & F_ULP2_TX)
1744 ulptx_intr_handler(adapter);
1745 if (cause & F_PM1_RX)
1746 pmrx_intr_handler(adapter);
1747 if (cause & F_PM1_TX)
1748 pmtx_intr_handler(adapter);
1749 if (cause & F_CPL_SWITCH)
1750 cplsw_intr_handler(adapter);
1751 if (cause & F_MPS0)
1752 mps_intr_handler(adapter);
1753 if (cause & F_MC5A)
1754 t3_mc5_intr_handler(&adapter->mc5);
1755 if (cause & F_XGMAC0_0)
1756 mac_intr_handler(adapter, 0);
1757 if (cause & F_XGMAC0_1)
1758 mac_intr_handler(adapter, 1);
1759 if (cause & F_T3DBG)
1760 t3_os_ext_intr_handler(adapter);
1761
1762 /* Clear the interrupts just processed. */
1763 t3_write_reg(adapter, A_PL_INT_CAUSE0, cause);
1764 t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
1765 return 1;
1766}
1767
1768/**
1769 * t3_intr_enable - enable interrupts
1770 * @adapter: the adapter whose interrupts should be enabled
1771 *
1772 * Enable interrupts by setting the interrupt enable registers of the
1773 * various HW modules and then enabling the top-level interrupt
1774 * concentrator.
1775 */
1776void t3_intr_enable(struct adapter *adapter)
1777{
1778 static const struct addr_val_pair intr_en_avp[] = {
1779 {A_SG_INT_ENABLE, SGE_INTR_MASK},
1780 {A_MC7_INT_ENABLE, MC7_INTR_MASK},
1781 {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
1782 MC7_INTR_MASK},
1783 {A_MC7_INT_ENABLE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
1784 MC7_INTR_MASK},
1785 {A_MC5_DB_INT_ENABLE, MC5_INTR_MASK},
1786 {A_ULPRX_INT_ENABLE, ULPRX_INTR_MASK},
Divy Le Ray4d22de32007-01-18 22:04:14 -05001787 {A_PM1_TX_INT_ENABLE, PMTX_INTR_MASK},
1788 {A_PM1_RX_INT_ENABLE, PMRX_INTR_MASK},
1789 {A_CIM_HOST_INT_ENABLE, CIM_INTR_MASK},
1790 {A_MPS_INT_ENABLE, MPS_INTR_MASK},
1791 };
1792
1793 adapter->slow_intr_mask = PL_INTR_MASK;
1794
1795 t3_write_regs(adapter, intr_en_avp, ARRAY_SIZE(intr_en_avp), 0);
Divy Le Raya2604be2007-11-16 11:22:16 -08001796 t3_write_reg(adapter, A_TP_INT_ENABLE,
1797 adapter->params.rev >= T3_REV_C ? 0x2bfffff : 0x3bfffff);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001798
1799 if (adapter->params.rev > 0) {
1800 t3_write_reg(adapter, A_CPL_INTR_ENABLE,
1801 CPLSW_INTR_MASK | F_CIM_OVFL_ERROR);
1802 t3_write_reg(adapter, A_ULPTX_INT_ENABLE,
1803 ULPTX_INTR_MASK | F_PBL_BOUND_ERR_CH0 |
1804 F_PBL_BOUND_ERR_CH1);
1805 } else {
1806 t3_write_reg(adapter, A_CPL_INTR_ENABLE, CPLSW_INTR_MASK);
1807 t3_write_reg(adapter, A_ULPTX_INT_ENABLE, ULPTX_INTR_MASK);
1808 }
1809
1810 t3_write_reg(adapter, A_T3DBG_GPIO_ACT_LOW,
1811 adapter_info(adapter)->gpio_intr);
1812 t3_write_reg(adapter, A_T3DBG_INT_ENABLE,
1813 adapter_info(adapter)->gpio_intr);
1814 if (is_pcie(adapter))
1815 t3_write_reg(adapter, A_PCIE_INT_ENABLE, PCIE_INTR_MASK);
1816 else
1817 t3_write_reg(adapter, A_PCIX_INT_ENABLE, PCIX_INTR_MASK);
1818 t3_write_reg(adapter, A_PL_INT_ENABLE0, adapter->slow_intr_mask);
1819 t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
1820}
1821
1822/**
1823 * t3_intr_disable - disable a card's interrupts
1824 * @adapter: the adapter whose interrupts should be disabled
1825 *
1826 * Disable interrupts. We only disable the top-level interrupt
1827 * concentrator and the SGE data interrupts.
1828 */
1829void t3_intr_disable(struct adapter *adapter)
1830{
1831 t3_write_reg(adapter, A_PL_INT_ENABLE0, 0);
1832 t3_read_reg(adapter, A_PL_INT_ENABLE0); /* flush */
1833 adapter->slow_intr_mask = 0;
1834}
1835
1836/**
1837 * t3_intr_clear - clear all interrupts
1838 * @adapter: the adapter whose interrupts should be cleared
1839 *
1840 * Clears all interrupts.
1841 */
1842void t3_intr_clear(struct adapter *adapter)
1843{
1844 static const unsigned int cause_reg_addr[] = {
1845 A_SG_INT_CAUSE,
1846 A_SG_RSPQ_FL_STATUS,
1847 A_PCIX_INT_CAUSE,
1848 A_MC7_INT_CAUSE,
1849 A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_PMTX_BASE_ADDR,
1850 A_MC7_INT_CAUSE - MC7_PMRX_BASE_ADDR + MC7_CM_BASE_ADDR,
1851 A_CIM_HOST_INT_CAUSE,
1852 A_TP_INT_CAUSE,
1853 A_MC5_DB_INT_CAUSE,
1854 A_ULPRX_INT_CAUSE,
1855 A_ULPTX_INT_CAUSE,
1856 A_CPL_INTR_CAUSE,
1857 A_PM1_TX_INT_CAUSE,
1858 A_PM1_RX_INT_CAUSE,
1859 A_MPS_INT_CAUSE,
1860 A_T3DBG_INT_CAUSE,
1861 };
1862 unsigned int i;
1863
1864 /* Clear PHY and MAC interrupts for each port. */
1865 for_each_port(adapter, i)
1866 t3_port_intr_clear(adapter, i);
1867
1868 for (i = 0; i < ARRAY_SIZE(cause_reg_addr); ++i)
1869 t3_write_reg(adapter, cause_reg_addr[i], 0xffffffff);
1870
Divy Le Ray3eea3332007-09-05 15:58:15 -07001871 if (is_pcie(adapter))
1872 t3_write_reg(adapter, A_PCIE_PEX_ERR, 0xffffffff);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001873 t3_write_reg(adapter, A_PL_INT_CAUSE0, 0xffffffff);
1874 t3_read_reg(adapter, A_PL_INT_CAUSE0); /* flush */
1875}
1876
1877/**
1878 * t3_port_intr_enable - enable port-specific interrupts
1879 * @adapter: associated adapter
1880 * @idx: index of port whose interrupts should be enabled
1881 *
1882 * Enable port-specific (i.e., MAC and PHY) interrupts for the given
1883 * adapter port.
1884 */
1885void t3_port_intr_enable(struct adapter *adapter, int idx)
1886{
1887 struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
1888
1889 t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), XGM_INTR_MASK);
1890 t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
1891 phy->ops->intr_enable(phy);
1892}
1893
1894/**
1895 * t3_port_intr_disable - disable port-specific interrupts
1896 * @adapter: associated adapter
1897 * @idx: index of port whose interrupts should be disabled
1898 *
1899 * Disable port-specific (i.e., MAC and PHY) interrupts for the given
1900 * adapter port.
1901 */
1902void t3_port_intr_disable(struct adapter *adapter, int idx)
1903{
1904 struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
1905
1906 t3_write_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx), 0);
1907 t3_read_reg(adapter, XGM_REG(A_XGM_INT_ENABLE, idx)); /* flush */
1908 phy->ops->intr_disable(phy);
1909}
1910
1911/**
1912 * t3_port_intr_clear - clear port-specific interrupts
1913 * @adapter: associated adapter
1914 * @idx: index of port whose interrupts to clear
1915 *
1916 * Clear port-specific (i.e., MAC and PHY) interrupts for the given
1917 * adapter port.
1918 */
1919void t3_port_intr_clear(struct adapter *adapter, int idx)
1920{
1921 struct cphy *phy = &adap2pinfo(adapter, idx)->phy;
1922
1923 t3_write_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx), 0xffffffff);
1924 t3_read_reg(adapter, XGM_REG(A_XGM_INT_CAUSE, idx)); /* flush */
1925 phy->ops->intr_clear(phy);
1926}
1927
Divy Le Raybb9366a2007-09-05 15:58:30 -07001928#define SG_CONTEXT_CMD_ATTEMPTS 100
1929
Divy Le Ray4d22de32007-01-18 22:04:14 -05001930/**
1931 * t3_sge_write_context - write an SGE context
1932 * @adapter: the adapter
1933 * @id: the context id
1934 * @type: the context type
1935 *
1936 * Program an SGE context with the values already loaded in the
1937 * CONTEXT_DATA? registers.
1938 */
1939static int t3_sge_write_context(struct adapter *adapter, unsigned int id,
1940 unsigned int type)
1941{
1942 t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0xffffffff);
1943 t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0xffffffff);
1944 t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0xffffffff);
1945 t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0xffffffff);
1946 t3_write_reg(adapter, A_SG_CONTEXT_CMD,
1947 V_CONTEXT_CMD_OPCODE(1) | type | V_CONTEXT(id));
1948 return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
Divy Le Raybb9366a2007-09-05 15:58:30 -07001949 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05001950}
1951
Divy Le Rayb8819552007-12-17 18:47:31 -08001952static int clear_sge_ctxt(struct adapter *adap, unsigned int id,
1953 unsigned int type)
1954{
1955 t3_write_reg(adap, A_SG_CONTEXT_DATA0, 0);
1956 t3_write_reg(adap, A_SG_CONTEXT_DATA1, 0);
1957 t3_write_reg(adap, A_SG_CONTEXT_DATA2, 0);
1958 t3_write_reg(adap, A_SG_CONTEXT_DATA3, 0);
1959 return t3_sge_write_context(adap, id, type);
1960}
1961
Divy Le Ray4d22de32007-01-18 22:04:14 -05001962/**
1963 * t3_sge_init_ecntxt - initialize an SGE egress context
1964 * @adapter: the adapter to configure
1965 * @id: the context id
1966 * @gts_enable: whether to enable GTS for the context
1967 * @type: the egress context type
1968 * @respq: associated response queue
1969 * @base_addr: base address of queue
1970 * @size: number of queue entries
1971 * @token: uP token
1972 * @gen: initial generation value for the context
1973 * @cidx: consumer pointer
1974 *
1975 * Initialize an SGE egress context and make it ready for use. If the
1976 * platform allows concurrent context operations, the caller is
1977 * responsible for appropriate locking.
1978 */
1979int t3_sge_init_ecntxt(struct adapter *adapter, unsigned int id, int gts_enable,
1980 enum sge_context_type type, int respq, u64 base_addr,
1981 unsigned int size, unsigned int token, int gen,
1982 unsigned int cidx)
1983{
1984 unsigned int credits = type == SGE_CNTXT_OFLD ? 0 : FW_WR_NUM;
1985
1986 if (base_addr & 0xfff) /* must be 4K aligned */
1987 return -EINVAL;
1988 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
1989 return -EBUSY;
1990
1991 base_addr >>= 12;
1992 t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_EC_INDEX(cidx) |
1993 V_EC_CREDITS(credits) | V_EC_GTS(gts_enable));
1994 t3_write_reg(adapter, A_SG_CONTEXT_DATA1, V_EC_SIZE(size) |
1995 V_EC_BASE_LO(base_addr & 0xffff));
1996 base_addr >>= 16;
1997 t3_write_reg(adapter, A_SG_CONTEXT_DATA2, base_addr);
1998 base_addr >>= 32;
1999 t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2000 V_EC_BASE_HI(base_addr & 0xf) | V_EC_RESPQ(respq) |
2001 V_EC_TYPE(type) | V_EC_GEN(gen) | V_EC_UP_TOKEN(token) |
2002 F_EC_VALID);
2003 return t3_sge_write_context(adapter, id, F_EGRESS);
2004}
2005
2006/**
2007 * t3_sge_init_flcntxt - initialize an SGE free-buffer list context
2008 * @adapter: the adapter to configure
2009 * @id: the context id
2010 * @gts_enable: whether to enable GTS for the context
2011 * @base_addr: base address of queue
2012 * @size: number of queue entries
2013 * @bsize: size of each buffer for this queue
2014 * @cong_thres: threshold to signal congestion to upstream producers
2015 * @gen: initial generation value for the context
2016 * @cidx: consumer pointer
2017 *
2018 * Initialize an SGE free list context and make it ready for use. The
2019 * caller is responsible for ensuring only one context operation occurs
2020 * at a time.
2021 */
2022int t3_sge_init_flcntxt(struct adapter *adapter, unsigned int id,
2023 int gts_enable, u64 base_addr, unsigned int size,
2024 unsigned int bsize, unsigned int cong_thres, int gen,
2025 unsigned int cidx)
2026{
2027 if (base_addr & 0xfff) /* must be 4K aligned */
2028 return -EINVAL;
2029 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2030 return -EBUSY;
2031
2032 base_addr >>= 12;
2033 t3_write_reg(adapter, A_SG_CONTEXT_DATA0, base_addr);
2034 base_addr >>= 32;
2035 t3_write_reg(adapter, A_SG_CONTEXT_DATA1,
2036 V_FL_BASE_HI((u32) base_addr) |
2037 V_FL_INDEX_LO(cidx & M_FL_INDEX_LO));
2038 t3_write_reg(adapter, A_SG_CONTEXT_DATA2, V_FL_SIZE(size) |
2039 V_FL_GEN(gen) | V_FL_INDEX_HI(cidx >> 12) |
2040 V_FL_ENTRY_SIZE_LO(bsize & M_FL_ENTRY_SIZE_LO));
2041 t3_write_reg(adapter, A_SG_CONTEXT_DATA3,
2042 V_FL_ENTRY_SIZE_HI(bsize >> (32 - S_FL_ENTRY_SIZE_LO)) |
2043 V_FL_CONG_THRES(cong_thres) | V_FL_GTS(gts_enable));
2044 return t3_sge_write_context(adapter, id, F_FREELIST);
2045}
2046
2047/**
2048 * t3_sge_init_rspcntxt - initialize an SGE response queue context
2049 * @adapter: the adapter to configure
2050 * @id: the context id
2051 * @irq_vec_idx: MSI-X interrupt vector index, 0 if no MSI-X, -1 if no IRQ
2052 * @base_addr: base address of queue
2053 * @size: number of queue entries
2054 * @fl_thres: threshold for selecting the normal or jumbo free list
2055 * @gen: initial generation value for the context
2056 * @cidx: consumer pointer
2057 *
2058 * Initialize an SGE response queue context and make it ready for use.
2059 * The caller is responsible for ensuring only one context operation
2060 * occurs at a time.
2061 */
2062int t3_sge_init_rspcntxt(struct adapter *adapter, unsigned int id,
2063 int irq_vec_idx, u64 base_addr, unsigned int size,
2064 unsigned int fl_thres, int gen, unsigned int cidx)
2065{
2066 unsigned int intr = 0;
2067
2068 if (base_addr & 0xfff) /* must be 4K aligned */
2069 return -EINVAL;
2070 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2071 return -EBUSY;
2072
2073 base_addr >>= 12;
2074 t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size) |
2075 V_CQ_INDEX(cidx));
2076 t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
2077 base_addr >>= 32;
2078 if (irq_vec_idx >= 0)
2079 intr = V_RQ_MSI_VEC(irq_vec_idx) | F_RQ_INTR_EN;
2080 t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2081 V_CQ_BASE_HI((u32) base_addr) | intr | V_RQ_GEN(gen));
2082 t3_write_reg(adapter, A_SG_CONTEXT_DATA3, fl_thres);
2083 return t3_sge_write_context(adapter, id, F_RESPONSEQ);
2084}
2085
2086/**
2087 * t3_sge_init_cqcntxt - initialize an SGE completion queue context
2088 * @adapter: the adapter to configure
2089 * @id: the context id
2090 * @base_addr: base address of queue
2091 * @size: number of queue entries
2092 * @rspq: response queue for async notifications
2093 * @ovfl_mode: CQ overflow mode
2094 * @credits: completion queue credits
2095 * @credit_thres: the credit threshold
2096 *
2097 * Initialize an SGE completion queue context and make it ready for use.
2098 * The caller is responsible for ensuring only one context operation
2099 * occurs at a time.
2100 */
2101int t3_sge_init_cqcntxt(struct adapter *adapter, unsigned int id, u64 base_addr,
2102 unsigned int size, int rspq, int ovfl_mode,
2103 unsigned int credits, unsigned int credit_thres)
2104{
2105 if (base_addr & 0xfff) /* must be 4K aligned */
2106 return -EINVAL;
2107 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2108 return -EBUSY;
2109
2110 base_addr >>= 12;
2111 t3_write_reg(adapter, A_SG_CONTEXT_DATA0, V_CQ_SIZE(size));
2112 t3_write_reg(adapter, A_SG_CONTEXT_DATA1, base_addr);
2113 base_addr >>= 32;
2114 t3_write_reg(adapter, A_SG_CONTEXT_DATA2,
2115 V_CQ_BASE_HI((u32) base_addr) | V_CQ_RSPQ(rspq) |
Divy Le Ray1c17ae82007-09-05 15:58:25 -07002116 V_CQ_GEN(1) | V_CQ_OVERFLOW_MODE(ovfl_mode) |
2117 V_CQ_ERR(ovfl_mode));
Divy Le Ray4d22de32007-01-18 22:04:14 -05002118 t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_CQ_CREDITS(credits) |
2119 V_CQ_CREDIT_THRES(credit_thres));
2120 return t3_sge_write_context(adapter, id, F_CQ);
2121}
2122
2123/**
2124 * t3_sge_enable_ecntxt - enable/disable an SGE egress context
2125 * @adapter: the adapter
2126 * @id: the egress context id
2127 * @enable: enable (1) or disable (0) the context
2128 *
2129 * Enable or disable an SGE egress context. The caller is responsible for
2130 * ensuring only one context operation occurs at a time.
2131 */
2132int t3_sge_enable_ecntxt(struct adapter *adapter, unsigned int id, int enable)
2133{
2134 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2135 return -EBUSY;
2136
2137 t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2138 t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2139 t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2140 t3_write_reg(adapter, A_SG_CONTEXT_MASK3, F_EC_VALID);
2141 t3_write_reg(adapter, A_SG_CONTEXT_DATA3, V_EC_VALID(enable));
2142 t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2143 V_CONTEXT_CMD_OPCODE(1) | F_EGRESS | V_CONTEXT(id));
2144 return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
Divy Le Raybb9366a2007-09-05 15:58:30 -07002145 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002146}
2147
2148/**
2149 * t3_sge_disable_fl - disable an SGE free-buffer list
2150 * @adapter: the adapter
2151 * @id: the free list context id
2152 *
2153 * Disable an SGE free-buffer list. The caller is responsible for
2154 * ensuring only one context operation occurs at a time.
2155 */
2156int t3_sge_disable_fl(struct adapter *adapter, unsigned int id)
2157{
2158 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2159 return -EBUSY;
2160
2161 t3_write_reg(adapter, A_SG_CONTEXT_MASK0, 0);
2162 t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2163 t3_write_reg(adapter, A_SG_CONTEXT_MASK2, V_FL_SIZE(M_FL_SIZE));
2164 t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2165 t3_write_reg(adapter, A_SG_CONTEXT_DATA2, 0);
2166 t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2167 V_CONTEXT_CMD_OPCODE(1) | F_FREELIST | V_CONTEXT(id));
2168 return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
Divy Le Raybb9366a2007-09-05 15:58:30 -07002169 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002170}
2171
2172/**
2173 * t3_sge_disable_rspcntxt - disable an SGE response queue
2174 * @adapter: the adapter
2175 * @id: the response queue context id
2176 *
2177 * Disable an SGE response queue. The caller is responsible for
2178 * ensuring only one context operation occurs at a time.
2179 */
2180int t3_sge_disable_rspcntxt(struct adapter *adapter, unsigned int id)
2181{
2182 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2183 return -EBUSY;
2184
2185 t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2186 t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2187 t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2188 t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2189 t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2190 t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2191 V_CONTEXT_CMD_OPCODE(1) | F_RESPONSEQ | V_CONTEXT(id));
2192 return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
Divy Le Raybb9366a2007-09-05 15:58:30 -07002193 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002194}
2195
2196/**
2197 * t3_sge_disable_cqcntxt - disable an SGE completion queue
2198 * @adapter: the adapter
2199 * @id: the completion queue context id
2200 *
2201 * Disable an SGE completion queue. The caller is responsible for
2202 * ensuring only one context operation occurs at a time.
2203 */
2204int t3_sge_disable_cqcntxt(struct adapter *adapter, unsigned int id)
2205{
2206 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2207 return -EBUSY;
2208
2209 t3_write_reg(adapter, A_SG_CONTEXT_MASK0, V_CQ_SIZE(M_CQ_SIZE));
2210 t3_write_reg(adapter, A_SG_CONTEXT_MASK1, 0);
2211 t3_write_reg(adapter, A_SG_CONTEXT_MASK2, 0);
2212 t3_write_reg(adapter, A_SG_CONTEXT_MASK3, 0);
2213 t3_write_reg(adapter, A_SG_CONTEXT_DATA0, 0);
2214 t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2215 V_CONTEXT_CMD_OPCODE(1) | F_CQ | V_CONTEXT(id));
2216 return t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
Divy Le Raybb9366a2007-09-05 15:58:30 -07002217 0, SG_CONTEXT_CMD_ATTEMPTS, 1);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002218}
2219
2220/**
2221 * t3_sge_cqcntxt_op - perform an operation on a completion queue context
2222 * @adapter: the adapter
2223 * @id: the context id
2224 * @op: the operation to perform
2225 *
2226 * Perform the selected operation on an SGE completion queue context.
2227 * The caller is responsible for ensuring only one context operation
2228 * occurs at a time.
2229 */
2230int t3_sge_cqcntxt_op(struct adapter *adapter, unsigned int id, unsigned int op,
2231 unsigned int credits)
2232{
2233 u32 val;
2234
2235 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2236 return -EBUSY;
2237
2238 t3_write_reg(adapter, A_SG_CONTEXT_DATA0, credits << 16);
2239 t3_write_reg(adapter, A_SG_CONTEXT_CMD, V_CONTEXT_CMD_OPCODE(op) |
2240 V_CONTEXT(id) | F_CQ);
2241 if (t3_wait_op_done_val(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY,
Divy Le Raybb9366a2007-09-05 15:58:30 -07002242 0, SG_CONTEXT_CMD_ATTEMPTS, 1, &val))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002243 return -EIO;
2244
2245 if (op >= 2 && op < 7) {
2246 if (adapter->params.rev > 0)
2247 return G_CQ_INDEX(val);
2248
2249 t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2250 V_CONTEXT_CMD_OPCODE(0) | F_CQ | V_CONTEXT(id));
2251 if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD,
Divy Le Raybb9366a2007-09-05 15:58:30 -07002252 F_CONTEXT_CMD_BUSY, 0,
2253 SG_CONTEXT_CMD_ATTEMPTS, 1))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002254 return -EIO;
2255 return G_CQ_INDEX(t3_read_reg(adapter, A_SG_CONTEXT_DATA0));
2256 }
2257 return 0;
2258}
2259
2260/**
2261 * t3_sge_read_context - read an SGE context
2262 * @type: the context type
2263 * @adapter: the adapter
2264 * @id: the context id
2265 * @data: holds the retrieved context
2266 *
2267 * Read an SGE egress context. The caller is responsible for ensuring
2268 * only one context operation occurs at a time.
2269 */
2270static int t3_sge_read_context(unsigned int type, struct adapter *adapter,
2271 unsigned int id, u32 data[4])
2272{
2273 if (t3_read_reg(adapter, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
2274 return -EBUSY;
2275
2276 t3_write_reg(adapter, A_SG_CONTEXT_CMD,
2277 V_CONTEXT_CMD_OPCODE(0) | type | V_CONTEXT(id));
2278 if (t3_wait_op_done(adapter, A_SG_CONTEXT_CMD, F_CONTEXT_CMD_BUSY, 0,
Divy Le Raybb9366a2007-09-05 15:58:30 -07002279 SG_CONTEXT_CMD_ATTEMPTS, 1))
Divy Le Ray4d22de32007-01-18 22:04:14 -05002280 return -EIO;
2281 data[0] = t3_read_reg(adapter, A_SG_CONTEXT_DATA0);
2282 data[1] = t3_read_reg(adapter, A_SG_CONTEXT_DATA1);
2283 data[2] = t3_read_reg(adapter, A_SG_CONTEXT_DATA2);
2284 data[3] = t3_read_reg(adapter, A_SG_CONTEXT_DATA3);
2285 return 0;
2286}
2287
2288/**
2289 * t3_sge_read_ecntxt - read an SGE egress context
2290 * @adapter: the adapter
2291 * @id: the context id
2292 * @data: holds the retrieved context
2293 *
2294 * Read an SGE egress context. The caller is responsible for ensuring
2295 * only one context operation occurs at a time.
2296 */
2297int t3_sge_read_ecntxt(struct adapter *adapter, unsigned int id, u32 data[4])
2298{
2299 if (id >= 65536)
2300 return -EINVAL;
2301 return t3_sge_read_context(F_EGRESS, adapter, id, data);
2302}
2303
2304/**
2305 * t3_sge_read_cq - read an SGE CQ context
2306 * @adapter: the adapter
2307 * @id: the context id
2308 * @data: holds the retrieved context
2309 *
2310 * Read an SGE CQ context. The caller is responsible for ensuring
2311 * only one context operation occurs at a time.
2312 */
2313int t3_sge_read_cq(struct adapter *adapter, unsigned int id, u32 data[4])
2314{
2315 if (id >= 65536)
2316 return -EINVAL;
2317 return t3_sge_read_context(F_CQ, adapter, id, data);
2318}
2319
2320/**
2321 * t3_sge_read_fl - read an SGE free-list context
2322 * @adapter: the adapter
2323 * @id: the context id
2324 * @data: holds the retrieved context
2325 *
2326 * Read an SGE free-list context. The caller is responsible for ensuring
2327 * only one context operation occurs at a time.
2328 */
2329int t3_sge_read_fl(struct adapter *adapter, unsigned int id, u32 data[4])
2330{
2331 if (id >= SGE_QSETS * 2)
2332 return -EINVAL;
2333 return t3_sge_read_context(F_FREELIST, adapter, id, data);
2334}
2335
2336/**
2337 * t3_sge_read_rspq - read an SGE response queue context
2338 * @adapter: the adapter
2339 * @id: the context id
2340 * @data: holds the retrieved context
2341 *
2342 * Read an SGE response queue context. The caller is responsible for
2343 * ensuring only one context operation occurs at a time.
2344 */
2345int t3_sge_read_rspq(struct adapter *adapter, unsigned int id, u32 data[4])
2346{
2347 if (id >= SGE_QSETS)
2348 return -EINVAL;
2349 return t3_sge_read_context(F_RESPONSEQ, adapter, id, data);
2350}
2351
2352/**
2353 * t3_config_rss - configure Rx packet steering
2354 * @adapter: the adapter
2355 * @rss_config: RSS settings (written to TP_RSS_CONFIG)
2356 * @cpus: values for the CPU lookup table (0xff terminated)
2357 * @rspq: values for the response queue lookup table (0xffff terminated)
2358 *
2359 * Programs the receive packet steering logic. @cpus and @rspq provide
2360 * the values for the CPU and response queue lookup tables. If they
2361 * provide fewer values than the size of the tables the supplied values
2362 * are used repeatedly until the tables are fully populated.
2363 */
2364void t3_config_rss(struct adapter *adapter, unsigned int rss_config,
2365 const u8 * cpus, const u16 *rspq)
2366{
2367 int i, j, cpu_idx = 0, q_idx = 0;
2368
2369 if (cpus)
2370 for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2371 u32 val = i << 16;
2372
2373 for (j = 0; j < 2; ++j) {
2374 val |= (cpus[cpu_idx++] & 0x3f) << (8 * j);
2375 if (cpus[cpu_idx] == 0xff)
2376 cpu_idx = 0;
2377 }
2378 t3_write_reg(adapter, A_TP_RSS_LKP_TABLE, val);
2379 }
2380
2381 if (rspq)
2382 for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2383 t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
2384 (i << 16) | rspq[q_idx++]);
2385 if (rspq[q_idx] == 0xffff)
2386 q_idx = 0;
2387 }
2388
2389 t3_write_reg(adapter, A_TP_RSS_CONFIG, rss_config);
2390}
2391
2392/**
2393 * t3_read_rss - read the contents of the RSS tables
2394 * @adapter: the adapter
2395 * @lkup: holds the contents of the RSS lookup table
2396 * @map: holds the contents of the RSS map table
2397 *
2398 * Reads the contents of the receive packet steering tables.
2399 */
2400int t3_read_rss(struct adapter *adapter, u8 * lkup, u16 *map)
2401{
2402 int i;
2403 u32 val;
2404
2405 if (lkup)
2406 for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2407 t3_write_reg(adapter, A_TP_RSS_LKP_TABLE,
2408 0xffff0000 | i);
2409 val = t3_read_reg(adapter, A_TP_RSS_LKP_TABLE);
2410 if (!(val & 0x80000000))
2411 return -EAGAIN;
2412 *lkup++ = val;
2413 *lkup++ = (val >> 8);
2414 }
2415
2416 if (map)
2417 for (i = 0; i < RSS_TABLE_SIZE; ++i) {
2418 t3_write_reg(adapter, A_TP_RSS_MAP_TABLE,
2419 0xffff0000 | i);
2420 val = t3_read_reg(adapter, A_TP_RSS_MAP_TABLE);
2421 if (!(val & 0x80000000))
2422 return -EAGAIN;
2423 *map++ = val;
2424 }
2425 return 0;
2426}
2427
2428/**
2429 * t3_tp_set_offload_mode - put TP in NIC/offload mode
2430 * @adap: the adapter
2431 * @enable: 1 to select offload mode, 0 for regular NIC
2432 *
2433 * Switches TP to NIC/offload mode.
2434 */
2435void t3_tp_set_offload_mode(struct adapter *adap, int enable)
2436{
2437 if (is_offload(adap) || !enable)
2438 t3_set_reg_field(adap, A_TP_IN_CONFIG, F_NICMODE,
2439 V_NICMODE(!enable));
2440}
2441
2442/**
2443 * pm_num_pages - calculate the number of pages of the payload memory
2444 * @mem_size: the size of the payload memory
2445 * @pg_size: the size of each payload memory page
2446 *
2447 * Calculate the number of pages, each of the given size, that fit in a
2448 * memory of the specified size, respecting the HW requirement that the
2449 * number of pages must be a multiple of 24.
2450 */
2451static inline unsigned int pm_num_pages(unsigned int mem_size,
2452 unsigned int pg_size)
2453{
2454 unsigned int n = mem_size / pg_size;
2455
2456 return n - n % 24;
2457}
2458
2459#define mem_region(adap, start, size, reg) \
2460 t3_write_reg((adap), A_ ## reg, (start)); \
2461 start += size
2462
Divy Le Rayb8819552007-12-17 18:47:31 -08002463/**
Divy Le Ray4d22de32007-01-18 22:04:14 -05002464 * partition_mem - partition memory and configure TP memory settings
2465 * @adap: the adapter
2466 * @p: the TP parameters
2467 *
2468 * Partitions context and payload memory and configures TP's memory
2469 * registers.
2470 */
2471static void partition_mem(struct adapter *adap, const struct tp_params *p)
2472{
2473 unsigned int m, pstructs, tids = t3_mc5_size(&adap->mc5);
2474 unsigned int timers = 0, timers_shift = 22;
2475
2476 if (adap->params.rev > 0) {
2477 if (tids <= 16 * 1024) {
2478 timers = 1;
2479 timers_shift = 16;
2480 } else if (tids <= 64 * 1024) {
2481 timers = 2;
2482 timers_shift = 18;
2483 } else if (tids <= 256 * 1024) {
2484 timers = 3;
2485 timers_shift = 20;
2486 }
2487 }
2488
2489 t3_write_reg(adap, A_TP_PMM_SIZE,
2490 p->chan_rx_size | (p->chan_tx_size >> 16));
2491
2492 t3_write_reg(adap, A_TP_PMM_TX_BASE, 0);
2493 t3_write_reg(adap, A_TP_PMM_TX_PAGE_SIZE, p->tx_pg_size);
2494 t3_write_reg(adap, A_TP_PMM_TX_MAX_PAGE, p->tx_num_pgs);
2495 t3_set_reg_field(adap, A_TP_PARA_REG3, V_TXDATAACKIDX(M_TXDATAACKIDX),
2496 V_TXDATAACKIDX(fls(p->tx_pg_size) - 12));
2497
2498 t3_write_reg(adap, A_TP_PMM_RX_BASE, 0);
2499 t3_write_reg(adap, A_TP_PMM_RX_PAGE_SIZE, p->rx_pg_size);
2500 t3_write_reg(adap, A_TP_PMM_RX_MAX_PAGE, p->rx_num_pgs);
2501
2502 pstructs = p->rx_num_pgs + p->tx_num_pgs;
2503 /* Add a bit of headroom and make multiple of 24 */
2504 pstructs += 48;
2505 pstructs -= pstructs % 24;
2506 t3_write_reg(adap, A_TP_CMM_MM_MAX_PSTRUCT, pstructs);
2507
2508 m = tids * TCB_SIZE;
2509 mem_region(adap, m, (64 << 10) * 64, SG_EGR_CNTX_BADDR);
2510 mem_region(adap, m, (64 << 10) * 64, SG_CQ_CONTEXT_BADDR);
2511 t3_write_reg(adap, A_TP_CMM_TIMER_BASE, V_CMTIMERMAXNUM(timers) | m);
2512 m += ((p->ntimer_qs - 1) << timers_shift) + (1 << 22);
2513 mem_region(adap, m, pstructs * 64, TP_CMM_MM_BASE);
2514 mem_region(adap, m, 64 * (pstructs / 24), TP_CMM_MM_PS_FLST_BASE);
2515 mem_region(adap, m, 64 * (p->rx_num_pgs / 24), TP_CMM_MM_RX_FLST_BASE);
2516 mem_region(adap, m, 64 * (p->tx_num_pgs / 24), TP_CMM_MM_TX_FLST_BASE);
2517
2518 m = (m + 4095) & ~0xfff;
2519 t3_write_reg(adap, A_CIM_SDRAM_BASE_ADDR, m);
2520 t3_write_reg(adap, A_CIM_SDRAM_ADDR_SIZE, p->cm_size - m);
2521
2522 tids = (p->cm_size - m - (3 << 20)) / 3072 - 32;
2523 m = t3_mc5_size(&adap->mc5) - adap->params.mc5.nservers -
2524 adap->params.mc5.nfilters - adap->params.mc5.nroutes;
2525 if (tids < m)
2526 adap->params.mc5.nservers += m - tids;
2527}
2528
2529static inline void tp_wr_indirect(struct adapter *adap, unsigned int addr,
2530 u32 val)
2531{
2532 t3_write_reg(adap, A_TP_PIO_ADDR, addr);
2533 t3_write_reg(adap, A_TP_PIO_DATA, val);
2534}
2535
2536static void tp_config(struct adapter *adap, const struct tp_params *p)
2537{
Divy Le Ray4d22de32007-01-18 22:04:14 -05002538 t3_write_reg(adap, A_TP_GLOBAL_CONFIG, F_TXPACINGENABLE | F_PATHMTU |
2539 F_IPCHECKSUMOFFLOAD | F_UDPCHECKSUMOFFLOAD |
2540 F_TCPCHECKSUMOFFLOAD | V_IPTTL(64));
2541 t3_write_reg(adap, A_TP_TCP_OPTIONS, V_MTUDEFAULT(576) |
2542 F_MTUENABLE | V_WINDOWSCALEMODE(1) |
Divy Le Ray8a9fab22007-05-30 21:10:52 -07002543 V_TIMESTAMPSMODE(0) | V_SACKMODE(1) | V_SACKRX(1));
Divy Le Ray4d22de32007-01-18 22:04:14 -05002544 t3_write_reg(adap, A_TP_DACK_CONFIG, V_AUTOSTATE3(1) |
2545 V_AUTOSTATE2(1) | V_AUTOSTATE1(0) |
2546 V_BYTETHRESHOLD(16384) | V_MSSTHRESHOLD(2) |
2547 F_AUTOCAREFUL | F_AUTOENABLE | V_DACK_MODE(1));
Divy Le Rayb8819552007-12-17 18:47:31 -08002548 t3_set_reg_field(adap, A_TP_IN_CONFIG, F_RXFBARBPRIO | F_TXFBARBPRIO,
Divy Le Ray4d22de32007-01-18 22:04:14 -05002549 F_IPV6ENABLE | F_NICMODE);
2550 t3_write_reg(adap, A_TP_TX_RESOURCE_LIMIT, 0x18141814);
2551 t3_write_reg(adap, A_TP_PARA_REG4, 0x5050105);
Divy Le Ray8a9fab22007-05-30 21:10:52 -07002552 t3_set_reg_field(adap, A_TP_PARA_REG6, 0,
2553 adap->params.rev > 0 ? F_ENABLEESND :
2554 F_T3A_ENABLEESND);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002555
Divy Le Ray3b1d3072007-01-30 19:44:07 -08002556 t3_set_reg_field(adap, A_TP_PC_CONFIG,
Divy Le Ray8a9fab22007-05-30 21:10:52 -07002557 F_ENABLEEPCMDAFULL,
2558 F_ENABLEOCSPIFULL |F_TXDEFERENABLE | F_HEARBEATDACK |
2559 F_TXCONGESTIONMODE | F_RXCONGESTIONMODE);
Divy Le Rayb8819552007-12-17 18:47:31 -08002560 t3_set_reg_field(adap, A_TP_PC_CONFIG2, F_CHDRAFULL,
2561 F_ENABLEIPV6RSS | F_ENABLENONOFDTNLSYN |
2562 F_ENABLEARPMISS | F_DISBLEDAPARBIT0);
Divy Le Ray8a9fab22007-05-30 21:10:52 -07002563 t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1080);
2564 t3_write_reg(adap, A_TP_PROXY_FLOW_CNTL, 1000);
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002565
Divy Le Ray4d22de32007-01-18 22:04:14 -05002566 if (adap->params.rev > 0) {
2567 tp_wr_indirect(adap, A_TP_EGRESS_CONFIG, F_REWRITEFORCETOSIZE);
2568 t3_set_reg_field(adap, A_TP_PARA_REG3, F_TXPACEAUTO,
2569 F_TXPACEAUTO);
2570 t3_set_reg_field(adap, A_TP_PC_CONFIG, F_LOCKTID, F_LOCKTID);
2571 t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEAUTOSTRICT);
2572 } else
2573 t3_set_reg_field(adap, A_TP_PARA_REG3, 0, F_TXPACEFIXED);
2574
Divy Le Raya2604be2007-11-16 11:22:16 -08002575 if (adap->params.rev == T3_REV_C)
2576 t3_set_reg_field(adap, A_TP_PC_CONFIG,
2577 V_TABLELATENCYDELTA(M_TABLELATENCYDELTA),
2578 V_TABLELATENCYDELTA(4));
2579
Divy Le Ray8a9fab22007-05-30 21:10:52 -07002580 t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT1, 0);
2581 t3_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0, 0);
2582 t3_write_reg(adap, A_TP_MOD_CHANNEL_WEIGHT, 0);
2583 t3_write_reg(adap, A_TP_MOD_RATE_LIMIT, 0xf2200000);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002584}
2585
2586/* Desired TP timer resolution in usec */
2587#define TP_TMR_RES 50
2588
2589/* TCP timer values in ms */
2590#define TP_DACK_TIMER 50
2591#define TP_RTO_MIN 250
2592
2593/**
2594 * tp_set_timers - set TP timing parameters
2595 * @adap: the adapter to set
2596 * @core_clk: the core clock frequency in Hz
2597 *
2598 * Set TP's timing parameters, such as the various timer resolutions and
2599 * the TCP timer values.
2600 */
2601static void tp_set_timers(struct adapter *adap, unsigned int core_clk)
2602{
2603 unsigned int tre = fls(core_clk / (1000000 / TP_TMR_RES)) - 1;
2604 unsigned int dack_re = fls(core_clk / 5000) - 1; /* 200us */
2605 unsigned int tstamp_re = fls(core_clk / 1000); /* 1ms, at least */
2606 unsigned int tps = core_clk >> tre;
2607
2608 t3_write_reg(adap, A_TP_TIMER_RESOLUTION, V_TIMERRESOLUTION(tre) |
2609 V_DELAYEDACKRESOLUTION(dack_re) |
2610 V_TIMESTAMPRESOLUTION(tstamp_re));
2611 t3_write_reg(adap, A_TP_DACK_TIMER,
2612 (core_clk >> dack_re) / (1000 / TP_DACK_TIMER));
2613 t3_write_reg(adap, A_TP_TCP_BACKOFF_REG0, 0x3020100);
2614 t3_write_reg(adap, A_TP_TCP_BACKOFF_REG1, 0x7060504);
2615 t3_write_reg(adap, A_TP_TCP_BACKOFF_REG2, 0xb0a0908);
2616 t3_write_reg(adap, A_TP_TCP_BACKOFF_REG3, 0xf0e0d0c);
2617 t3_write_reg(adap, A_TP_SHIFT_CNT, V_SYNSHIFTMAX(6) |
2618 V_RXTSHIFTMAXR1(4) | V_RXTSHIFTMAXR2(15) |
2619 V_PERSHIFTBACKOFFMAX(8) | V_PERSHIFTMAX(8) |
2620 V_KEEPALIVEMAX(9));
2621
2622#define SECONDS * tps
2623
2624 t3_write_reg(adap, A_TP_MSL, adap->params.rev > 0 ? 0 : 2 SECONDS);
2625 t3_write_reg(adap, A_TP_RXT_MIN, tps / (1000 / TP_RTO_MIN));
2626 t3_write_reg(adap, A_TP_RXT_MAX, 64 SECONDS);
2627 t3_write_reg(adap, A_TP_PERS_MIN, 5 SECONDS);
2628 t3_write_reg(adap, A_TP_PERS_MAX, 64 SECONDS);
2629 t3_write_reg(adap, A_TP_KEEP_IDLE, 7200 SECONDS);
2630 t3_write_reg(adap, A_TP_KEEP_INTVL, 75 SECONDS);
2631 t3_write_reg(adap, A_TP_INIT_SRTT, 3 SECONDS);
2632 t3_write_reg(adap, A_TP_FINWAIT2_TIMER, 600 SECONDS);
2633
2634#undef SECONDS
2635}
2636
2637/**
2638 * t3_tp_set_coalescing_size - set receive coalescing size
2639 * @adap: the adapter
2640 * @size: the receive coalescing size
2641 * @psh: whether a set PSH bit should deliver coalesced data
2642 *
2643 * Set the receive coalescing size and PSH bit handling.
2644 */
2645int t3_tp_set_coalescing_size(struct adapter *adap, unsigned int size, int psh)
2646{
2647 u32 val;
2648
2649 if (size > MAX_RX_COALESCING_LEN)
2650 return -EINVAL;
2651
2652 val = t3_read_reg(adap, A_TP_PARA_REG3);
2653 val &= ~(F_RXCOALESCEENABLE | F_RXCOALESCEPSHEN);
2654
2655 if (size) {
2656 val |= F_RXCOALESCEENABLE;
2657 if (psh)
2658 val |= F_RXCOALESCEPSHEN;
Divy Le Ray8a9fab22007-05-30 21:10:52 -07002659 size = min(MAX_RX_COALESCING_LEN, size);
Divy Le Ray4d22de32007-01-18 22:04:14 -05002660 t3_write_reg(adap, A_TP_PARA_REG2, V_RXCOALESCESIZE(size) |
2661 V_MAXRXDATA(MAX_RX_COALESCING_LEN));
2662 }
2663 t3_write_reg(adap, A_TP_PARA_REG3, val);
2664 return 0;
2665}
2666
2667/**
2668 * t3_tp_set_max_rxsize - set the max receive size
2669 * @adap: the adapter
2670 * @size: the max receive size
2671 *
2672 * Set TP's max receive size. This is the limit that applies when
2673 * receive coalescing is disabled.
2674 */
2675void t3_tp_set_max_rxsize(struct adapter *adap, unsigned int size)
2676{
2677 t3_write_reg(adap, A_TP_PARA_REG7,
2678 V_PMMAXXFERLEN0(size) | V_PMMAXXFERLEN1(size));
2679}
2680
Roland Dreier7b9b0942008-01-29 14:45:11 -08002681static void init_mtus(unsigned short mtus[])
Divy Le Ray4d22de32007-01-18 22:04:14 -05002682{
2683 /*
2684 * See draft-mathis-plpmtud-00.txt for the values. The min is 88 so
2685 * it can accomodate max size TCP/IP headers when SACK and timestamps
2686 * are enabled and still have at least 8 bytes of payload.
2687 */
Divy Le Ray75758e82007-12-05 10:15:01 -08002688 mtus[0] = 88;
Divy Le Ray8a9fab22007-05-30 21:10:52 -07002689 mtus[1] = 88;
2690 mtus[2] = 256;
2691 mtus[3] = 512;
2692 mtus[4] = 576;
Divy Le Ray4d22de32007-01-18 22:04:14 -05002693 mtus[5] = 1024;
2694 mtus[6] = 1280;
2695 mtus[7] = 1492;
2696 mtus[8] = 1500;
2697 mtus[9] = 2002;
2698 mtus[10] = 2048;
2699 mtus[11] = 4096;
2700 mtus[12] = 4352;
2701 mtus[13] = 8192;
2702 mtus[14] = 9000;
2703 mtus[15] = 9600;
2704}
2705
2706/*
2707 * Initial congestion control parameters.
2708 */
Roland Dreier7b9b0942008-01-29 14:45:11 -08002709static void init_cong_ctrl(unsigned short *a, unsigned short *b)
Divy Le Ray4d22de32007-01-18 22:04:14 -05002710{
2711 a[0] = a[1] = a[2] = a[3] = a[4] = a[5] = a[6] = a[7] = a[8] = 1;
2712 a[9] = 2;
2713 a[10] = 3;
2714 a[11] = 4;
2715 a[12] = 5;
2716 a[13] = 6;
2717 a[14] = 7;
2718 a[15] = 8;
2719 a[16] = 9;
2720 a[17] = 10;
2721 a[18] = 14;
2722 a[19] = 17;
2723 a[20] = 21;
2724 a[21] = 25;
2725 a[22] = 30;
2726 a[23] = 35;
2727 a[24] = 45;
2728 a[25] = 60;
2729 a[26] = 80;
2730 a[27] = 100;
2731 a[28] = 200;
2732 a[29] = 300;
2733 a[30] = 400;
2734 a[31] = 500;
2735
2736 b[0] = b[1] = b[2] = b[3] = b[4] = b[5] = b[6] = b[7] = b[8] = 0;
2737 b[9] = b[10] = 1;
2738 b[11] = b[12] = 2;
2739 b[13] = b[14] = b[15] = b[16] = 3;
2740 b[17] = b[18] = b[19] = b[20] = b[21] = 4;
2741 b[22] = b[23] = b[24] = b[25] = b[26] = b[27] = 5;
2742 b[28] = b[29] = 6;
2743 b[30] = b[31] = 7;
2744}
2745
2746/* The minimum additive increment value for the congestion control table */
2747#define CC_MIN_INCR 2U
2748
2749/**
2750 * t3_load_mtus - write the MTU and congestion control HW tables
2751 * @adap: the adapter
2752 * @mtus: the unrestricted values for the MTU table
2753 * @alphs: the values for the congestion control alpha parameter
2754 * @beta: the values for the congestion control beta parameter
2755 * @mtu_cap: the maximum permitted effective MTU
2756 *
2757 * Write the MTU table with the supplied MTUs capping each at &mtu_cap.
2758 * Update the high-speed congestion control table with the supplied alpha,
2759 * beta, and MTUs.
2760 */
2761void t3_load_mtus(struct adapter *adap, unsigned short mtus[NMTUS],
2762 unsigned short alpha[NCCTRL_WIN],
2763 unsigned short beta[NCCTRL_WIN], unsigned short mtu_cap)
2764{
2765 static const unsigned int avg_pkts[NCCTRL_WIN] = {
2766 2, 6, 10, 14, 20, 28, 40, 56, 80, 112, 160, 224, 320, 448, 640,
2767 896, 1281, 1792, 2560, 3584, 5120, 7168, 10240, 14336, 20480,
2768 28672, 40960, 57344, 81920, 114688, 163840, 229376
2769 };
2770
2771 unsigned int i, w;
2772
2773 for (i = 0; i < NMTUS; ++i) {
2774 unsigned int mtu = min(mtus[i], mtu_cap);
2775 unsigned int log2 = fls(mtu);
2776
2777 if (!(mtu & ((1 << log2) >> 2))) /* round */
2778 log2--;
2779 t3_write_reg(adap, A_TP_MTU_TABLE,
2780 (i << 24) | (log2 << 16) | mtu);
2781
2782 for (w = 0; w < NCCTRL_WIN; ++w) {
2783 unsigned int inc;
2784
2785 inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
2786 CC_MIN_INCR);
2787
2788 t3_write_reg(adap, A_TP_CCTRL_TABLE, (i << 21) |
2789 (w << 16) | (beta[w] << 13) | inc);
2790 }
2791 }
2792}
2793
2794/**
2795 * t3_read_hw_mtus - returns the values in the HW MTU table
2796 * @adap: the adapter
2797 * @mtus: where to store the HW MTU values
2798 *
2799 * Reads the HW MTU table.
2800 */
2801void t3_read_hw_mtus(struct adapter *adap, unsigned short mtus[NMTUS])
2802{
2803 int i;
2804
2805 for (i = 0; i < NMTUS; ++i) {
2806 unsigned int val;
2807
2808 t3_write_reg(adap, A_TP_MTU_TABLE, 0xff000000 | i);
2809 val = t3_read_reg(adap, A_TP_MTU_TABLE);
2810 mtus[i] = val & 0x3fff;
2811 }
2812}
2813
2814/**
2815 * t3_get_cong_cntl_tab - reads the congestion control table
2816 * @adap: the adapter
2817 * @incr: where to store the alpha values
2818 *
2819 * Reads the additive increments programmed into the HW congestion
2820 * control table.
2821 */
2822void t3_get_cong_cntl_tab(struct adapter *adap,
2823 unsigned short incr[NMTUS][NCCTRL_WIN])
2824{
2825 unsigned int mtu, w;
2826
2827 for (mtu = 0; mtu < NMTUS; ++mtu)
2828 for (w = 0; w < NCCTRL_WIN; ++w) {
2829 t3_write_reg(adap, A_TP_CCTRL_TABLE,
2830 0xffff0000 | (mtu << 5) | w);
2831 incr[mtu][w] = t3_read_reg(adap, A_TP_CCTRL_TABLE) &
2832 0x1fff;
2833 }
2834}
2835
2836/**
2837 * t3_tp_get_mib_stats - read TP's MIB counters
2838 * @adap: the adapter
2839 * @tps: holds the returned counter values
2840 *
2841 * Returns the values of TP's MIB counters.
2842 */
2843void t3_tp_get_mib_stats(struct adapter *adap, struct tp_mib_stats *tps)
2844{
2845 t3_read_indirect(adap, A_TP_MIB_INDEX, A_TP_MIB_RDATA, (u32 *) tps,
2846 sizeof(*tps) / sizeof(u32), 0);
2847}
2848
2849#define ulp_region(adap, name, start, len) \
2850 t3_write_reg((adap), A_ULPRX_ ## name ## _LLIMIT, (start)); \
2851 t3_write_reg((adap), A_ULPRX_ ## name ## _ULIMIT, \
2852 (start) + (len) - 1); \
2853 start += len
2854
2855#define ulptx_region(adap, name, start, len) \
2856 t3_write_reg((adap), A_ULPTX_ ## name ## _LLIMIT, (start)); \
2857 t3_write_reg((adap), A_ULPTX_ ## name ## _ULIMIT, \
2858 (start) + (len) - 1)
2859
2860static void ulp_config(struct adapter *adap, const struct tp_params *p)
2861{
2862 unsigned int m = p->chan_rx_size;
2863
2864 ulp_region(adap, ISCSI, m, p->chan_rx_size / 8);
2865 ulp_region(adap, TDDP, m, p->chan_rx_size / 8);
2866 ulptx_region(adap, TPT, m, p->chan_rx_size / 4);
2867 ulp_region(adap, STAG, m, p->chan_rx_size / 4);
2868 ulp_region(adap, RQ, m, p->chan_rx_size / 4);
2869 ulptx_region(adap, PBL, m, p->chan_rx_size / 4);
2870 ulp_region(adap, PBL, m, p->chan_rx_size / 4);
2871 t3_write_reg(adap, A_ULPRX_TDDP_TAGMASK, 0xffffffff);
2872}
2873
Divy Le Ray480fe1a2007-05-30 21:10:58 -07002874/**
2875 * t3_set_proto_sram - set the contents of the protocol sram
2876 * @adapter: the adapter
2877 * @data: the protocol image
2878 *
2879 * Write the contents of the protocol SRAM.
2880 */
David Woodhouse2c733a12008-05-24 00:10:55 +01002881int t3_set_proto_sram(struct adapter *adap, const u8 *data)
Divy Le Ray480fe1a2007-05-30 21:10:58 -07002882{
2883 int i;
David Woodhouse2c733a12008-05-24 00:10:55 +01002884 const __be32 *buf = (const __be32 *)data;
Divy Le Ray480fe1a2007-05-30 21:10:58 -07002885
2886 for (i = 0; i < PROTO_SRAM_LINES; i++) {
Al Viro05e5c112007-12-22 18:56:23 +00002887 t3_write_reg(adap, A_TP_EMBED_OP_FIELD5, be32_to_cpu(*buf++));
2888 t3_write_reg(adap, A_TP_EMBED_OP_FIELD4, be32_to_cpu(*buf++));
2889 t3_write_reg(adap, A_TP_EMBED_OP_FIELD3, be32_to_cpu(*buf++));
2890 t3_write_reg(adap, A_TP_EMBED_OP_FIELD2, be32_to_cpu(*buf++));
2891 t3_write_reg(adap, A_TP_EMBED_OP_FIELD1, be32_to_cpu(*buf++));
Jeff Garzik2eab17a2007-11-23 21:59:45 -05002892
Divy Le Ray480fe1a2007-05-30 21:10:58 -07002893 t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, i << 1 | 1 << 31);
2894 if (t3_wait_op_done(adap, A_TP_EMBED_OP_FIELD0, 1, 1, 5, 1))
2895 return -EIO;
2896 }
2897 t3_write_reg(adap, A_TP_EMBED_OP_FIELD0, 0);
2898
2899 return 0;
2900}
2901
Divy Le Ray4d22de32007-01-18 22:04:14 -05002902void t3_config_trace_filter(struct adapter *adapter,
2903 const struct trace_params *tp, int filter_index,
2904 int invert, int enable)
2905{
2906 u32 addr, key[4], mask[4];
2907
2908 key[0] = tp->sport | (tp->sip << 16);
2909 key[1] = (tp->sip >> 16) | (tp->dport << 16);
2910 key[2] = tp->dip;
2911 key[3] = tp->proto | (tp->vlan << 8) | (tp->intf << 20);
2912
2913 mask[0] = tp->sport_mask | (tp->sip_mask << 16);
2914 mask[1] = (tp->sip_mask >> 16) | (tp->dport_mask << 16);
2915 mask[2] = tp->dip_mask;
2916 mask[3] = tp->proto_mask | (tp->vlan_mask << 8) | (tp->intf_mask << 20);
2917
2918 if (invert)
2919 key[3] |= (1 << 29);
2920 if (enable)
2921 key[3] |= (1 << 28);
2922
2923 addr = filter_index ? A_TP_RX_TRC_KEY0 : A_TP_TX_TRC_KEY0;
2924 tp_wr_indirect(adapter, addr++, key[0]);
2925 tp_wr_indirect(adapter, addr++, mask[0]);
2926 tp_wr_indirect(adapter, addr++, key[1]);
2927 tp_wr_indirect(adapter, addr++, mask[1]);
2928 tp_wr_indirect(adapter, addr++, key[2]);
2929 tp_wr_indirect(adapter, addr++, mask[2]);
2930 tp_wr_indirect(adapter, addr++, key[3]);
2931 tp_wr_indirect(adapter, addr, mask[3]);
2932 t3_read_reg(adapter, A_TP_PIO_DATA);
2933}
2934
2935/**
2936 * t3_config_sched - configure a HW traffic scheduler
2937 * @adap: the adapter
2938 * @kbps: target rate in Kbps
2939 * @sched: the scheduler index
2940 *
2941 * Configure a HW scheduler for the target rate
2942 */
2943int t3_config_sched(struct adapter *adap, unsigned int kbps, int sched)
2944{
2945 unsigned int v, tps, cpt, bpt, delta, mindelta = ~0;
2946 unsigned int clk = adap->params.vpd.cclk * 1000;
2947 unsigned int selected_cpt = 0, selected_bpt = 0;
2948
2949 if (kbps > 0) {
2950 kbps *= 125; /* -> bytes */
2951 for (cpt = 1; cpt <= 255; cpt++) {
2952 tps = clk / cpt;
2953 bpt = (kbps + tps / 2) / tps;
2954 if (bpt > 0 && bpt <= 255) {
2955 v = bpt * tps;
2956 delta = v >= kbps ? v - kbps : kbps - v;
2957 if (delta <= mindelta) {
2958 mindelta = delta;
2959 selected_cpt = cpt;
2960 selected_bpt = bpt;
2961 }
2962 } else if (selected_cpt)
2963 break;
2964 }
2965 if (!selected_cpt)
2966 return -EINVAL;
2967 }
2968 t3_write_reg(adap, A_TP_TM_PIO_ADDR,
2969 A_TP_TX_MOD_Q1_Q0_RATE_LIMIT - sched / 2);
2970 v = t3_read_reg(adap, A_TP_TM_PIO_DATA);
2971 if (sched & 1)
2972 v = (v & 0xffff) | (selected_cpt << 16) | (selected_bpt << 24);
2973 else
2974 v = (v & 0xffff0000) | selected_cpt | (selected_bpt << 8);
2975 t3_write_reg(adap, A_TP_TM_PIO_DATA, v);
2976 return 0;
2977}
2978
2979static int tp_init(struct adapter *adap, const struct tp_params *p)
2980{
2981 int busy = 0;
2982
2983 tp_config(adap, p);
2984 t3_set_vlan_accel(adap, 3, 0);
2985
2986 if (is_offload(adap)) {
2987 tp_set_timers(adap, adap->params.vpd.cclk * 1000);
2988 t3_write_reg(adap, A_TP_RESET, F_FLSTINITENABLE);
2989 busy = t3_wait_op_done(adap, A_TP_RESET, F_FLSTINITENABLE,
2990 0, 1000, 5);
2991 if (busy)
2992 CH_ERR(adap, "TP initialization timed out\n");
2993 }
2994
2995 if (!busy)
2996 t3_write_reg(adap, A_TP_RESET, F_TPRESET);
2997 return busy;
2998}
2999
3000int t3_mps_set_active_ports(struct adapter *adap, unsigned int port_mask)
3001{
3002 if (port_mask & ~((1 << adap->params.nports) - 1))
3003 return -EINVAL;
3004 t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE | F_PORT0ACTIVE,
3005 port_mask << S_PORT0ACTIVE);
3006 return 0;
3007}
3008
3009/*
3010 * Perform the bits of HW initialization that are dependent on the number
3011 * of available ports.
3012 */
3013static void init_hw_for_avail_ports(struct adapter *adap, int nports)
3014{
3015 int i;
3016
3017 if (nports == 1) {
3018 t3_set_reg_field(adap, A_ULPRX_CTL, F_ROUND_ROBIN, 0);
3019 t3_set_reg_field(adap, A_ULPTX_CONFIG, F_CFG_RR_ARB, 0);
3020 t3_write_reg(adap, A_MPS_CFG, F_TPRXPORTEN | F_TPTXPORT0EN |
3021 F_PORT0ACTIVE | F_ENFORCEPKT);
Divy Le Ray8a9fab22007-05-30 21:10:52 -07003022 t3_write_reg(adap, A_PM1_TX_CFG, 0xffffffff);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003023 } else {
3024 t3_set_reg_field(adap, A_ULPRX_CTL, 0, F_ROUND_ROBIN);
3025 t3_set_reg_field(adap, A_ULPTX_CONFIG, 0, F_CFG_RR_ARB);
3026 t3_write_reg(adap, A_ULPTX_DMA_WEIGHT,
3027 V_D1_WEIGHT(16) | V_D0_WEIGHT(16));
3028 t3_write_reg(adap, A_MPS_CFG, F_TPTXPORT0EN | F_TPTXPORT1EN |
3029 F_TPRXPORTEN | F_PORT0ACTIVE | F_PORT1ACTIVE |
3030 F_ENFORCEPKT);
3031 t3_write_reg(adap, A_PM1_TX_CFG, 0x80008000);
3032 t3_set_reg_field(adap, A_TP_PC_CONFIG, 0, F_TXTOSQUEUEMAPMODE);
3033 t3_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
3034 V_TX_MOD_QUEUE_REQ_MAP(0xaa));
3035 for (i = 0; i < 16; i++)
3036 t3_write_reg(adap, A_TP_TX_MOD_QUE_TABLE,
3037 (i << 16) | 0x1010);
3038 }
3039}
3040
3041static int calibrate_xgm(struct adapter *adapter)
3042{
3043 if (uses_xaui(adapter)) {
3044 unsigned int v, i;
3045
3046 for (i = 0; i < 5; ++i) {
3047 t3_write_reg(adapter, A_XGM_XAUI_IMP, 0);
3048 t3_read_reg(adapter, A_XGM_XAUI_IMP);
3049 msleep(1);
3050 v = t3_read_reg(adapter, A_XGM_XAUI_IMP);
3051 if (!(v & (F_XGM_CALFAULT | F_CALBUSY))) {
3052 t3_write_reg(adapter, A_XGM_XAUI_IMP,
3053 V_XAUIIMP(G_CALIMP(v) >> 2));
3054 return 0;
3055 }
3056 }
3057 CH_ERR(adapter, "MAC calibration failed\n");
3058 return -1;
3059 } else {
3060 t3_write_reg(adapter, A_XGM_RGMII_IMP,
3061 V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3062 t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3063 F_XGM_IMPSETUPDATE);
3064 }
3065 return 0;
3066}
3067
3068static void calibrate_xgm_t3b(struct adapter *adapter)
3069{
3070 if (!uses_xaui(adapter)) {
3071 t3_write_reg(adapter, A_XGM_RGMII_IMP, F_CALRESET |
3072 F_CALUPDATE | V_RGMIIIMPPD(2) | V_RGMIIIMPPU(3));
3073 t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALRESET, 0);
3074 t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0,
3075 F_XGM_IMPSETUPDATE);
3076 t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_XGM_IMPSETUPDATE,
3077 0);
3078 t3_set_reg_field(adapter, A_XGM_RGMII_IMP, F_CALUPDATE, 0);
3079 t3_set_reg_field(adapter, A_XGM_RGMII_IMP, 0, F_CALUPDATE);
3080 }
3081}
3082
3083struct mc7_timing_params {
3084 unsigned char ActToPreDly;
3085 unsigned char ActToRdWrDly;
3086 unsigned char PreCyc;
3087 unsigned char RefCyc[5];
3088 unsigned char BkCyc;
3089 unsigned char WrToRdDly;
3090 unsigned char RdToWrDly;
3091};
3092
3093/*
3094 * Write a value to a register and check that the write completed. These
3095 * writes normally complete in a cycle or two, so one read should suffice.
3096 * The very first read exists to flush the posted write to the device.
3097 */
3098static int wrreg_wait(struct adapter *adapter, unsigned int addr, u32 val)
3099{
3100 t3_write_reg(adapter, addr, val);
3101 t3_read_reg(adapter, addr); /* flush */
3102 if (!(t3_read_reg(adapter, addr) & F_BUSY))
3103 return 0;
3104 CH_ERR(adapter, "write to MC7 register 0x%x timed out\n", addr);
3105 return -EIO;
3106}
3107
3108static int mc7_init(struct mc7 *mc7, unsigned int mc7_clock, int mem_type)
3109{
3110 static const unsigned int mc7_mode[] = {
3111 0x632, 0x642, 0x652, 0x432, 0x442
3112 };
3113 static const struct mc7_timing_params mc7_timings[] = {
3114 {12, 3, 4, {20, 28, 34, 52, 0}, 15, 6, 4},
3115 {12, 4, 5, {20, 28, 34, 52, 0}, 16, 7, 4},
3116 {12, 5, 6, {20, 28, 34, 52, 0}, 17, 8, 4},
3117 {9, 3, 4, {15, 21, 26, 39, 0}, 12, 6, 4},
3118 {9, 4, 5, {15, 21, 26, 39, 0}, 13, 7, 4}
3119 };
3120
3121 u32 val;
3122 unsigned int width, density, slow, attempts;
3123 struct adapter *adapter = mc7->adapter;
3124 const struct mc7_timing_params *p = &mc7_timings[mem_type];
3125
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003126 if (!mc7->size)
3127 return 0;
3128
Divy Le Ray4d22de32007-01-18 22:04:14 -05003129 val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
3130 slow = val & F_SLOW;
3131 width = G_WIDTH(val);
3132 density = G_DEN(val);
3133
3134 t3_write_reg(adapter, mc7->offset + A_MC7_CFG, val | F_IFEN);
3135 val = t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
3136 msleep(1);
3137
3138 if (!slow) {
3139 t3_write_reg(adapter, mc7->offset + A_MC7_CAL, F_SGL_CAL_EN);
3140 t3_read_reg(adapter, mc7->offset + A_MC7_CAL);
3141 msleep(1);
3142 if (t3_read_reg(adapter, mc7->offset + A_MC7_CAL) &
3143 (F_BUSY | F_SGL_CAL_EN | F_CAL_FAULT)) {
3144 CH_ERR(adapter, "%s MC7 calibration timed out\n",
3145 mc7->name);
3146 goto out_fail;
3147 }
3148 }
3149
3150 t3_write_reg(adapter, mc7->offset + A_MC7_PARM,
3151 V_ACTTOPREDLY(p->ActToPreDly) |
3152 V_ACTTORDWRDLY(p->ActToRdWrDly) | V_PRECYC(p->PreCyc) |
3153 V_REFCYC(p->RefCyc[density]) | V_BKCYC(p->BkCyc) |
3154 V_WRTORDDLY(p->WrToRdDly) | V_RDTOWRDLY(p->RdToWrDly));
3155
3156 t3_write_reg(adapter, mc7->offset + A_MC7_CFG,
3157 val | F_CLKEN | F_TERM150);
3158 t3_read_reg(adapter, mc7->offset + A_MC7_CFG); /* flush */
3159
3160 if (!slow)
3161 t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLENB,
3162 F_DLLENB);
3163 udelay(1);
3164
3165 val = slow ? 3 : 6;
3166 if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
3167 wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE2, 0) ||
3168 wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE3, 0) ||
3169 wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
3170 goto out_fail;
3171
3172 if (!slow) {
3173 t3_write_reg(adapter, mc7->offset + A_MC7_MODE, 0x100);
3174 t3_set_reg_field(adapter, mc7->offset + A_MC7_DLL, F_DLLRST, 0);
3175 udelay(5);
3176 }
3177
3178 if (wrreg_wait(adapter, mc7->offset + A_MC7_PRE, 0) ||
3179 wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
3180 wrreg_wait(adapter, mc7->offset + A_MC7_REF, 0) ||
3181 wrreg_wait(adapter, mc7->offset + A_MC7_MODE,
3182 mc7_mode[mem_type]) ||
3183 wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val | 0x380) ||
3184 wrreg_wait(adapter, mc7->offset + A_MC7_EXT_MODE1, val))
3185 goto out_fail;
3186
3187 /* clock value is in KHz */
3188 mc7_clock = mc7_clock * 7812 + mc7_clock / 2; /* ns */
3189 mc7_clock /= 1000000; /* KHz->MHz, ns->us */
3190
3191 t3_write_reg(adapter, mc7->offset + A_MC7_REF,
3192 F_PERREFEN | V_PREREFDIV(mc7_clock));
3193 t3_read_reg(adapter, mc7->offset + A_MC7_REF); /* flush */
3194
3195 t3_write_reg(adapter, mc7->offset + A_MC7_ECC, F_ECCGENEN | F_ECCCHKEN);
3196 t3_write_reg(adapter, mc7->offset + A_MC7_BIST_DATA, 0);
3197 t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_BEG, 0);
3198 t3_write_reg(adapter, mc7->offset + A_MC7_BIST_ADDR_END,
3199 (mc7->size << width) - 1);
3200 t3_write_reg(adapter, mc7->offset + A_MC7_BIST_OP, V_OP(1));
3201 t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP); /* flush */
3202
3203 attempts = 50;
3204 do {
3205 msleep(250);
3206 val = t3_read_reg(adapter, mc7->offset + A_MC7_BIST_OP);
3207 } while ((val & F_BUSY) && --attempts);
3208 if (val & F_BUSY) {
3209 CH_ERR(adapter, "%s MC7 BIST timed out\n", mc7->name);
3210 goto out_fail;
3211 }
3212
3213 /* Enable normal memory accesses. */
3214 t3_set_reg_field(adapter, mc7->offset + A_MC7_CFG, 0, F_RDY);
3215 return 0;
3216
3217out_fail:
3218 return -1;
3219}
3220
3221static void config_pcie(struct adapter *adap)
3222{
3223 static const u16 ack_lat[4][6] = {
3224 {237, 416, 559, 1071, 2095, 4143},
3225 {128, 217, 289, 545, 1057, 2081},
3226 {73, 118, 154, 282, 538, 1050},
3227 {67, 107, 86, 150, 278, 534}
3228 };
3229 static const u16 rpl_tmr[4][6] = {
3230 {711, 1248, 1677, 3213, 6285, 12429},
3231 {384, 651, 867, 1635, 3171, 6243},
3232 {219, 354, 462, 846, 1614, 3150},
3233 {201, 321, 258, 450, 834, 1602}
3234 };
3235
3236 u16 val;
3237 unsigned int log2_width, pldsize;
3238 unsigned int fst_trn_rx, fst_trn_tx, acklat, rpllmt;
3239
3240 pci_read_config_word(adap->pdev,
3241 adap->params.pci.pcie_cap_addr + PCI_EXP_DEVCTL,
3242 &val);
3243 pldsize = (val & PCI_EXP_DEVCTL_PAYLOAD) >> 5;
3244 pci_read_config_word(adap->pdev,
3245 adap->params.pci.pcie_cap_addr + PCI_EXP_LNKCTL,
3246 &val);
3247
3248 fst_trn_tx = G_NUMFSTTRNSEQ(t3_read_reg(adap, A_PCIE_PEX_CTRL0));
3249 fst_trn_rx = adap->params.rev == 0 ? fst_trn_tx :
3250 G_NUMFSTTRNSEQRX(t3_read_reg(adap, A_PCIE_MODE));
3251 log2_width = fls(adap->params.pci.width) - 1;
3252 acklat = ack_lat[log2_width][pldsize];
3253 if (val & 1) /* check LOsEnable */
3254 acklat += fst_trn_tx * 4;
3255 rpllmt = rpl_tmr[log2_width][pldsize] + fst_trn_rx * 4;
3256
3257 if (adap->params.rev == 0)
3258 t3_set_reg_field(adap, A_PCIE_PEX_CTRL1,
3259 V_T3A_ACKLAT(M_T3A_ACKLAT),
3260 V_T3A_ACKLAT(acklat));
3261 else
3262 t3_set_reg_field(adap, A_PCIE_PEX_CTRL1, V_ACKLAT(M_ACKLAT),
3263 V_ACKLAT(acklat));
3264
3265 t3_set_reg_field(adap, A_PCIE_PEX_CTRL0, V_REPLAYLMT(M_REPLAYLMT),
3266 V_REPLAYLMT(rpllmt));
3267
3268 t3_write_reg(adap, A_PCIE_PEX_ERR, 0xffffffff);
Divy Le Rayb8819552007-12-17 18:47:31 -08003269 t3_set_reg_field(adap, A_PCIE_CFG, 0,
Divy Le Ray204e2f92008-05-06 19:26:01 -07003270 F_ENABLELINKDWNDRST | F_ENABLELINKDOWNRST |
Divy Le Rayb8819552007-12-17 18:47:31 -08003271 F_PCIE_DMASTOPEN | F_PCIE_CLIDECEN);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003272}
3273
3274/*
3275 * Initialize and configure T3 HW modules. This performs the
3276 * initialization steps that need to be done once after a card is reset.
3277 * MAC and PHY initialization is handled separarely whenever a port is enabled.
3278 *
3279 * fw_params are passed to FW and their value is platform dependent. Only the
3280 * top 8 bits are available for use, the rest must be 0.
3281 */
3282int t3_init_hw(struct adapter *adapter, u32 fw_params)
3283{
Divy Le Rayb8819552007-12-17 18:47:31 -08003284 int err = -EIO, attempts, i;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003285 const struct vpd_params *vpd = &adapter->params.vpd;
3286
3287 if (adapter->params.rev > 0)
3288 calibrate_xgm_t3b(adapter);
3289 else if (calibrate_xgm(adapter))
3290 goto out_err;
3291
3292 if (vpd->mclk) {
3293 partition_mem(adapter, &adapter->params.tp);
3294
3295 if (mc7_init(&adapter->pmrx, vpd->mclk, vpd->mem_timing) ||
3296 mc7_init(&adapter->pmtx, vpd->mclk, vpd->mem_timing) ||
3297 mc7_init(&adapter->cm, vpd->mclk, vpd->mem_timing) ||
3298 t3_mc5_init(&adapter->mc5, adapter->params.mc5.nservers,
3299 adapter->params.mc5.nfilters,
3300 adapter->params.mc5.nroutes))
3301 goto out_err;
Divy Le Rayb8819552007-12-17 18:47:31 -08003302
3303 for (i = 0; i < 32; i++)
3304 if (clear_sge_ctxt(adapter, i, F_CQ))
3305 goto out_err;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003306 }
3307
3308 if (tp_init(adapter, &adapter->params.tp))
3309 goto out_err;
3310
3311 t3_tp_set_coalescing_size(adapter,
3312 min(adapter->params.sge.max_pkt_size,
3313 MAX_RX_COALESCING_LEN), 1);
3314 t3_tp_set_max_rxsize(adapter,
3315 min(adapter->params.sge.max_pkt_size, 16384U));
3316 ulp_config(adapter, &adapter->params.tp);
3317
3318 if (is_pcie(adapter))
3319 config_pcie(adapter);
3320 else
Divy Le Rayb8819552007-12-17 18:47:31 -08003321 t3_set_reg_field(adapter, A_PCIX_CFG, 0,
3322 F_DMASTOPEN | F_CLIDECEN);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003323
Divy Le Raya2604be2007-11-16 11:22:16 -08003324 if (adapter->params.rev == T3_REV_C)
3325 t3_set_reg_field(adapter, A_ULPTX_CONFIG, 0,
3326 F_CFG_CQE_SOP_MASK);
3327
Divy Le Ray8a9fab22007-05-30 21:10:52 -07003328 t3_write_reg(adapter, A_PM1_RX_CFG, 0xffffffff);
Divy Le Ray3f61e422007-08-21 20:49:41 -07003329 t3_write_reg(adapter, A_PM1_RX_MODE, 0);
3330 t3_write_reg(adapter, A_PM1_TX_MODE, 0);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003331 init_hw_for_avail_ports(adapter, adapter->params.nports);
3332 t3_sge_init(adapter, &adapter->params.sge);
3333
3334 t3_write_reg(adapter, A_CIM_HOST_ACC_DATA, vpd->uclk | fw_params);
3335 t3_write_reg(adapter, A_CIM_BOOT_CFG,
3336 V_BOOTADDR(FW_FLASH_BOOT_ADDR >> 2));
3337 t3_read_reg(adapter, A_CIM_BOOT_CFG); /* flush */
3338
Divy Le Rayb8819552007-12-17 18:47:31 -08003339 attempts = 100;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003340 do { /* wait for uP to initialize */
3341 msleep(20);
3342 } while (t3_read_reg(adapter, A_CIM_HOST_ACC_DATA) && --attempts);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003343 if (!attempts) {
3344 CH_ERR(adapter, "uP initialization timed out\n");
Divy Le Ray4d22de32007-01-18 22:04:14 -05003345 goto out_err;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003346 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05003347
3348 err = 0;
3349out_err:
3350 return err;
3351}
3352
3353/**
3354 * get_pci_mode - determine a card's PCI mode
3355 * @adapter: the adapter
3356 * @p: where to store the PCI settings
3357 *
3358 * Determines a card's PCI mode and associated parameters, such as speed
3359 * and width.
3360 */
Roland Dreier7b9b0942008-01-29 14:45:11 -08003361static void get_pci_mode(struct adapter *adapter, struct pci_params *p)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003362{
3363 static unsigned short speed_map[] = { 33, 66, 100, 133 };
3364 u32 pci_mode, pcie_cap;
3365
3366 pcie_cap = pci_find_capability(adapter->pdev, PCI_CAP_ID_EXP);
3367 if (pcie_cap) {
3368 u16 val;
3369
3370 p->variant = PCI_VARIANT_PCIE;
3371 p->pcie_cap_addr = pcie_cap;
3372 pci_read_config_word(adapter->pdev, pcie_cap + PCI_EXP_LNKSTA,
3373 &val);
3374 p->width = (val >> 4) & 0x3f;
3375 return;
3376 }
3377
3378 pci_mode = t3_read_reg(adapter, A_PCIX_MODE);
3379 p->speed = speed_map[G_PCLKRANGE(pci_mode)];
3380 p->width = (pci_mode & F_64BIT) ? 64 : 32;
3381 pci_mode = G_PCIXINITPAT(pci_mode);
3382 if (pci_mode == 0)
3383 p->variant = PCI_VARIANT_PCI;
3384 else if (pci_mode < 4)
3385 p->variant = PCI_VARIANT_PCIX_MODE1_PARITY;
3386 else if (pci_mode < 8)
3387 p->variant = PCI_VARIANT_PCIX_MODE1_ECC;
3388 else
3389 p->variant = PCI_VARIANT_PCIX_266_MODE2;
3390}
3391
3392/**
3393 * init_link_config - initialize a link's SW state
3394 * @lc: structure holding the link state
3395 * @ai: information about the current card
3396 *
3397 * Initializes the SW state maintained for each link, including the link's
3398 * capabilities and default speed/duplex/flow-control/autonegotiation
3399 * settings.
3400 */
Roland Dreier7b9b0942008-01-29 14:45:11 -08003401static void init_link_config(struct link_config *lc, unsigned int caps)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003402{
3403 lc->supported = caps;
3404 lc->requested_speed = lc->speed = SPEED_INVALID;
3405 lc->requested_duplex = lc->duplex = DUPLEX_INVALID;
3406 lc->requested_fc = lc->fc = PAUSE_RX | PAUSE_TX;
3407 if (lc->supported & SUPPORTED_Autoneg) {
3408 lc->advertising = lc->supported;
3409 lc->autoneg = AUTONEG_ENABLE;
3410 lc->requested_fc |= PAUSE_AUTONEG;
3411 } else {
3412 lc->advertising = 0;
3413 lc->autoneg = AUTONEG_DISABLE;
3414 }
3415}
3416
3417/**
3418 * mc7_calc_size - calculate MC7 memory size
3419 * @cfg: the MC7 configuration
3420 *
3421 * Calculates the size of an MC7 memory in bytes from the value of its
3422 * configuration register.
3423 */
Roland Dreier7b9b0942008-01-29 14:45:11 -08003424static unsigned int mc7_calc_size(u32 cfg)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003425{
3426 unsigned int width = G_WIDTH(cfg);
3427 unsigned int banks = !!(cfg & F_BKS) + 1;
3428 unsigned int org = !!(cfg & F_ORG) + 1;
3429 unsigned int density = G_DEN(cfg);
3430 unsigned int MBs = ((256 << density) * banks) / (org << width);
3431
3432 return MBs << 20;
3433}
3434
Roland Dreier7b9b0942008-01-29 14:45:11 -08003435static void mc7_prep(struct adapter *adapter, struct mc7 *mc7,
3436 unsigned int base_addr, const char *name)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003437{
3438 u32 cfg;
3439
3440 mc7->adapter = adapter;
3441 mc7->name = name;
3442 mc7->offset = base_addr - MC7_PMRX_BASE_ADDR;
3443 cfg = t3_read_reg(adapter, mc7->offset + A_MC7_CFG);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003444 mc7->size = mc7->size = G_DEN(cfg) == M_DEN ? 0 : mc7_calc_size(cfg);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003445 mc7->width = G_WIDTH(cfg);
3446}
3447
3448void mac_prep(struct cmac *mac, struct adapter *adapter, int index)
3449{
3450 mac->adapter = adapter;
3451 mac->offset = (XGMAC0_1_BASE_ADDR - XGMAC0_0_BASE_ADDR) * index;
3452 mac->nucast = 1;
3453
3454 if (adapter->params.rev == 0 && uses_xaui(adapter)) {
3455 t3_write_reg(adapter, A_XGM_SERDES_CTRL + mac->offset,
3456 is_10G(adapter) ? 0x2901c04 : 0x2301c04);
3457 t3_set_reg_field(adapter, A_XGM_PORT_CFG + mac->offset,
3458 F_ENRGMII, 0);
3459 }
3460}
3461
3462void early_hw_init(struct adapter *adapter, const struct adapter_info *ai)
3463{
3464 u32 val = V_PORTSPEED(is_10G(adapter) ? 3 : 2);
3465
3466 mi1_init(adapter, ai);
3467 t3_write_reg(adapter, A_I2C_CFG, /* set for 80KHz */
3468 V_I2C_CLKDIV(adapter->params.vpd.cclk / 80 - 1));
3469 t3_write_reg(adapter, A_T3DBG_GPIO_EN,
3470 ai->gpio_out | F_GPIO0_OEN | F_GPIO0_OUT_VAL);
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003471 t3_write_reg(adapter, A_MC5_DB_SERVER_INDEX, 0);
Divy Le Rayb8819552007-12-17 18:47:31 -08003472 t3_write_reg(adapter, A_SG_OCO_BASE, V_BASE1(0xfff));
Divy Le Ray4d22de32007-01-18 22:04:14 -05003473
3474 if (adapter->params.rev == 0 || !uses_xaui(adapter))
3475 val |= F_ENRGMII;
3476
3477 /* Enable MAC clocks so we can access the registers */
3478 t3_write_reg(adapter, A_XGM_PORT_CFG, val);
3479 t3_read_reg(adapter, A_XGM_PORT_CFG);
3480
3481 val |= F_CLKDIVRESET_;
3482 t3_write_reg(adapter, A_XGM_PORT_CFG, val);
3483 t3_read_reg(adapter, A_XGM_PORT_CFG);
3484 t3_write_reg(adapter, XGM_REG(A_XGM_PORT_CFG, 1), val);
3485 t3_read_reg(adapter, A_XGM_PORT_CFG);
3486}
3487
3488/*
Jeff Garzik2eab17a2007-11-23 21:59:45 -05003489 * Reset the adapter.
Divy Le Raye4d08352007-03-18 13:10:17 -07003490 * Older PCIe cards lose their config space during reset, PCI-X
Divy Le Ray4d22de32007-01-18 22:04:14 -05003491 * ones don't.
3492 */
Divy Le Ray20d3fc12008-10-08 17:36:03 -07003493int t3_reset_adapter(struct adapter *adapter)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003494{
Jeff Garzik2eab17a2007-11-23 21:59:45 -05003495 int i, save_and_restore_pcie =
Divy Le Raye4d08352007-03-18 13:10:17 -07003496 adapter->params.rev < T3_REV_B2 && is_pcie(adapter);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003497 uint16_t devid = 0;
3498
Divy Le Raye4d08352007-03-18 13:10:17 -07003499 if (save_and_restore_pcie)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003500 pci_save_state(adapter->pdev);
3501 t3_write_reg(adapter, A_PL_RST, F_CRSTWRM | F_CRSTWRMMODE);
3502
3503 /*
3504 * Delay. Give Some time to device to reset fully.
3505 * XXX The delay time should be modified.
3506 */
3507 for (i = 0; i < 10; i++) {
3508 msleep(50);
3509 pci_read_config_word(adapter->pdev, 0x00, &devid);
3510 if (devid == 0x1425)
3511 break;
3512 }
3513
3514 if (devid != 0x1425)
3515 return -1;
3516
Divy Le Raye4d08352007-03-18 13:10:17 -07003517 if (save_and_restore_pcie)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003518 pci_restore_state(adapter->pdev);
3519 return 0;
3520}
3521
Roland Dreier7b9b0942008-01-29 14:45:11 -08003522static int init_parity(struct adapter *adap)
Divy Le Rayb8819552007-12-17 18:47:31 -08003523{
3524 int i, err, addr;
3525
3526 if (t3_read_reg(adap, A_SG_CONTEXT_CMD) & F_CONTEXT_CMD_BUSY)
3527 return -EBUSY;
3528
3529 for (err = i = 0; !err && i < 16; i++)
3530 err = clear_sge_ctxt(adap, i, F_EGRESS);
3531 for (i = 0xfff0; !err && i <= 0xffff; i++)
3532 err = clear_sge_ctxt(adap, i, F_EGRESS);
3533 for (i = 0; !err && i < SGE_QSETS; i++)
3534 err = clear_sge_ctxt(adap, i, F_RESPONSEQ);
3535 if (err)
3536 return err;
3537
3538 t3_write_reg(adap, A_CIM_IBQ_DBG_DATA, 0);
3539 for (i = 0; i < 4; i++)
3540 for (addr = 0; addr <= M_IBQDBGADDR; addr++) {
3541 t3_write_reg(adap, A_CIM_IBQ_DBG_CFG, F_IBQDBGEN |
3542 F_IBQDBGWR | V_IBQDBGQID(i) |
3543 V_IBQDBGADDR(addr));
3544 err = t3_wait_op_done(adap, A_CIM_IBQ_DBG_CFG,
3545 F_IBQDBGBUSY, 0, 2, 1);
3546 if (err)
3547 return err;
3548 }
3549 return 0;
3550}
3551
Divy Le Ray4d22de32007-01-18 22:04:14 -05003552/*
3553 * Initialize adapter SW state for the various HW modules, set initial values
3554 * for some adapter tunables, take PHYs out of reset, and initialize the MDIO
3555 * interface.
3556 */
Roland Dreier7b9b0942008-01-29 14:45:11 -08003557int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
3558 int reset)
Divy Le Ray4d22de32007-01-18 22:04:14 -05003559{
3560 int ret;
Divy Le Ray04497982008-10-08 17:38:29 -07003561 unsigned int i, j = -1;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003562
3563 get_pci_mode(adapter, &adapter->params.pci);
3564
3565 adapter->params.info = ai;
3566 adapter->params.nports = ai->nports;
3567 adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
3568 adapter->params.linkpoll_period = 0;
3569 adapter->params.stats_update_period = is_10G(adapter) ?
3570 MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
3571 adapter->params.pci.vpd_cap_addr =
3572 pci_find_capability(adapter->pdev, PCI_CAP_ID_VPD);
3573 ret = get_vpd_params(adapter, &adapter->params.vpd);
3574 if (ret < 0)
3575 return ret;
3576
3577 if (reset && t3_reset_adapter(adapter))
3578 return -1;
3579
3580 t3_sge_prep(adapter, &adapter->params.sge);
3581
3582 if (adapter->params.vpd.mclk) {
3583 struct tp_params *p = &adapter->params.tp;
3584
3585 mc7_prep(adapter, &adapter->pmrx, MC7_PMRX_BASE_ADDR, "PMRX");
3586 mc7_prep(adapter, &adapter->pmtx, MC7_PMTX_BASE_ADDR, "PMTX");
3587 mc7_prep(adapter, &adapter->cm, MC7_CM_BASE_ADDR, "CM");
3588
3589 p->nchan = ai->nports;
3590 p->pmrx_size = t3_mc7_size(&adapter->pmrx);
3591 p->pmtx_size = t3_mc7_size(&adapter->pmtx);
3592 p->cm_size = t3_mc7_size(&adapter->cm);
3593 p->chan_rx_size = p->pmrx_size / 2; /* only 1 Rx channel */
3594 p->chan_tx_size = p->pmtx_size / p->nchan;
3595 p->rx_pg_size = 64 * 1024;
3596 p->tx_pg_size = is_10G(adapter) ? 64 * 1024 : 16 * 1024;
3597 p->rx_num_pgs = pm_num_pages(p->chan_rx_size, p->rx_pg_size);
3598 p->tx_num_pgs = pm_num_pages(p->chan_tx_size, p->tx_pg_size);
3599 p->ntimer_qs = p->cm_size >= (128 << 20) ||
3600 adapter->params.rev > 0 ? 12 : 6;
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003601 }
Divy Le Ray4d22de32007-01-18 22:04:14 -05003602
Divy Le Ray8ac3ba62007-03-31 00:23:19 -07003603 adapter->params.offload = t3_mc7_size(&adapter->pmrx) &&
3604 t3_mc7_size(&adapter->pmtx) &&
3605 t3_mc7_size(&adapter->cm);
3606
3607 if (is_offload(adapter)) {
Divy Le Ray4d22de32007-01-18 22:04:14 -05003608 adapter->params.mc5.nservers = DEFAULT_NSERVERS;
3609 adapter->params.mc5.nfilters = adapter->params.rev > 0 ?
3610 DEFAULT_NFILTERS : 0;
3611 adapter->params.mc5.nroutes = 0;
3612 t3_mc5_prep(adapter, &adapter->mc5, MC5_MODE_144_BIT);
3613
3614 init_mtus(adapter->params.mtus);
3615 init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
3616 }
3617
3618 early_hw_init(adapter, ai);
Divy Le Rayb8819552007-12-17 18:47:31 -08003619 ret = init_parity(adapter);
3620 if (ret)
3621 return ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003622
3623 for_each_port(adapter, i) {
3624 u8 hw_addr[6];
Divy Le Ray04497982008-10-08 17:38:29 -07003625 const struct port_type_info *pti;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003626 struct port_info *p = adap2pinfo(adapter, i);
3627
Divy Le Ray04497982008-10-08 17:38:29 -07003628 while (!adapter->params.vpd.port_type[++j])
3629 ;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003630
Divy Le Ray04497982008-10-08 17:38:29 -07003631 pti = &port_types[adapter->params.vpd.port_type[j]];
3632 ret = pti->phy_prep(&p->phy, adapter, ai->phy_base_addr + j,
3633 ai->mdio_ops);
Divy Le Ray78e46892008-10-08 17:38:01 -07003634 if (ret)
3635 return ret;
Divy Le Ray4d22de32007-01-18 22:04:14 -05003636 mac_prep(&p->mac, adapter, j);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003637
3638 /*
3639 * The VPD EEPROM stores the base Ethernet address for the
3640 * card. A port's address is derived from the base by adding
3641 * the port's index to the base's low octet.
3642 */
3643 memcpy(hw_addr, adapter->params.vpd.eth_base, 5);
3644 hw_addr[5] = adapter->params.vpd.eth_base[5] + i;
3645
3646 memcpy(adapter->port[i]->dev_addr, hw_addr,
3647 ETH_ALEN);
3648 memcpy(adapter->port[i]->perm_addr, hw_addr,
3649 ETH_ALEN);
Divy Le Ray04497982008-10-08 17:38:29 -07003650 init_link_config(&p->link_config, p->phy.caps);
Divy Le Ray4d22de32007-01-18 22:04:14 -05003651 p->phy.ops->power_down(&p->phy, 1);
Divy Le Ray04497982008-10-08 17:38:29 -07003652 if (!(p->phy.caps & SUPPORTED_IRQ))
Divy Le Ray4d22de32007-01-18 22:04:14 -05003653 adapter->params.linkpoll_period = 10;
3654 }
3655
3656 return 0;
3657}
3658
3659void t3_led_ready(struct adapter *adapter)
3660{
3661 t3_set_reg_field(adapter, A_T3DBG_GPIO_EN, F_GPIO0_OUT_VAL,
3662 F_GPIO0_OUT_VAL);
3663}
Divy Le Ray204e2f92008-05-06 19:26:01 -07003664
3665int t3_replay_prep_adapter(struct adapter *adapter)
3666{
3667 const struct adapter_info *ai = adapter->params.info;
Divy Le Ray04497982008-10-08 17:38:29 -07003668 unsigned int i, j = -1;
Divy Le Ray204e2f92008-05-06 19:26:01 -07003669 int ret;
3670
3671 early_hw_init(adapter, ai);
3672 ret = init_parity(adapter);
3673 if (ret)
3674 return ret;
3675
3676 for_each_port(adapter, i) {
Divy Le Ray04497982008-10-08 17:38:29 -07003677 const struct port_type_info *pti;
Divy Le Ray204e2f92008-05-06 19:26:01 -07003678 struct port_info *p = adap2pinfo(adapter, i);
Divy Le Ray204e2f92008-05-06 19:26:01 -07003679
Divy Le Ray04497982008-10-08 17:38:29 -07003680 while (!adapter->params.vpd.port_type[++j])
3681 ;
3682
3683 pti = &port_types[adapter->params.vpd.port_type[j]];
3684 ret = pti->phy_prep(&p->phy, adapter, p->phy.addr, NULL);
Divy Le Ray78e46892008-10-08 17:38:01 -07003685 if (ret)
3686 return ret;
Divy Le Ray204e2f92008-05-06 19:26:01 -07003687 p->phy.ops->power_down(&p->phy, 1);
Divy Le Ray204e2f92008-05-06 19:26:01 -07003688 }
3689
3690return 0;
3691}
3692