blob: 7857b463012447c404eb256206921427cc20d56c [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chan206cc832006-01-23 16:14:05 -08003 * Copyright (c) 2004, 2005, 2006 Broadcom Corporation
Michael Chanb6016b72005-05-26 13:03:09 -07004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation.
8 *
9 * Written by: Michael Chan (mchan@broadcom.com)
10 */
11
Michael Chanf2a4f052006-03-23 01:13:12 -080012
13#include <linux/module.h>
14#include <linux/moduleparam.h>
15
16#include <linux/kernel.h>
17#include <linux/timer.h>
18#include <linux/errno.h>
19#include <linux/ioport.h>
20#include <linux/slab.h>
21#include <linux/vmalloc.h>
22#include <linux/interrupt.h>
23#include <linux/pci.h>
24#include <linux/init.h>
25#include <linux/netdevice.h>
26#include <linux/etherdevice.h>
27#include <linux/skbuff.h>
28#include <linux/dma-mapping.h>
29#include <asm/bitops.h>
30#include <asm/io.h>
31#include <asm/irq.h>
32#include <linux/delay.h>
33#include <asm/byteorder.h>
Michael Chanc86a31f2006-06-13 15:03:47 -070034#include <asm/page.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080035#include <linux/time.h>
36#include <linux/ethtool.h>
37#include <linux/mii.h>
38#ifdef NETIF_F_HW_VLAN_TX
39#include <linux/if_vlan.h>
40#define BCM_VLAN 1
41#endif
42#ifdef NETIF_F_TSO
43#include <net/ip.h>
44#include <net/tcp.h>
45#include <net/checksum.h>
46#define BCM_TSO 1
47#endif
48#include <linux/workqueue.h>
49#include <linux/crc32.h>
50#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080051#include <linux/cache.h>
Michael Chanfba9fe92006-06-12 22:21:25 -070052#include <linux/zlib.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080053
Michael Chanb6016b72005-05-26 13:03:09 -070054#include "bnx2.h"
55#include "bnx2_fw.h"
56
57#define DRV_MODULE_NAME "bnx2"
58#define PFX DRV_MODULE_NAME ": "
Michael Chan932f3772006-08-15 01:39:36 -070059#define DRV_MODULE_VERSION "1.4.44"
60#define DRV_MODULE_RELDATE "August 10, 2006"
Michael Chanb6016b72005-05-26 13:03:09 -070061
62#define RUN_AT(x) (jiffies + (x))
63
64/* Time in jiffies before concluding the transmitter is hung. */
65#define TX_TIMEOUT (5*HZ)
66
Randy Dunlape19360f2006-04-10 23:22:06 -070067static const char version[] __devinitdata =
Michael Chanb6016b72005-05-26 13:03:09 -070068 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
69
70MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Michael Chan05d0f1c2005-11-04 08:53:48 -080071MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070072MODULE_LICENSE("GPL");
73MODULE_VERSION(DRV_MODULE_VERSION);
74
75static int disable_msi = 0;
76
77module_param(disable_msi, int, 0);
78MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
79
80typedef enum {
81 BCM5706 = 0,
82 NC370T,
83 NC370I,
84 BCM5706S,
85 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080086 BCM5708,
87 BCM5708S,
Michael Chanb6016b72005-05-26 13:03:09 -070088} board_t;
89
90/* indexed by board_t, above */
Arjan van de Venf71e1302006-03-03 21:33:57 -050091static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -070092 char *name;
93} board_info[] __devinitdata = {
94 { "Broadcom NetXtreme II BCM5706 1000Base-T" },
95 { "HP NC370T Multifunction Gigabit Server Adapter" },
96 { "HP NC370i Multifunction Gigabit Server Adapter" },
97 { "Broadcom NetXtreme II BCM5706 1000Base-SX" },
98 { "HP NC370F Multifunction Gigabit Server Adapter" },
Michael Chan5b0c76a2005-11-04 08:45:49 -080099 { "Broadcom NetXtreme II BCM5708 1000Base-T" },
100 { "Broadcom NetXtreme II BCM5708 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700101 };
102
103static struct pci_device_id bnx2_pci_tbl[] = {
104 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
105 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
106 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
107 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
108 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
109 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800110 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
111 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700112 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
113 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
114 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
115 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800116 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
117 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanb6016b72005-05-26 13:03:09 -0700118 { 0, }
119};
120
121static struct flash_spec flash_table[] =
122{
123 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800124 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chanb6016b72005-05-26 13:03:09 -0700125 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
126 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
127 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800128 /* Expansion entry 0001 */
129 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chanb6016b72005-05-26 13:03:09 -0700130 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800131 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
132 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700133 /* Saifun SA25F010 (non-buffered flash) */
134 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800135 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chanb6016b72005-05-26 13:03:09 -0700136 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
137 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
138 "Non-buffered flash (128kB)"},
139 /* Saifun SA25F020 (non-buffered flash) */
140 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800141 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chanb6016b72005-05-26 13:03:09 -0700142 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
143 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
144 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800145 /* Expansion entry 0100 */
146 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
147 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
148 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
149 "Entry 0100"},
150 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
151 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
152 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
153 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
154 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
155 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
156 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
157 0, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
158 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
159 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
160 /* Saifun SA25F005 (non-buffered flash) */
161 /* strap, cfg1, & write1 need updates */
162 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
163 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
164 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
165 "Non-buffered flash (64kB)"},
166 /* Fast EEPROM */
167 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
168 1, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
169 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
170 "EEPROM - fast"},
171 /* Expansion entry 1001 */
172 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
173 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
174 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
175 "Entry 1001"},
176 /* Expansion entry 1010 */
177 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
178 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
179 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
180 "Entry 1010"},
181 /* ATMEL AT45DB011B (buffered flash) */
182 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
183 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
184 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
185 "Buffered flash (128kB)"},
186 /* Expansion entry 1100 */
187 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
188 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
189 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
190 "Entry 1100"},
191 /* Expansion entry 1101 */
192 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
193 0, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
194 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
195 "Entry 1101"},
196 /* Ateml Expansion entry 1110 */
197 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
198 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
199 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
200 "Entry 1110 (Atmel)"},
201 /* ATMEL AT45DB021B (buffered flash) */
202 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
203 1, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
204 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
205 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700206};
207
208MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
209
Michael Chane89bbf12005-08-25 15:36:58 -0700210static inline u32 bnx2_tx_avail(struct bnx2 *bp)
211{
Michael Chan2f8af122006-08-15 01:39:10 -0700212 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700213
Michael Chan2f8af122006-08-15 01:39:10 -0700214 smp_mb();
215 diff = TX_RING_IDX(bp->tx_prod) - TX_RING_IDX(bp->tx_cons);
Michael Chane89bbf12005-08-25 15:36:58 -0700216 if (diff > MAX_TX_DESC_CNT)
217 diff = (diff & MAX_TX_DESC_CNT) - 1;
218 return (bp->tx_ring_size - diff);
219}
220
Michael Chanb6016b72005-05-26 13:03:09 -0700221static u32
222bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
223{
224 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
225 return (REG_RD(bp, BNX2_PCICFG_REG_WINDOW));
226}
227
228static void
229bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
230{
231 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
232 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
233}
234
235static void
236bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
237{
238 offset += cid_addr;
239 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
240 REG_WR(bp, BNX2_CTX_DATA, val);
241}
242
243static int
244bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
245{
246 u32 val1;
247 int i, ret;
248
249 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
250 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
251 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
252
253 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
254 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
255
256 udelay(40);
257 }
258
259 val1 = (bp->phy_addr << 21) | (reg << 16) |
260 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
261 BNX2_EMAC_MDIO_COMM_START_BUSY;
262 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
263
264 for (i = 0; i < 50; i++) {
265 udelay(10);
266
267 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
268 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
269 udelay(5);
270
271 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
272 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
273
274 break;
275 }
276 }
277
278 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
279 *val = 0x0;
280 ret = -EBUSY;
281 }
282 else {
283 *val = val1;
284 ret = 0;
285 }
286
287 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
288 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
289 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
290
291 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
292 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
293
294 udelay(40);
295 }
296
297 return ret;
298}
299
300static int
301bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
302{
303 u32 val1;
304 int i, ret;
305
306 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
307 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
308 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
309
310 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
311 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
312
313 udelay(40);
314 }
315
316 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
317 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
318 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
319 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
320
321 for (i = 0; i < 50; i++) {
322 udelay(10);
323
324 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
325 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
326 udelay(5);
327 break;
328 }
329 }
330
331 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
332 ret = -EBUSY;
333 else
334 ret = 0;
335
336 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
337 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
338 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
339
340 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
341 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
342
343 udelay(40);
344 }
345
346 return ret;
347}
348
349static void
350bnx2_disable_int(struct bnx2 *bp)
351{
352 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
353 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
354 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
355}
356
357static void
358bnx2_enable_int(struct bnx2 *bp)
359{
Michael Chanb6016b72005-05-26 13:03:09 -0700360 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chan1269a8a2006-01-23 16:11:03 -0800361 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
362 BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx);
363
364 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -0700365 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx);
366
Michael Chanbf5295b2006-03-23 01:11:56 -0800367 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700368}
369
370static void
371bnx2_disable_int_sync(struct bnx2 *bp)
372{
373 atomic_inc(&bp->intr_sem);
374 bnx2_disable_int(bp);
375 synchronize_irq(bp->pdev->irq);
376}
377
378static void
379bnx2_netif_stop(struct bnx2 *bp)
380{
381 bnx2_disable_int_sync(bp);
382 if (netif_running(bp->dev)) {
383 netif_poll_disable(bp->dev);
384 netif_tx_disable(bp->dev);
385 bp->dev->trans_start = jiffies; /* prevent tx timeout */
386 }
387}
388
389static void
390bnx2_netif_start(struct bnx2 *bp)
391{
392 if (atomic_dec_and_test(&bp->intr_sem)) {
393 if (netif_running(bp->dev)) {
394 netif_wake_queue(bp->dev);
395 netif_poll_enable(bp->dev);
396 bnx2_enable_int(bp);
397 }
398 }
399}
400
401static void
402bnx2_free_mem(struct bnx2 *bp)
403{
Michael Chan13daffa2006-03-20 17:49:20 -0800404 int i;
405
Michael Chanb6016b72005-05-26 13:03:09 -0700406 if (bp->status_blk) {
Michael Chan0f31f992006-03-23 01:12:38 -0800407 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700408 bp->status_blk, bp->status_blk_mapping);
409 bp->status_blk = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800410 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700411 }
412 if (bp->tx_desc_ring) {
413 pci_free_consistent(bp->pdev,
414 sizeof(struct tx_bd) * TX_DESC_CNT,
415 bp->tx_desc_ring, bp->tx_desc_mapping);
416 bp->tx_desc_ring = NULL;
417 }
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400418 kfree(bp->tx_buf_ring);
419 bp->tx_buf_ring = NULL;
Michael Chan13daffa2006-03-20 17:49:20 -0800420 for (i = 0; i < bp->rx_max_ring; i++) {
421 if (bp->rx_desc_ring[i])
422 pci_free_consistent(bp->pdev,
423 sizeof(struct rx_bd) * RX_DESC_CNT,
424 bp->rx_desc_ring[i],
425 bp->rx_desc_mapping[i]);
426 bp->rx_desc_ring[i] = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700427 }
Michael Chan13daffa2006-03-20 17:49:20 -0800428 vfree(bp->rx_buf_ring);
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400429 bp->rx_buf_ring = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700430}
431
432static int
433bnx2_alloc_mem(struct bnx2 *bp)
434{
Michael Chan0f31f992006-03-23 01:12:38 -0800435 int i, status_blk_size;
Michael Chan13daffa2006-03-20 17:49:20 -0800436
Michael Chan0f31f992006-03-23 01:12:38 -0800437 bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
438 GFP_KERNEL);
Michael Chanb6016b72005-05-26 13:03:09 -0700439 if (bp->tx_buf_ring == NULL)
440 return -ENOMEM;
441
Michael Chanb6016b72005-05-26 13:03:09 -0700442 bp->tx_desc_ring = pci_alloc_consistent(bp->pdev,
443 sizeof(struct tx_bd) *
444 TX_DESC_CNT,
445 &bp->tx_desc_mapping);
446 if (bp->tx_desc_ring == NULL)
447 goto alloc_mem_err;
448
Michael Chan13daffa2006-03-20 17:49:20 -0800449 bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
450 bp->rx_max_ring);
Michael Chanb6016b72005-05-26 13:03:09 -0700451 if (bp->rx_buf_ring == NULL)
452 goto alloc_mem_err;
453
Michael Chan13daffa2006-03-20 17:49:20 -0800454 memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *
455 bp->rx_max_ring);
456
457 for (i = 0; i < bp->rx_max_ring; i++) {
458 bp->rx_desc_ring[i] =
459 pci_alloc_consistent(bp->pdev,
460 sizeof(struct rx_bd) * RX_DESC_CNT,
461 &bp->rx_desc_mapping[i]);
462 if (bp->rx_desc_ring[i] == NULL)
463 goto alloc_mem_err;
464
465 }
Michael Chanb6016b72005-05-26 13:03:09 -0700466
Michael Chan0f31f992006-03-23 01:12:38 -0800467 /* Combine status and statistics blocks into one allocation. */
468 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
469 bp->status_stats_size = status_blk_size +
470 sizeof(struct statistics_block);
471
472 bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700473 &bp->status_blk_mapping);
474 if (bp->status_blk == NULL)
475 goto alloc_mem_err;
476
Michael Chan0f31f992006-03-23 01:12:38 -0800477 memset(bp->status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700478
Michael Chan0f31f992006-03-23 01:12:38 -0800479 bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
480 status_blk_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700481
Michael Chan0f31f992006-03-23 01:12:38 -0800482 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700483
484 return 0;
485
486alloc_mem_err:
487 bnx2_free_mem(bp);
488 return -ENOMEM;
489}
490
491static void
Michael Chane3648b32005-11-04 08:51:21 -0800492bnx2_report_fw_link(struct bnx2 *bp)
493{
494 u32 fw_link_status = 0;
495
496 if (bp->link_up) {
497 u32 bmsr;
498
499 switch (bp->line_speed) {
500 case SPEED_10:
501 if (bp->duplex == DUPLEX_HALF)
502 fw_link_status = BNX2_LINK_STATUS_10HALF;
503 else
504 fw_link_status = BNX2_LINK_STATUS_10FULL;
505 break;
506 case SPEED_100:
507 if (bp->duplex == DUPLEX_HALF)
508 fw_link_status = BNX2_LINK_STATUS_100HALF;
509 else
510 fw_link_status = BNX2_LINK_STATUS_100FULL;
511 break;
512 case SPEED_1000:
513 if (bp->duplex == DUPLEX_HALF)
514 fw_link_status = BNX2_LINK_STATUS_1000HALF;
515 else
516 fw_link_status = BNX2_LINK_STATUS_1000FULL;
517 break;
518 case SPEED_2500:
519 if (bp->duplex == DUPLEX_HALF)
520 fw_link_status = BNX2_LINK_STATUS_2500HALF;
521 else
522 fw_link_status = BNX2_LINK_STATUS_2500FULL;
523 break;
524 }
525
526 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
527
528 if (bp->autoneg) {
529 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
530
531 bnx2_read_phy(bp, MII_BMSR, &bmsr);
532 bnx2_read_phy(bp, MII_BMSR, &bmsr);
533
534 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
535 bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
536 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
537 else
538 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
539 }
540 }
541 else
542 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
543
544 REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
545}
546
547static void
Michael Chanb6016b72005-05-26 13:03:09 -0700548bnx2_report_link(struct bnx2 *bp)
549{
550 if (bp->link_up) {
551 netif_carrier_on(bp->dev);
552 printk(KERN_INFO PFX "%s NIC Link is Up, ", bp->dev->name);
553
554 printk("%d Mbps ", bp->line_speed);
555
556 if (bp->duplex == DUPLEX_FULL)
557 printk("full duplex");
558 else
559 printk("half duplex");
560
561 if (bp->flow_ctrl) {
562 if (bp->flow_ctrl & FLOW_CTRL_RX) {
563 printk(", receive ");
564 if (bp->flow_ctrl & FLOW_CTRL_TX)
565 printk("& transmit ");
566 }
567 else {
568 printk(", transmit ");
569 }
570 printk("flow control ON");
571 }
572 printk("\n");
573 }
574 else {
575 netif_carrier_off(bp->dev);
576 printk(KERN_ERR PFX "%s NIC Link is Down\n", bp->dev->name);
577 }
Michael Chane3648b32005-11-04 08:51:21 -0800578
579 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700580}
581
582static void
583bnx2_resolve_flow_ctrl(struct bnx2 *bp)
584{
585 u32 local_adv, remote_adv;
586
587 bp->flow_ctrl = 0;
588 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
589 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
590
591 if (bp->duplex == DUPLEX_FULL) {
592 bp->flow_ctrl = bp->req_flow_ctrl;
593 }
594 return;
595 }
596
597 if (bp->duplex != DUPLEX_FULL) {
598 return;
599 }
600
Michael Chan5b0c76a2005-11-04 08:45:49 -0800601 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
602 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
603 u32 val;
604
605 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
606 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
607 bp->flow_ctrl |= FLOW_CTRL_TX;
608 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
609 bp->flow_ctrl |= FLOW_CTRL_RX;
610 return;
611 }
612
Michael Chanb6016b72005-05-26 13:03:09 -0700613 bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
614 bnx2_read_phy(bp, MII_LPA, &remote_adv);
615
616 if (bp->phy_flags & PHY_SERDES_FLAG) {
617 u32 new_local_adv = 0;
618 u32 new_remote_adv = 0;
619
620 if (local_adv & ADVERTISE_1000XPAUSE)
621 new_local_adv |= ADVERTISE_PAUSE_CAP;
622 if (local_adv & ADVERTISE_1000XPSE_ASYM)
623 new_local_adv |= ADVERTISE_PAUSE_ASYM;
624 if (remote_adv & ADVERTISE_1000XPAUSE)
625 new_remote_adv |= ADVERTISE_PAUSE_CAP;
626 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
627 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
628
629 local_adv = new_local_adv;
630 remote_adv = new_remote_adv;
631 }
632
633 /* See Table 28B-3 of 802.3ab-1999 spec. */
634 if (local_adv & ADVERTISE_PAUSE_CAP) {
635 if(local_adv & ADVERTISE_PAUSE_ASYM) {
636 if (remote_adv & ADVERTISE_PAUSE_CAP) {
637 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
638 }
639 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
640 bp->flow_ctrl = FLOW_CTRL_RX;
641 }
642 }
643 else {
644 if (remote_adv & ADVERTISE_PAUSE_CAP) {
645 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
646 }
647 }
648 }
649 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
650 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
651 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
652
653 bp->flow_ctrl = FLOW_CTRL_TX;
654 }
655 }
656}
657
658static int
Michael Chan5b0c76a2005-11-04 08:45:49 -0800659bnx2_5708s_linkup(struct bnx2 *bp)
660{
661 u32 val;
662
663 bp->link_up = 1;
664 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
665 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
666 case BCM5708S_1000X_STAT1_SPEED_10:
667 bp->line_speed = SPEED_10;
668 break;
669 case BCM5708S_1000X_STAT1_SPEED_100:
670 bp->line_speed = SPEED_100;
671 break;
672 case BCM5708S_1000X_STAT1_SPEED_1G:
673 bp->line_speed = SPEED_1000;
674 break;
675 case BCM5708S_1000X_STAT1_SPEED_2G5:
676 bp->line_speed = SPEED_2500;
677 break;
678 }
679 if (val & BCM5708S_1000X_STAT1_FD)
680 bp->duplex = DUPLEX_FULL;
681 else
682 bp->duplex = DUPLEX_HALF;
683
684 return 0;
685}
686
687static int
688bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -0700689{
690 u32 bmcr, local_adv, remote_adv, common;
691
692 bp->link_up = 1;
693 bp->line_speed = SPEED_1000;
694
695 bnx2_read_phy(bp, MII_BMCR, &bmcr);
696 if (bmcr & BMCR_FULLDPLX) {
697 bp->duplex = DUPLEX_FULL;
698 }
699 else {
700 bp->duplex = DUPLEX_HALF;
701 }
702
703 if (!(bmcr & BMCR_ANENABLE)) {
704 return 0;
705 }
706
707 bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
708 bnx2_read_phy(bp, MII_LPA, &remote_adv);
709
710 common = local_adv & remote_adv;
711 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
712
713 if (common & ADVERTISE_1000XFULL) {
714 bp->duplex = DUPLEX_FULL;
715 }
716 else {
717 bp->duplex = DUPLEX_HALF;
718 }
719 }
720
721 return 0;
722}
723
724static int
725bnx2_copper_linkup(struct bnx2 *bp)
726{
727 u32 bmcr;
728
729 bnx2_read_phy(bp, MII_BMCR, &bmcr);
730 if (bmcr & BMCR_ANENABLE) {
731 u32 local_adv, remote_adv, common;
732
733 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
734 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
735
736 common = local_adv & (remote_adv >> 2);
737 if (common & ADVERTISE_1000FULL) {
738 bp->line_speed = SPEED_1000;
739 bp->duplex = DUPLEX_FULL;
740 }
741 else if (common & ADVERTISE_1000HALF) {
742 bp->line_speed = SPEED_1000;
743 bp->duplex = DUPLEX_HALF;
744 }
745 else {
746 bnx2_read_phy(bp, MII_ADVERTISE, &local_adv);
747 bnx2_read_phy(bp, MII_LPA, &remote_adv);
748
749 common = local_adv & remote_adv;
750 if (common & ADVERTISE_100FULL) {
751 bp->line_speed = SPEED_100;
752 bp->duplex = DUPLEX_FULL;
753 }
754 else if (common & ADVERTISE_100HALF) {
755 bp->line_speed = SPEED_100;
756 bp->duplex = DUPLEX_HALF;
757 }
758 else if (common & ADVERTISE_10FULL) {
759 bp->line_speed = SPEED_10;
760 bp->duplex = DUPLEX_FULL;
761 }
762 else if (common & ADVERTISE_10HALF) {
763 bp->line_speed = SPEED_10;
764 bp->duplex = DUPLEX_HALF;
765 }
766 else {
767 bp->line_speed = 0;
768 bp->link_up = 0;
769 }
770 }
771 }
772 else {
773 if (bmcr & BMCR_SPEED100) {
774 bp->line_speed = SPEED_100;
775 }
776 else {
777 bp->line_speed = SPEED_10;
778 }
779 if (bmcr & BMCR_FULLDPLX) {
780 bp->duplex = DUPLEX_FULL;
781 }
782 else {
783 bp->duplex = DUPLEX_HALF;
784 }
785 }
786
787 return 0;
788}
789
790static int
791bnx2_set_mac_link(struct bnx2 *bp)
792{
793 u32 val;
794
795 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
796 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
797 (bp->duplex == DUPLEX_HALF)) {
798 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
799 }
800
801 /* Configure the EMAC mode register. */
802 val = REG_RD(bp, BNX2_EMAC_MODE);
803
804 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -0800805 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
806 BNX2_EMAC_MODE_25G);
Michael Chanb6016b72005-05-26 13:03:09 -0700807
808 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -0800809 switch (bp->line_speed) {
810 case SPEED_10:
811 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
812 val |= BNX2_EMAC_MODE_PORT_MII_10;
813 break;
814 }
815 /* fall through */
816 case SPEED_100:
817 val |= BNX2_EMAC_MODE_PORT_MII;
818 break;
819 case SPEED_2500:
820 val |= BNX2_EMAC_MODE_25G;
821 /* fall through */
822 case SPEED_1000:
823 val |= BNX2_EMAC_MODE_PORT_GMII;
824 break;
825 }
Michael Chanb6016b72005-05-26 13:03:09 -0700826 }
827 else {
828 val |= BNX2_EMAC_MODE_PORT_GMII;
829 }
830
831 /* Set the MAC to operate in the appropriate duplex mode. */
832 if (bp->duplex == DUPLEX_HALF)
833 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
834 REG_WR(bp, BNX2_EMAC_MODE, val);
835
836 /* Enable/disable rx PAUSE. */
837 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
838
839 if (bp->flow_ctrl & FLOW_CTRL_RX)
840 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
841 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
842
843 /* Enable/disable tx PAUSE. */
844 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
845 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
846
847 if (bp->flow_ctrl & FLOW_CTRL_TX)
848 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
849 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
850
851 /* Acknowledge the interrupt. */
852 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
853
854 return 0;
855}
856
857static int
858bnx2_set_link(struct bnx2 *bp)
859{
860 u32 bmsr;
861 u8 link_up;
862
863 if (bp->loopback == MAC_LOOPBACK) {
864 bp->link_up = 1;
865 return 0;
866 }
867
868 link_up = bp->link_up;
869
870 bnx2_read_phy(bp, MII_BMSR, &bmsr);
871 bnx2_read_phy(bp, MII_BMSR, &bmsr);
872
873 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
874 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
875 u32 val;
876
877 val = REG_RD(bp, BNX2_EMAC_STATUS);
878 if (val & BNX2_EMAC_STATUS_LINK)
879 bmsr |= BMSR_LSTATUS;
880 else
881 bmsr &= ~BMSR_LSTATUS;
882 }
883
884 if (bmsr & BMSR_LSTATUS) {
885 bp->link_up = 1;
886
887 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -0800888 if (CHIP_NUM(bp) == CHIP_NUM_5706)
889 bnx2_5706s_linkup(bp);
890 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
891 bnx2_5708s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700892 }
893 else {
894 bnx2_copper_linkup(bp);
895 }
896 bnx2_resolve_flow_ctrl(bp);
897 }
898 else {
899 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
900 (bp->autoneg & AUTONEG_SPEED)) {
901
902 u32 bmcr;
903
904 bnx2_read_phy(bp, MII_BMCR, &bmcr);
905 if (!(bmcr & BMCR_ANENABLE)) {
906 bnx2_write_phy(bp, MII_BMCR, bmcr |
907 BMCR_ANENABLE);
908 }
909 }
910 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
911 bp->link_up = 0;
912 }
913
914 if (bp->link_up != link_up) {
915 bnx2_report_link(bp);
916 }
917
918 bnx2_set_mac_link(bp);
919
920 return 0;
921}
922
923static int
924bnx2_reset_phy(struct bnx2 *bp)
925{
926 int i;
927 u32 reg;
928
929 bnx2_write_phy(bp, MII_BMCR, BMCR_RESET);
930
931#define PHY_RESET_MAX_WAIT 100
932 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
933 udelay(10);
934
935 bnx2_read_phy(bp, MII_BMCR, &reg);
936 if (!(reg & BMCR_RESET)) {
937 udelay(20);
938 break;
939 }
940 }
941 if (i == PHY_RESET_MAX_WAIT) {
942 return -EBUSY;
943 }
944 return 0;
945}
946
947static u32
948bnx2_phy_get_pause_adv(struct bnx2 *bp)
949{
950 u32 adv = 0;
951
952 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
953 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
954
955 if (bp->phy_flags & PHY_SERDES_FLAG) {
956 adv = ADVERTISE_1000XPAUSE;
957 }
958 else {
959 adv = ADVERTISE_PAUSE_CAP;
960 }
961 }
962 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
963 if (bp->phy_flags & PHY_SERDES_FLAG) {
964 adv = ADVERTISE_1000XPSE_ASYM;
965 }
966 else {
967 adv = ADVERTISE_PAUSE_ASYM;
968 }
969 }
970 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
971 if (bp->phy_flags & PHY_SERDES_FLAG) {
972 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
973 }
974 else {
975 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
976 }
977 }
978 return adv;
979}
980
981static int
982bnx2_setup_serdes_phy(struct bnx2 *bp)
983{
Michael Chan5b0c76a2005-11-04 08:45:49 -0800984 u32 adv, bmcr, up1;
Michael Chanb6016b72005-05-26 13:03:09 -0700985 u32 new_adv = 0;
986
987 if (!(bp->autoneg & AUTONEG_SPEED)) {
988 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -0800989 int force_link_down = 0;
990
991 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
992 bnx2_read_phy(bp, BCM5708S_UP1, &up1);
993 if (up1 & BCM5708S_UP1_2G5) {
994 up1 &= ~BCM5708S_UP1_2G5;
995 bnx2_write_phy(bp, BCM5708S_UP1, up1);
996 force_link_down = 1;
997 }
998 }
999
1000 bnx2_read_phy(bp, MII_ADVERTISE, &adv);
1001 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
Michael Chanb6016b72005-05-26 13:03:09 -07001002
1003 bnx2_read_phy(bp, MII_BMCR, &bmcr);
1004 new_bmcr = bmcr & ~BMCR_ANENABLE;
1005 new_bmcr |= BMCR_SPEED1000;
1006 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001007 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001008 new_bmcr |= BMCR_FULLDPLX;
1009 }
1010 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001011 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001012 new_bmcr &= ~BMCR_FULLDPLX;
1013 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001014 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001015 /* Force a link down visible on the other side */
1016 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001017 bnx2_write_phy(bp, MII_ADVERTISE, adv &
1018 ~(ADVERTISE_1000XFULL |
1019 ADVERTISE_1000XHALF));
Michael Chanb6016b72005-05-26 13:03:09 -07001020 bnx2_write_phy(bp, MII_BMCR, bmcr |
1021 BMCR_ANRESTART | BMCR_ANENABLE);
1022
1023 bp->link_up = 0;
1024 netif_carrier_off(bp->dev);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001025 bnx2_write_phy(bp, MII_BMCR, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001026 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001027 bnx2_write_phy(bp, MII_ADVERTISE, adv);
Michael Chanb6016b72005-05-26 13:03:09 -07001028 bnx2_write_phy(bp, MII_BMCR, new_bmcr);
1029 }
1030 return 0;
1031 }
1032
Michael Chan5b0c76a2005-11-04 08:45:49 -08001033 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
1034 bnx2_read_phy(bp, BCM5708S_UP1, &up1);
1035 up1 |= BCM5708S_UP1_2G5;
1036 bnx2_write_phy(bp, BCM5708S_UP1, up1);
1037 }
1038
Michael Chanb6016b72005-05-26 13:03:09 -07001039 if (bp->advertising & ADVERTISED_1000baseT_Full)
1040 new_adv |= ADVERTISE_1000XFULL;
1041
1042 new_adv |= bnx2_phy_get_pause_adv(bp);
1043
1044 bnx2_read_phy(bp, MII_ADVERTISE, &adv);
1045 bnx2_read_phy(bp, MII_BMCR, &bmcr);
1046
1047 bp->serdes_an_pending = 0;
1048 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1049 /* Force a link down visible on the other side */
1050 if (bp->link_up) {
1051 int i;
1052
1053 bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
1054 for (i = 0; i < 110; i++) {
1055 udelay(100);
1056 }
1057 }
1058
1059 bnx2_write_phy(bp, MII_ADVERTISE, new_adv);
1060 bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART |
1061 BMCR_ANENABLE);
Michael Chancd339a02005-08-25 15:35:24 -07001062 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
1063 /* Speed up link-up time when the link partner
1064 * does not autonegotiate which is very common
1065 * in blade servers. Some blade servers use
1066 * IPMI for kerboard input and it's important
1067 * to minimize link disruptions. Autoneg. involves
1068 * exchanging base pages plus 3 next pages and
1069 * normally completes in about 120 msec.
1070 */
1071 bp->current_interval = SERDES_AN_TIMEOUT;
1072 bp->serdes_an_pending = 1;
1073 mod_timer(&bp->timer, jiffies + bp->current_interval);
1074 }
Michael Chanb6016b72005-05-26 13:03:09 -07001075 }
1076
1077 return 0;
1078}
1079
1080#define ETHTOOL_ALL_FIBRE_SPEED \
1081 (ADVERTISED_1000baseT_Full)
1082
1083#define ETHTOOL_ALL_COPPER_SPEED \
1084 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1085 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1086 ADVERTISED_1000baseT_Full)
1087
1088#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1089 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
1090
1091#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1092
1093static int
1094bnx2_setup_copper_phy(struct bnx2 *bp)
1095{
1096 u32 bmcr;
1097 u32 new_bmcr;
1098
1099 bnx2_read_phy(bp, MII_BMCR, &bmcr);
1100
1101 if (bp->autoneg & AUTONEG_SPEED) {
1102 u32 adv_reg, adv1000_reg;
1103 u32 new_adv_reg = 0;
1104 u32 new_adv1000_reg = 0;
1105
1106 bnx2_read_phy(bp, MII_ADVERTISE, &adv_reg);
1107 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
1108 ADVERTISE_PAUSE_ASYM);
1109
1110 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
1111 adv1000_reg &= PHY_ALL_1000_SPEED;
1112
1113 if (bp->advertising & ADVERTISED_10baseT_Half)
1114 new_adv_reg |= ADVERTISE_10HALF;
1115 if (bp->advertising & ADVERTISED_10baseT_Full)
1116 new_adv_reg |= ADVERTISE_10FULL;
1117 if (bp->advertising & ADVERTISED_100baseT_Half)
1118 new_adv_reg |= ADVERTISE_100HALF;
1119 if (bp->advertising & ADVERTISED_100baseT_Full)
1120 new_adv_reg |= ADVERTISE_100FULL;
1121 if (bp->advertising & ADVERTISED_1000baseT_Full)
1122 new_adv1000_reg |= ADVERTISE_1000FULL;
1123
1124 new_adv_reg |= ADVERTISE_CSMA;
1125
1126 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
1127
1128 if ((adv1000_reg != new_adv1000_reg) ||
1129 (adv_reg != new_adv_reg) ||
1130 ((bmcr & BMCR_ANENABLE) == 0)) {
1131
1132 bnx2_write_phy(bp, MII_ADVERTISE, new_adv_reg);
1133 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
1134 bnx2_write_phy(bp, MII_BMCR, BMCR_ANRESTART |
1135 BMCR_ANENABLE);
1136 }
1137 else if (bp->link_up) {
1138 /* Flow ctrl may have changed from auto to forced */
1139 /* or vice-versa. */
1140
1141 bnx2_resolve_flow_ctrl(bp);
1142 bnx2_set_mac_link(bp);
1143 }
1144 return 0;
1145 }
1146
1147 new_bmcr = 0;
1148 if (bp->req_line_speed == SPEED_100) {
1149 new_bmcr |= BMCR_SPEED100;
1150 }
1151 if (bp->req_duplex == DUPLEX_FULL) {
1152 new_bmcr |= BMCR_FULLDPLX;
1153 }
1154 if (new_bmcr != bmcr) {
1155 u32 bmsr;
1156 int i = 0;
1157
1158 bnx2_read_phy(bp, MII_BMSR, &bmsr);
1159 bnx2_read_phy(bp, MII_BMSR, &bmsr);
1160
1161 if (bmsr & BMSR_LSTATUS) {
1162 /* Force link down */
1163 bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
1164 do {
1165 udelay(100);
1166 bnx2_read_phy(bp, MII_BMSR, &bmsr);
1167 bnx2_read_phy(bp, MII_BMSR, &bmsr);
1168 i++;
1169 } while ((bmsr & BMSR_LSTATUS) && (i < 620));
1170 }
1171
1172 bnx2_write_phy(bp, MII_BMCR, new_bmcr);
1173
1174 /* Normally, the new speed is setup after the link has
1175 * gone down and up again. In some cases, link will not go
1176 * down so we need to set up the new speed here.
1177 */
1178 if (bmsr & BMSR_LSTATUS) {
1179 bp->line_speed = bp->req_line_speed;
1180 bp->duplex = bp->req_duplex;
1181 bnx2_resolve_flow_ctrl(bp);
1182 bnx2_set_mac_link(bp);
1183 }
1184 }
1185 return 0;
1186}
1187
1188static int
1189bnx2_setup_phy(struct bnx2 *bp)
1190{
1191 if (bp->loopback == MAC_LOOPBACK)
1192 return 0;
1193
1194 if (bp->phy_flags & PHY_SERDES_FLAG) {
1195 return (bnx2_setup_serdes_phy(bp));
1196 }
1197 else {
1198 return (bnx2_setup_copper_phy(bp));
1199 }
1200}
1201
1202static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001203bnx2_init_5708s_phy(struct bnx2 *bp)
1204{
1205 u32 val;
1206
1207 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
1208 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
1209 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1210
1211 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
1212 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
1213 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
1214
1215 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
1216 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
1217 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
1218
1219 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
1220 bnx2_read_phy(bp, BCM5708S_UP1, &val);
1221 val |= BCM5708S_UP1_2G5;
1222 bnx2_write_phy(bp, BCM5708S_UP1, val);
1223 }
1224
1225 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08001226 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
1227 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001228 /* increase tx signal amplitude */
1229 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1230 BCM5708S_BLK_ADDR_TX_MISC);
1231 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
1232 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
1233 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
1234 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1235 }
1236
Michael Chane3648b32005-11-04 08:51:21 -08001237 val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001238 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
1239
1240 if (val) {
1241 u32 is_backplane;
1242
Michael Chane3648b32005-11-04 08:51:21 -08001243 is_backplane = REG_RD_IND(bp, bp->shmem_base +
Michael Chan5b0c76a2005-11-04 08:45:49 -08001244 BNX2_SHARED_HW_CFG_CONFIG);
1245 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
1246 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1247 BCM5708S_BLK_ADDR_TX_MISC);
1248 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
1249 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1250 BCM5708S_BLK_ADDR_DIG);
1251 }
1252 }
1253 return 0;
1254}
1255
1256static int
1257bnx2_init_5706s_phy(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001258{
1259 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
1260
1261 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
1262 REG_WR(bp, BNX2_MISC_UNUSED0, 0x300);
1263 }
1264
1265 if (bp->dev->mtu > 1500) {
1266 u32 val;
1267
1268 /* Set extended packet length bit */
1269 bnx2_write_phy(bp, 0x18, 0x7);
1270 bnx2_read_phy(bp, 0x18, &val);
1271 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
1272
1273 bnx2_write_phy(bp, 0x1c, 0x6c00);
1274 bnx2_read_phy(bp, 0x1c, &val);
1275 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
1276 }
1277 else {
1278 u32 val;
1279
1280 bnx2_write_phy(bp, 0x18, 0x7);
1281 bnx2_read_phy(bp, 0x18, &val);
1282 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1283
1284 bnx2_write_phy(bp, 0x1c, 0x6c00);
1285 bnx2_read_phy(bp, 0x1c, &val);
1286 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
1287 }
1288
1289 return 0;
1290}
1291
1292static int
1293bnx2_init_copper_phy(struct bnx2 *bp)
1294{
Michael Chan5b0c76a2005-11-04 08:45:49 -08001295 u32 val;
1296
Michael Chanb6016b72005-05-26 13:03:09 -07001297 bp->phy_flags |= PHY_CRC_FIX_FLAG;
1298
1299 if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
1300 bnx2_write_phy(bp, 0x18, 0x0c00);
1301 bnx2_write_phy(bp, 0x17, 0x000a);
1302 bnx2_write_phy(bp, 0x15, 0x310b);
1303 bnx2_write_phy(bp, 0x17, 0x201f);
1304 bnx2_write_phy(bp, 0x15, 0x9506);
1305 bnx2_write_phy(bp, 0x17, 0x401f);
1306 bnx2_write_phy(bp, 0x15, 0x14e2);
1307 bnx2_write_phy(bp, 0x18, 0x0400);
1308 }
1309
1310 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07001311 /* Set extended packet length bit */
1312 bnx2_write_phy(bp, 0x18, 0x7);
1313 bnx2_read_phy(bp, 0x18, &val);
1314 bnx2_write_phy(bp, 0x18, val | 0x4000);
1315
1316 bnx2_read_phy(bp, 0x10, &val);
1317 bnx2_write_phy(bp, 0x10, val | 0x1);
1318 }
1319 else {
Michael Chanb6016b72005-05-26 13:03:09 -07001320 bnx2_write_phy(bp, 0x18, 0x7);
1321 bnx2_read_phy(bp, 0x18, &val);
1322 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1323
1324 bnx2_read_phy(bp, 0x10, &val);
1325 bnx2_write_phy(bp, 0x10, val & ~0x1);
1326 }
1327
Michael Chan5b0c76a2005-11-04 08:45:49 -08001328 /* ethernet@wirespeed */
1329 bnx2_write_phy(bp, 0x18, 0x7007);
1330 bnx2_read_phy(bp, 0x18, &val);
1331 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07001332 return 0;
1333}
1334
1335
1336static int
1337bnx2_init_phy(struct bnx2 *bp)
1338{
1339 u32 val;
1340 int rc = 0;
1341
1342 bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
1343 bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
1344
1345 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
1346
1347 bnx2_reset_phy(bp);
1348
1349 bnx2_read_phy(bp, MII_PHYSID1, &val);
1350 bp->phy_id = val << 16;
1351 bnx2_read_phy(bp, MII_PHYSID2, &val);
1352 bp->phy_id |= val & 0xffff;
1353
1354 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001355 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1356 rc = bnx2_init_5706s_phy(bp);
1357 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1358 rc = bnx2_init_5708s_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001359 }
1360 else {
1361 rc = bnx2_init_copper_phy(bp);
1362 }
1363
1364 bnx2_setup_phy(bp);
1365
1366 return rc;
1367}
1368
1369static int
1370bnx2_set_mac_loopback(struct bnx2 *bp)
1371{
1372 u32 mac_mode;
1373
1374 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
1375 mac_mode &= ~BNX2_EMAC_MODE_PORT;
1376 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
1377 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
1378 bp->link_up = 1;
1379 return 0;
1380}
1381
Michael Chanbc5a0692006-01-23 16:13:22 -08001382static int bnx2_test_link(struct bnx2 *);
1383
1384static int
1385bnx2_set_phy_loopback(struct bnx2 *bp)
1386{
1387 u32 mac_mode;
1388 int rc, i;
1389
1390 spin_lock_bh(&bp->phy_lock);
1391 rc = bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK | BMCR_FULLDPLX |
1392 BMCR_SPEED1000);
1393 spin_unlock_bh(&bp->phy_lock);
1394 if (rc)
1395 return rc;
1396
1397 for (i = 0; i < 10; i++) {
1398 if (bnx2_test_link(bp) == 0)
1399 break;
1400 udelay(10);
1401 }
1402
1403 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
1404 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
1405 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
1406 BNX2_EMAC_MODE_25G);
1407
1408 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
1409 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
1410 bp->link_up = 1;
1411 return 0;
1412}
1413
Michael Chanb6016b72005-05-26 13:03:09 -07001414static int
Michael Chanb090ae22006-01-23 16:07:10 -08001415bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07001416{
1417 int i;
1418 u32 val;
1419
Michael Chanb6016b72005-05-26 13:03:09 -07001420 bp->fw_wr_seq++;
1421 msg_data |= bp->fw_wr_seq;
1422
Michael Chane3648b32005-11-04 08:51:21 -08001423 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07001424
1425 /* wait for an acknowledgement. */
Michael Chanb090ae22006-01-23 16:07:10 -08001426 for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
1427 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07001428
Michael Chane3648b32005-11-04 08:51:21 -08001429 val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07001430
1431 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
1432 break;
1433 }
Michael Chanb090ae22006-01-23 16:07:10 -08001434 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
1435 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07001436
1437 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08001438 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
1439 if (!silent)
1440 printk(KERN_ERR PFX "fw sync timeout, reset code = "
1441 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07001442
1443 msg_data &= ~BNX2_DRV_MSG_CODE;
1444 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
1445
Michael Chane3648b32005-11-04 08:51:21 -08001446 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07001447
Michael Chanb6016b72005-05-26 13:03:09 -07001448 return -EBUSY;
1449 }
1450
Michael Chanb090ae22006-01-23 16:07:10 -08001451 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
1452 return -EIO;
1453
Michael Chanb6016b72005-05-26 13:03:09 -07001454 return 0;
1455}
1456
1457static void
1458bnx2_init_context(struct bnx2 *bp)
1459{
1460 u32 vcid;
1461
1462 vcid = 96;
1463 while (vcid) {
1464 u32 vcid_addr, pcid_addr, offset;
1465
1466 vcid--;
1467
1468 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
1469 u32 new_vcid;
1470
1471 vcid_addr = GET_PCID_ADDR(vcid);
1472 if (vcid & 0x8) {
1473 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
1474 }
1475 else {
1476 new_vcid = vcid;
1477 }
1478 pcid_addr = GET_PCID_ADDR(new_vcid);
1479 }
1480 else {
1481 vcid_addr = GET_CID_ADDR(vcid);
1482 pcid_addr = vcid_addr;
1483 }
1484
1485 REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
1486 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
1487
1488 /* Zero out the context. */
1489 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4) {
1490 CTX_WR(bp, 0x00, offset, 0);
1491 }
1492
1493 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
1494 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
1495 }
1496}
1497
1498static int
1499bnx2_alloc_bad_rbuf(struct bnx2 *bp)
1500{
1501 u16 *good_mbuf;
1502 u32 good_mbuf_cnt;
1503 u32 val;
1504
1505 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
1506 if (good_mbuf == NULL) {
1507 printk(KERN_ERR PFX "Failed to allocate memory in "
1508 "bnx2_alloc_bad_rbuf\n");
1509 return -ENOMEM;
1510 }
1511
1512 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
1513 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
1514
1515 good_mbuf_cnt = 0;
1516
1517 /* Allocate a bunch of mbufs and save the good ones in an array. */
1518 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
1519 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
1520 REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
1521
1522 val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
1523
1524 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
1525
1526 /* The addresses with Bit 9 set are bad memory blocks. */
1527 if (!(val & (1 << 9))) {
1528 good_mbuf[good_mbuf_cnt] = (u16) val;
1529 good_mbuf_cnt++;
1530 }
1531
1532 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
1533 }
1534
1535 /* Free the good ones back to the mbuf pool thus discarding
1536 * all the bad ones. */
1537 while (good_mbuf_cnt) {
1538 good_mbuf_cnt--;
1539
1540 val = good_mbuf[good_mbuf_cnt];
1541 val = (val << 9) | val | 1;
1542
1543 REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
1544 }
1545 kfree(good_mbuf);
1546 return 0;
1547}
1548
1549static void
1550bnx2_set_mac_addr(struct bnx2 *bp)
1551{
1552 u32 val;
1553 u8 *mac_addr = bp->dev->dev_addr;
1554
1555 val = (mac_addr[0] << 8) | mac_addr[1];
1556
1557 REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
1558
1559 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
1560 (mac_addr[4] << 8) | mac_addr[5];
1561
1562 REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
1563}
1564
1565static inline int
1566bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
1567{
1568 struct sk_buff *skb;
1569 struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
1570 dma_addr_t mapping;
Michael Chan13daffa2006-03-20 17:49:20 -08001571 struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07001572 unsigned long align;
1573
Michael Chan932f3772006-08-15 01:39:36 -07001574 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07001575 if (skb == NULL) {
1576 return -ENOMEM;
1577 }
1578
1579 if (unlikely((align = (unsigned long) skb->data & 0x7))) {
1580 skb_reserve(skb, 8 - align);
1581 }
1582
Michael Chanb6016b72005-05-26 13:03:09 -07001583 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
1584 PCI_DMA_FROMDEVICE);
1585
1586 rx_buf->skb = skb;
1587 pci_unmap_addr_set(rx_buf, mapping, mapping);
1588
1589 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
1590 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
1591
1592 bp->rx_prod_bseq += bp->rx_buf_use_size;
1593
1594 return 0;
1595}
1596
1597static void
1598bnx2_phy_int(struct bnx2 *bp)
1599{
1600 u32 new_link_state, old_link_state;
1601
1602 new_link_state = bp->status_blk->status_attn_bits &
1603 STATUS_ATTN_BITS_LINK_STATE;
1604 old_link_state = bp->status_blk->status_attn_bits_ack &
1605 STATUS_ATTN_BITS_LINK_STATE;
1606 if (new_link_state != old_link_state) {
1607 if (new_link_state) {
1608 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD,
1609 STATUS_ATTN_BITS_LINK_STATE);
1610 }
1611 else {
1612 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD,
1613 STATUS_ATTN_BITS_LINK_STATE);
1614 }
1615 bnx2_set_link(bp);
1616 }
1617}
1618
1619static void
1620bnx2_tx_int(struct bnx2 *bp)
1621{
Michael Chanf4e418f2005-11-04 08:53:48 -08001622 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07001623 u16 hw_cons, sw_cons, sw_ring_cons;
1624 int tx_free_bd = 0;
1625
Michael Chanf4e418f2005-11-04 08:53:48 -08001626 hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
Michael Chanb6016b72005-05-26 13:03:09 -07001627 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
1628 hw_cons++;
1629 }
1630 sw_cons = bp->tx_cons;
1631
1632 while (sw_cons != hw_cons) {
1633 struct sw_bd *tx_buf;
1634 struct sk_buff *skb;
1635 int i, last;
1636
1637 sw_ring_cons = TX_RING_IDX(sw_cons);
1638
1639 tx_buf = &bp->tx_buf_ring[sw_ring_cons];
1640 skb = tx_buf->skb;
1641#ifdef BCM_TSO
1642 /* partial BD completions possible with TSO packets */
Herbert Xu89114af2006-07-08 13:34:32 -07001643 if (skb_is_gso(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001644 u16 last_idx, last_ring_idx;
1645
1646 last_idx = sw_cons +
1647 skb_shinfo(skb)->nr_frags + 1;
1648 last_ring_idx = sw_ring_cons +
1649 skb_shinfo(skb)->nr_frags + 1;
1650 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
1651 last_idx++;
1652 }
1653 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
1654 break;
1655 }
1656 }
1657#endif
1658 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
1659 skb_headlen(skb), PCI_DMA_TODEVICE);
1660
1661 tx_buf->skb = NULL;
1662 last = skb_shinfo(skb)->nr_frags;
1663
1664 for (i = 0; i < last; i++) {
1665 sw_cons = NEXT_TX_BD(sw_cons);
1666
1667 pci_unmap_page(bp->pdev,
1668 pci_unmap_addr(
1669 &bp->tx_buf_ring[TX_RING_IDX(sw_cons)],
1670 mapping),
1671 skb_shinfo(skb)->frags[i].size,
1672 PCI_DMA_TODEVICE);
1673 }
1674
1675 sw_cons = NEXT_TX_BD(sw_cons);
1676
1677 tx_free_bd += last + 1;
1678
Michael Chan745720e2006-06-29 12:37:41 -07001679 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07001680
Michael Chanf4e418f2005-11-04 08:53:48 -08001681 hw_cons = bp->hw_tx_cons =
1682 sblk->status_tx_quick_consumer_index0;
1683
Michael Chanb6016b72005-05-26 13:03:09 -07001684 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
1685 hw_cons++;
1686 }
1687 }
1688
Michael Chane89bbf12005-08-25 15:36:58 -07001689 bp->tx_cons = sw_cons;
Michael Chan2f8af122006-08-15 01:39:10 -07001690 /* Need to make the tx_cons update visible to bnx2_start_xmit()
1691 * before checking for netif_queue_stopped(). Without the
1692 * memory barrier, there is a small possibility that bnx2_start_xmit()
1693 * will miss it and cause the queue to be stopped forever.
1694 */
1695 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07001696
Michael Chan2f8af122006-08-15 01:39:10 -07001697 if (unlikely(netif_queue_stopped(bp->dev)) &&
1698 (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) {
1699 netif_tx_lock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07001700 if ((netif_queue_stopped(bp->dev)) &&
Michael Chan2f8af122006-08-15 01:39:10 -07001701 (bnx2_tx_avail(bp) > bp->tx_wake_thresh))
Michael Chanb6016b72005-05-26 13:03:09 -07001702 netif_wake_queue(bp->dev);
Michael Chan2f8af122006-08-15 01:39:10 -07001703 netif_tx_unlock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07001704 }
Michael Chanb6016b72005-05-26 13:03:09 -07001705}
1706
1707static inline void
1708bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
1709 u16 cons, u16 prod)
1710{
Michael Chan236b6392006-03-20 17:49:02 -08001711 struct sw_bd *cons_rx_buf, *prod_rx_buf;
1712 struct rx_bd *cons_bd, *prod_bd;
1713
1714 cons_rx_buf = &bp->rx_buf_ring[cons];
1715 prod_rx_buf = &bp->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07001716
1717 pci_dma_sync_single_for_device(bp->pdev,
1718 pci_unmap_addr(cons_rx_buf, mapping),
1719 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
1720
Michael Chan236b6392006-03-20 17:49:02 -08001721 bp->rx_prod_bseq += bp->rx_buf_use_size;
1722
1723 prod_rx_buf->skb = skb;
1724
1725 if (cons == prod)
1726 return;
1727
Michael Chanb6016b72005-05-26 13:03:09 -07001728 pci_unmap_addr_set(prod_rx_buf, mapping,
1729 pci_unmap_addr(cons_rx_buf, mapping));
1730
Michael Chan3fdfcc22006-03-20 17:49:49 -08001731 cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
1732 prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08001733 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
1734 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07001735}
1736
1737static int
1738bnx2_rx_int(struct bnx2 *bp, int budget)
1739{
Michael Chanf4e418f2005-11-04 08:53:48 -08001740 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07001741 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
1742 struct l2_fhdr *rx_hdr;
1743 int rx_pkt = 0;
1744
Michael Chanf4e418f2005-11-04 08:53:48 -08001745 hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
Michael Chanb6016b72005-05-26 13:03:09 -07001746 if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
1747 hw_cons++;
1748 }
1749 sw_cons = bp->rx_cons;
1750 sw_prod = bp->rx_prod;
1751
1752 /* Memory barrier necessary as speculative reads of the rx
1753 * buffer can be ahead of the index in the status block
1754 */
1755 rmb();
1756 while (sw_cons != hw_cons) {
1757 unsigned int len;
Michael Chanade2bfe2006-01-23 16:09:51 -08001758 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07001759 struct sw_bd *rx_buf;
1760 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08001761 dma_addr_t dma_addr;
Michael Chanb6016b72005-05-26 13:03:09 -07001762
1763 sw_ring_cons = RX_RING_IDX(sw_cons);
1764 sw_ring_prod = RX_RING_IDX(sw_prod);
1765
1766 rx_buf = &bp->rx_buf_ring[sw_ring_cons];
1767 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08001768
1769 rx_buf->skb = NULL;
1770
1771 dma_addr = pci_unmap_addr(rx_buf, mapping);
1772
1773 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07001774 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
1775
1776 rx_hdr = (struct l2_fhdr *) skb->data;
1777 len = rx_hdr->l2_fhdr_pkt_len - 4;
1778
Michael Chanade2bfe2006-01-23 16:09:51 -08001779 if ((status = rx_hdr->l2_fhdr_status) &
Michael Chanb6016b72005-05-26 13:03:09 -07001780 (L2_FHDR_ERRORS_BAD_CRC |
1781 L2_FHDR_ERRORS_PHY_DECODE |
1782 L2_FHDR_ERRORS_ALIGNMENT |
1783 L2_FHDR_ERRORS_TOO_SHORT |
1784 L2_FHDR_ERRORS_GIANT_FRAME)) {
1785
1786 goto reuse_rx;
1787 }
1788
1789 /* Since we don't have a jumbo ring, copy small packets
1790 * if mtu > 1500
1791 */
1792 if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) {
1793 struct sk_buff *new_skb;
1794
Michael Chan932f3772006-08-15 01:39:36 -07001795 new_skb = netdev_alloc_skb(bp->dev, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07001796 if (new_skb == NULL)
1797 goto reuse_rx;
1798
1799 /* aligned copy */
1800 memcpy(new_skb->data,
1801 skb->data + bp->rx_offset - 2,
1802 len + 2);
1803
1804 skb_reserve(new_skb, 2);
1805 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07001806
1807 bnx2_reuse_rx_skb(bp, skb,
1808 sw_ring_cons, sw_ring_prod);
1809
1810 skb = new_skb;
1811 }
1812 else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
Michael Chan236b6392006-03-20 17:49:02 -08001813 pci_unmap_single(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07001814 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
1815
1816 skb_reserve(skb, bp->rx_offset);
1817 skb_put(skb, len);
1818 }
1819 else {
1820reuse_rx:
1821 bnx2_reuse_rx_skb(bp, skb,
1822 sw_ring_cons, sw_ring_prod);
1823 goto next_rx;
1824 }
1825
1826 skb->protocol = eth_type_trans(skb, bp->dev);
1827
1828 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07001829 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001830
Michael Chan745720e2006-06-29 12:37:41 -07001831 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07001832 goto next_rx;
1833
1834 }
1835
Michael Chanb6016b72005-05-26 13:03:09 -07001836 skb->ip_summed = CHECKSUM_NONE;
1837 if (bp->rx_csum &&
1838 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
1839 L2_FHDR_STATUS_UDP_DATAGRAM))) {
1840
Michael Chanade2bfe2006-01-23 16:09:51 -08001841 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
1842 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07001843 skb->ip_summed = CHECKSUM_UNNECESSARY;
1844 }
1845
1846#ifdef BCM_VLAN
1847 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && (bp->vlgrp != 0)) {
1848 vlan_hwaccel_receive_skb(skb, bp->vlgrp,
1849 rx_hdr->l2_fhdr_vlan_tag);
1850 }
1851 else
1852#endif
1853 netif_receive_skb(skb);
1854
1855 bp->dev->last_rx = jiffies;
1856 rx_pkt++;
1857
1858next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07001859 sw_cons = NEXT_RX_BD(sw_cons);
1860 sw_prod = NEXT_RX_BD(sw_prod);
1861
1862 if ((rx_pkt == budget))
1863 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08001864
1865 /* Refresh hw_cons to see if there is new work */
1866 if (sw_cons == hw_cons) {
1867 hw_cons = bp->hw_rx_cons =
1868 sblk->status_rx_quick_consumer_index0;
1869 if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)
1870 hw_cons++;
1871 rmb();
1872 }
Michael Chanb6016b72005-05-26 13:03:09 -07001873 }
1874 bp->rx_cons = sw_cons;
1875 bp->rx_prod = sw_prod;
1876
1877 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod);
1878
1879 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
1880
1881 mmiowb();
1882
1883 return rx_pkt;
1884
1885}
1886
1887/* MSI ISR - The only difference between this and the INTx ISR
1888 * is that the MSI interrupt is always serviced.
1889 */
1890static irqreturn_t
1891bnx2_msi(int irq, void *dev_instance, struct pt_regs *regs)
1892{
1893 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08001894 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07001895
Michael Chanc921e4c2005-09-08 13:15:32 -07001896 prefetch(bp->status_blk);
Michael Chanb6016b72005-05-26 13:03:09 -07001897 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
1898 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
1899 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
1900
1901 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07001902 if (unlikely(atomic_read(&bp->intr_sem) != 0))
1903 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07001904
Michael Chan73eef4c2005-08-25 15:39:15 -07001905 netif_rx_schedule(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07001906
Michael Chan73eef4c2005-08-25 15:39:15 -07001907 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07001908}
1909
1910static irqreturn_t
1911bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
1912{
1913 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08001914 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07001915
1916 /* When using INTx, it is possible for the interrupt to arrive
1917 * at the CPU before the status block posted prior to the
1918 * interrupt. Reading a register will flush the status block.
1919 * When using MSI, the MSI message will always complete after
1920 * the status block write.
1921 */
Michael Chanc921e4c2005-09-08 13:15:32 -07001922 if ((bp->status_blk->status_idx == bp->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07001923 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
1924 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07001925 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07001926
1927 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
1928 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
1929 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
1930
1931 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07001932 if (unlikely(atomic_read(&bp->intr_sem) != 0))
1933 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07001934
Michael Chan73eef4c2005-08-25 15:39:15 -07001935 netif_rx_schedule(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07001936
Michael Chan73eef4c2005-08-25 15:39:15 -07001937 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07001938}
1939
Michael Chanf4e418f2005-11-04 08:53:48 -08001940static inline int
1941bnx2_has_work(struct bnx2 *bp)
1942{
1943 struct status_block *sblk = bp->status_blk;
1944
1945 if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) ||
1946 (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
1947 return 1;
1948
1949 if (((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != 0) !=
1950 bp->link_up)
1951 return 1;
1952
1953 return 0;
1954}
1955
Michael Chanb6016b72005-05-26 13:03:09 -07001956static int
1957bnx2_poll(struct net_device *dev, int *budget)
1958{
Michael Chan972ec0d2006-01-23 16:12:43 -08001959 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07001960
Michael Chanb6016b72005-05-26 13:03:09 -07001961 if ((bp->status_blk->status_attn_bits &
1962 STATUS_ATTN_BITS_LINK_STATE) !=
1963 (bp->status_blk->status_attn_bits_ack &
1964 STATUS_ATTN_BITS_LINK_STATE)) {
1965
Michael Chanc770a652005-08-25 15:38:39 -07001966 spin_lock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001967 bnx2_phy_int(bp);
Michael Chanc770a652005-08-25 15:38:39 -07001968 spin_unlock(&bp->phy_lock);
Michael Chanbf5295b2006-03-23 01:11:56 -08001969
1970 /* This is needed to take care of transient status
1971 * during link changes.
1972 */
1973 REG_WR(bp, BNX2_HC_COMMAND,
1974 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
1975 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07001976 }
1977
Michael Chanf4e418f2005-11-04 08:53:48 -08001978 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
Michael Chanb6016b72005-05-26 13:03:09 -07001979 bnx2_tx_int(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001980
Michael Chanf4e418f2005-11-04 08:53:48 -08001981 if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) {
Michael Chanb6016b72005-05-26 13:03:09 -07001982 int orig_budget = *budget;
1983 int work_done;
1984
1985 if (orig_budget > dev->quota)
1986 orig_budget = dev->quota;
1987
1988 work_done = bnx2_rx_int(bp, orig_budget);
1989 *budget -= work_done;
1990 dev->quota -= work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07001991 }
1992
Michael Chanf4e418f2005-11-04 08:53:48 -08001993 bp->last_status_idx = bp->status_blk->status_idx;
1994 rmb();
1995
1996 if (!bnx2_has_work(bp)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001997 netif_rx_complete(dev);
Michael Chan1269a8a2006-01-23 16:11:03 -08001998 if (likely(bp->flags & USING_MSI_FLAG)) {
1999 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2000 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2001 bp->last_status_idx);
2002 return 0;
2003 }
Michael Chanb6016b72005-05-26 13:03:09 -07002004 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chan1269a8a2006-01-23 16:11:03 -08002005 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2006 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
2007 bp->last_status_idx);
2008
2009 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2010 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2011 bp->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -07002012 return 0;
2013 }
2014
2015 return 1;
2016}
2017
Herbert Xu932ff272006-06-09 12:20:56 -07002018/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07002019 * from set_multicast.
2020 */
2021static void
2022bnx2_set_rx_mode(struct net_device *dev)
2023{
Michael Chan972ec0d2006-01-23 16:12:43 -08002024 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002025 u32 rx_mode, sort_mode;
2026 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002027
Michael Chanc770a652005-08-25 15:38:39 -07002028 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002029
2030 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
2031 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
2032 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
2033#ifdef BCM_VLAN
Michael Chane29054f2006-01-23 16:06:06 -08002034 if (!bp->vlgrp && !(bp->flags & ASF_ENABLE_FLAG))
Michael Chanb6016b72005-05-26 13:03:09 -07002035 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002036#else
Michael Chane29054f2006-01-23 16:06:06 -08002037 if (!(bp->flags & ASF_ENABLE_FLAG))
2038 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002039#endif
2040 if (dev->flags & IFF_PROMISC) {
2041 /* Promiscuous mode. */
2042 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
2043 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN;
2044 }
2045 else if (dev->flags & IFF_ALLMULTI) {
2046 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2047 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2048 0xffffffff);
2049 }
2050 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
2051 }
2052 else {
2053 /* Accept one or more multicast(s). */
2054 struct dev_mc_list *mclist;
2055 u32 mc_filter[NUM_MC_HASH_REGISTERS];
2056 u32 regidx;
2057 u32 bit;
2058 u32 crc;
2059
2060 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
2061
2062 for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
2063 i++, mclist = mclist->next) {
2064
2065 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
2066 bit = crc & 0xff;
2067 regidx = (bit & 0xe0) >> 5;
2068 bit &= 0x1f;
2069 mc_filter[regidx] |= (1 << bit);
2070 }
2071
2072 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2073 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2074 mc_filter[i]);
2075 }
2076
2077 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
2078 }
2079
2080 if (rx_mode != bp->rx_mode) {
2081 bp->rx_mode = rx_mode;
2082 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
2083 }
2084
2085 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
2086 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
2087 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
2088
Michael Chanc770a652005-08-25 15:38:39 -07002089 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002090}
2091
Michael Chanfba9fe92006-06-12 22:21:25 -07002092#define FW_BUF_SIZE 0x8000
2093
2094static int
2095bnx2_gunzip_init(struct bnx2 *bp)
2096{
2097 if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
2098 goto gunzip_nomem1;
2099
2100 if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
2101 goto gunzip_nomem2;
2102
2103 bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
2104 if (bp->strm->workspace == NULL)
2105 goto gunzip_nomem3;
2106
2107 return 0;
2108
2109gunzip_nomem3:
2110 kfree(bp->strm);
2111 bp->strm = NULL;
2112
2113gunzip_nomem2:
2114 vfree(bp->gunzip_buf);
2115 bp->gunzip_buf = NULL;
2116
2117gunzip_nomem1:
2118 printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
2119 "uncompression.\n", bp->dev->name);
2120 return -ENOMEM;
2121}
2122
2123static void
2124bnx2_gunzip_end(struct bnx2 *bp)
2125{
2126 kfree(bp->strm->workspace);
2127
2128 kfree(bp->strm);
2129 bp->strm = NULL;
2130
2131 if (bp->gunzip_buf) {
2132 vfree(bp->gunzip_buf);
2133 bp->gunzip_buf = NULL;
2134 }
2135}
2136
2137static int
2138bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
2139{
2140 int n, rc;
2141
2142 /* check gzip header */
2143 if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
2144 return -EINVAL;
2145
2146 n = 10;
2147
2148#define FNAME 0x8
2149 if (zbuf[3] & FNAME)
2150 while ((zbuf[n++] != 0) && (n < len));
2151
2152 bp->strm->next_in = zbuf + n;
2153 bp->strm->avail_in = len - n;
2154 bp->strm->next_out = bp->gunzip_buf;
2155 bp->strm->avail_out = FW_BUF_SIZE;
2156
2157 rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
2158 if (rc != Z_OK)
2159 return rc;
2160
2161 rc = zlib_inflate(bp->strm, Z_FINISH);
2162
2163 *outlen = FW_BUF_SIZE - bp->strm->avail_out;
2164 *outbuf = bp->gunzip_buf;
2165
2166 if ((rc != Z_OK) && (rc != Z_STREAM_END))
2167 printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
2168 bp->dev->name, bp->strm->msg);
2169
2170 zlib_inflateEnd(bp->strm);
2171
2172 if (rc == Z_STREAM_END)
2173 return 0;
2174
2175 return rc;
2176}
2177
Michael Chanb6016b72005-05-26 13:03:09 -07002178static void
2179load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
2180 u32 rv2p_proc)
2181{
2182 int i;
2183 u32 val;
2184
2185
2186 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chanfba9fe92006-06-12 22:21:25 -07002187 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07002188 rv2p_code++;
Michael Chanfba9fe92006-06-12 22:21:25 -07002189 REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07002190 rv2p_code++;
2191
2192 if (rv2p_proc == RV2P_PROC1) {
2193 val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
2194 REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
2195 }
2196 else {
2197 val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
2198 REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
2199 }
2200 }
2201
2202 /* Reset the processor, un-stall is done later. */
2203 if (rv2p_proc == RV2P_PROC1) {
2204 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
2205 }
2206 else {
2207 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
2208 }
2209}
2210
2211static void
2212load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
2213{
2214 u32 offset;
2215 u32 val;
2216
2217 /* Halt the CPU. */
2218 val = REG_RD_IND(bp, cpu_reg->mode);
2219 val |= cpu_reg->mode_value_halt;
2220 REG_WR_IND(bp, cpu_reg->mode, val);
2221 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
2222
2223 /* Load the Text area. */
2224 offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
2225 if (fw->text) {
2226 int j;
2227
2228 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
Michael Chanfba9fe92006-06-12 22:21:25 -07002229 REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07002230 }
2231 }
2232
2233 /* Load the Data area. */
2234 offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
2235 if (fw->data) {
2236 int j;
2237
2238 for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
2239 REG_WR_IND(bp, offset, fw->data[j]);
2240 }
2241 }
2242
2243 /* Load the SBSS area. */
2244 offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
2245 if (fw->sbss) {
2246 int j;
2247
2248 for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
2249 REG_WR_IND(bp, offset, fw->sbss[j]);
2250 }
2251 }
2252
2253 /* Load the BSS area. */
2254 offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
2255 if (fw->bss) {
2256 int j;
2257
2258 for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
2259 REG_WR_IND(bp, offset, fw->bss[j]);
2260 }
2261 }
2262
2263 /* Load the Read-Only area. */
2264 offset = cpu_reg->spad_base +
2265 (fw->rodata_addr - cpu_reg->mips_view_base);
2266 if (fw->rodata) {
2267 int j;
2268
2269 for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
2270 REG_WR_IND(bp, offset, fw->rodata[j]);
2271 }
2272 }
2273
2274 /* Clear the pre-fetch instruction. */
2275 REG_WR_IND(bp, cpu_reg->inst, 0);
2276 REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
2277
2278 /* Start the CPU. */
2279 val = REG_RD_IND(bp, cpu_reg->mode);
2280 val &= ~cpu_reg->mode_value_halt;
2281 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
2282 REG_WR_IND(bp, cpu_reg->mode, val);
2283}
2284
Michael Chanfba9fe92006-06-12 22:21:25 -07002285static int
Michael Chanb6016b72005-05-26 13:03:09 -07002286bnx2_init_cpus(struct bnx2 *bp)
2287{
2288 struct cpu_reg cpu_reg;
2289 struct fw_info fw;
Michael Chanfba9fe92006-06-12 22:21:25 -07002290 int rc = 0;
2291 void *text;
2292 u32 text_len;
2293
2294 if ((rc = bnx2_gunzip_init(bp)) != 0)
2295 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07002296
2297 /* Initialize the RV2P processor. */
Michael Chanfba9fe92006-06-12 22:21:25 -07002298 rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
2299 &text_len);
2300 if (rc)
2301 goto init_cpu_err;
2302
2303 load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
2304
2305 rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
2306 &text_len);
2307 if (rc)
2308 goto init_cpu_err;
2309
2310 load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
Michael Chanb6016b72005-05-26 13:03:09 -07002311
2312 /* Initialize the RX Processor. */
2313 cpu_reg.mode = BNX2_RXP_CPU_MODE;
2314 cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
2315 cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
2316 cpu_reg.state = BNX2_RXP_CPU_STATE;
2317 cpu_reg.state_value_clear = 0xffffff;
2318 cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
2319 cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
2320 cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
2321 cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
2322 cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
2323 cpu_reg.spad_base = BNX2_RXP_SCRATCH;
2324 cpu_reg.mips_view_base = 0x8000000;
2325
2326 fw.ver_major = bnx2_RXP_b06FwReleaseMajor;
2327 fw.ver_minor = bnx2_RXP_b06FwReleaseMinor;
2328 fw.ver_fix = bnx2_RXP_b06FwReleaseFix;
2329 fw.start_addr = bnx2_RXP_b06FwStartAddr;
2330
2331 fw.text_addr = bnx2_RXP_b06FwTextAddr;
2332 fw.text_len = bnx2_RXP_b06FwTextLen;
2333 fw.text_index = 0;
Michael Chanfba9fe92006-06-12 22:21:25 -07002334
2335 rc = bnx2_gunzip(bp, bnx2_RXP_b06FwText, sizeof(bnx2_RXP_b06FwText),
2336 &text, &text_len);
2337 if (rc)
2338 goto init_cpu_err;
2339
2340 fw.text = text;
Michael Chanb6016b72005-05-26 13:03:09 -07002341
2342 fw.data_addr = bnx2_RXP_b06FwDataAddr;
2343 fw.data_len = bnx2_RXP_b06FwDataLen;
2344 fw.data_index = 0;
2345 fw.data = bnx2_RXP_b06FwData;
2346
2347 fw.sbss_addr = bnx2_RXP_b06FwSbssAddr;
2348 fw.sbss_len = bnx2_RXP_b06FwSbssLen;
2349 fw.sbss_index = 0;
2350 fw.sbss = bnx2_RXP_b06FwSbss;
2351
2352 fw.bss_addr = bnx2_RXP_b06FwBssAddr;
2353 fw.bss_len = bnx2_RXP_b06FwBssLen;
2354 fw.bss_index = 0;
2355 fw.bss = bnx2_RXP_b06FwBss;
2356
2357 fw.rodata_addr = bnx2_RXP_b06FwRodataAddr;
2358 fw.rodata_len = bnx2_RXP_b06FwRodataLen;
2359 fw.rodata_index = 0;
2360 fw.rodata = bnx2_RXP_b06FwRodata;
2361
2362 load_cpu_fw(bp, &cpu_reg, &fw);
2363
2364 /* Initialize the TX Processor. */
2365 cpu_reg.mode = BNX2_TXP_CPU_MODE;
2366 cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
2367 cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
2368 cpu_reg.state = BNX2_TXP_CPU_STATE;
2369 cpu_reg.state_value_clear = 0xffffff;
2370 cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
2371 cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
2372 cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
2373 cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
2374 cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
2375 cpu_reg.spad_base = BNX2_TXP_SCRATCH;
2376 cpu_reg.mips_view_base = 0x8000000;
2377
2378 fw.ver_major = bnx2_TXP_b06FwReleaseMajor;
2379 fw.ver_minor = bnx2_TXP_b06FwReleaseMinor;
2380 fw.ver_fix = bnx2_TXP_b06FwReleaseFix;
2381 fw.start_addr = bnx2_TXP_b06FwStartAddr;
2382
2383 fw.text_addr = bnx2_TXP_b06FwTextAddr;
2384 fw.text_len = bnx2_TXP_b06FwTextLen;
2385 fw.text_index = 0;
Michael Chanfba9fe92006-06-12 22:21:25 -07002386
2387 rc = bnx2_gunzip(bp, bnx2_TXP_b06FwText, sizeof(bnx2_TXP_b06FwText),
2388 &text, &text_len);
2389 if (rc)
2390 goto init_cpu_err;
2391
2392 fw.text = text;
Michael Chanb6016b72005-05-26 13:03:09 -07002393
2394 fw.data_addr = bnx2_TXP_b06FwDataAddr;
2395 fw.data_len = bnx2_TXP_b06FwDataLen;
2396 fw.data_index = 0;
2397 fw.data = bnx2_TXP_b06FwData;
2398
2399 fw.sbss_addr = bnx2_TXP_b06FwSbssAddr;
2400 fw.sbss_len = bnx2_TXP_b06FwSbssLen;
2401 fw.sbss_index = 0;
2402 fw.sbss = bnx2_TXP_b06FwSbss;
2403
2404 fw.bss_addr = bnx2_TXP_b06FwBssAddr;
2405 fw.bss_len = bnx2_TXP_b06FwBssLen;
2406 fw.bss_index = 0;
2407 fw.bss = bnx2_TXP_b06FwBss;
2408
2409 fw.rodata_addr = bnx2_TXP_b06FwRodataAddr;
2410 fw.rodata_len = bnx2_TXP_b06FwRodataLen;
2411 fw.rodata_index = 0;
2412 fw.rodata = bnx2_TXP_b06FwRodata;
2413
2414 load_cpu_fw(bp, &cpu_reg, &fw);
2415
2416 /* Initialize the TX Patch-up Processor. */
2417 cpu_reg.mode = BNX2_TPAT_CPU_MODE;
2418 cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
2419 cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
2420 cpu_reg.state = BNX2_TPAT_CPU_STATE;
2421 cpu_reg.state_value_clear = 0xffffff;
2422 cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
2423 cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
2424 cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
2425 cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
2426 cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
2427 cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
2428 cpu_reg.mips_view_base = 0x8000000;
2429
2430 fw.ver_major = bnx2_TPAT_b06FwReleaseMajor;
2431 fw.ver_minor = bnx2_TPAT_b06FwReleaseMinor;
2432 fw.ver_fix = bnx2_TPAT_b06FwReleaseFix;
2433 fw.start_addr = bnx2_TPAT_b06FwStartAddr;
2434
2435 fw.text_addr = bnx2_TPAT_b06FwTextAddr;
2436 fw.text_len = bnx2_TPAT_b06FwTextLen;
2437 fw.text_index = 0;
Michael Chanfba9fe92006-06-12 22:21:25 -07002438
2439 rc = bnx2_gunzip(bp, bnx2_TPAT_b06FwText, sizeof(bnx2_TPAT_b06FwText),
2440 &text, &text_len);
2441 if (rc)
2442 goto init_cpu_err;
2443
2444 fw.text = text;
Michael Chanb6016b72005-05-26 13:03:09 -07002445
2446 fw.data_addr = bnx2_TPAT_b06FwDataAddr;
2447 fw.data_len = bnx2_TPAT_b06FwDataLen;
2448 fw.data_index = 0;
2449 fw.data = bnx2_TPAT_b06FwData;
2450
2451 fw.sbss_addr = bnx2_TPAT_b06FwSbssAddr;
2452 fw.sbss_len = bnx2_TPAT_b06FwSbssLen;
2453 fw.sbss_index = 0;
2454 fw.sbss = bnx2_TPAT_b06FwSbss;
2455
2456 fw.bss_addr = bnx2_TPAT_b06FwBssAddr;
2457 fw.bss_len = bnx2_TPAT_b06FwBssLen;
2458 fw.bss_index = 0;
2459 fw.bss = bnx2_TPAT_b06FwBss;
2460
2461 fw.rodata_addr = bnx2_TPAT_b06FwRodataAddr;
2462 fw.rodata_len = bnx2_TPAT_b06FwRodataLen;
2463 fw.rodata_index = 0;
2464 fw.rodata = bnx2_TPAT_b06FwRodata;
2465
2466 load_cpu_fw(bp, &cpu_reg, &fw);
2467
2468 /* Initialize the Completion Processor. */
2469 cpu_reg.mode = BNX2_COM_CPU_MODE;
2470 cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
2471 cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
2472 cpu_reg.state = BNX2_COM_CPU_STATE;
2473 cpu_reg.state_value_clear = 0xffffff;
2474 cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
2475 cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
2476 cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
2477 cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
2478 cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
2479 cpu_reg.spad_base = BNX2_COM_SCRATCH;
2480 cpu_reg.mips_view_base = 0x8000000;
2481
2482 fw.ver_major = bnx2_COM_b06FwReleaseMajor;
2483 fw.ver_minor = bnx2_COM_b06FwReleaseMinor;
2484 fw.ver_fix = bnx2_COM_b06FwReleaseFix;
2485 fw.start_addr = bnx2_COM_b06FwStartAddr;
2486
2487 fw.text_addr = bnx2_COM_b06FwTextAddr;
2488 fw.text_len = bnx2_COM_b06FwTextLen;
2489 fw.text_index = 0;
Michael Chanfba9fe92006-06-12 22:21:25 -07002490
2491 rc = bnx2_gunzip(bp, bnx2_COM_b06FwText, sizeof(bnx2_COM_b06FwText),
2492 &text, &text_len);
2493 if (rc)
2494 goto init_cpu_err;
2495
2496 fw.text = text;
Michael Chanb6016b72005-05-26 13:03:09 -07002497
2498 fw.data_addr = bnx2_COM_b06FwDataAddr;
2499 fw.data_len = bnx2_COM_b06FwDataLen;
2500 fw.data_index = 0;
2501 fw.data = bnx2_COM_b06FwData;
2502
2503 fw.sbss_addr = bnx2_COM_b06FwSbssAddr;
2504 fw.sbss_len = bnx2_COM_b06FwSbssLen;
2505 fw.sbss_index = 0;
2506 fw.sbss = bnx2_COM_b06FwSbss;
2507
2508 fw.bss_addr = bnx2_COM_b06FwBssAddr;
2509 fw.bss_len = bnx2_COM_b06FwBssLen;
2510 fw.bss_index = 0;
2511 fw.bss = bnx2_COM_b06FwBss;
2512
2513 fw.rodata_addr = bnx2_COM_b06FwRodataAddr;
2514 fw.rodata_len = bnx2_COM_b06FwRodataLen;
2515 fw.rodata_index = 0;
2516 fw.rodata = bnx2_COM_b06FwRodata;
2517
2518 load_cpu_fw(bp, &cpu_reg, &fw);
2519
Michael Chanfba9fe92006-06-12 22:21:25 -07002520init_cpu_err:
2521 bnx2_gunzip_end(bp);
2522 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07002523}
2524
2525static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07002526bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07002527{
2528 u16 pmcsr;
2529
2530 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
2531
2532 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07002533 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07002534 u32 val;
2535
2536 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
2537 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
2538 PCI_PM_CTRL_PME_STATUS);
2539
2540 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
2541 /* delay required during transition out of D3hot */
2542 msleep(20);
2543
2544 val = REG_RD(bp, BNX2_EMAC_MODE);
2545 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
2546 val &= ~BNX2_EMAC_MODE_MPKT;
2547 REG_WR(bp, BNX2_EMAC_MODE, val);
2548
2549 val = REG_RD(bp, BNX2_RPM_CONFIG);
2550 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
2551 REG_WR(bp, BNX2_RPM_CONFIG, val);
2552 break;
2553 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07002554 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07002555 int i;
2556 u32 val, wol_msg;
2557
2558 if (bp->wol) {
2559 u32 advertising;
2560 u8 autoneg;
2561
2562 autoneg = bp->autoneg;
2563 advertising = bp->advertising;
2564
2565 bp->autoneg = AUTONEG_SPEED;
2566 bp->advertising = ADVERTISED_10baseT_Half |
2567 ADVERTISED_10baseT_Full |
2568 ADVERTISED_100baseT_Half |
2569 ADVERTISED_100baseT_Full |
2570 ADVERTISED_Autoneg;
2571
2572 bnx2_setup_copper_phy(bp);
2573
2574 bp->autoneg = autoneg;
2575 bp->advertising = advertising;
2576
2577 bnx2_set_mac_addr(bp);
2578
2579 val = REG_RD(bp, BNX2_EMAC_MODE);
2580
2581 /* Enable port mode. */
2582 val &= ~BNX2_EMAC_MODE_PORT;
2583 val |= BNX2_EMAC_MODE_PORT_MII |
2584 BNX2_EMAC_MODE_MPKT_RCVD |
2585 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07002586 BNX2_EMAC_MODE_MPKT;
2587
2588 REG_WR(bp, BNX2_EMAC_MODE, val);
2589
2590 /* receive all multicast */
2591 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2592 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2593 0xffffffff);
2594 }
2595 REG_WR(bp, BNX2_EMAC_RX_MODE,
2596 BNX2_EMAC_RX_MODE_SORT_MODE);
2597
2598 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
2599 BNX2_RPM_SORT_USER0_MC_EN;
2600 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
2601 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
2602 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
2603 BNX2_RPM_SORT_USER0_ENA);
2604
2605 /* Need to enable EMAC and RPM for WOL. */
2606 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2607 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
2608 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
2609 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
2610
2611 val = REG_RD(bp, BNX2_RPM_CONFIG);
2612 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
2613 REG_WR(bp, BNX2_RPM_CONFIG, val);
2614
2615 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
2616 }
2617 else {
2618 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
2619 }
2620
Michael Chandda1e392006-01-23 16:08:14 -08002621 if (!(bp->flags & NO_WOL_FLAG))
2622 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07002623
2624 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
2625 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
2626 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
2627
2628 if (bp->wol)
2629 pmcsr |= 3;
2630 }
2631 else {
2632 pmcsr |= 3;
2633 }
2634 if (bp->wol) {
2635 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
2636 }
2637 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
2638 pmcsr);
2639
2640 /* No more memory access after this point until
2641 * device is brought back to D0.
2642 */
2643 udelay(50);
2644 break;
2645 }
2646 default:
2647 return -EINVAL;
2648 }
2649 return 0;
2650}
2651
2652static int
2653bnx2_acquire_nvram_lock(struct bnx2 *bp)
2654{
2655 u32 val;
2656 int j;
2657
2658 /* Request access to the flash interface. */
2659 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
2660 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2661 val = REG_RD(bp, BNX2_NVM_SW_ARB);
2662 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
2663 break;
2664
2665 udelay(5);
2666 }
2667
2668 if (j >= NVRAM_TIMEOUT_COUNT)
2669 return -EBUSY;
2670
2671 return 0;
2672}
2673
2674static int
2675bnx2_release_nvram_lock(struct bnx2 *bp)
2676{
2677 int j;
2678 u32 val;
2679
2680 /* Relinquish nvram interface. */
2681 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
2682
2683 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2684 val = REG_RD(bp, BNX2_NVM_SW_ARB);
2685 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
2686 break;
2687
2688 udelay(5);
2689 }
2690
2691 if (j >= NVRAM_TIMEOUT_COUNT)
2692 return -EBUSY;
2693
2694 return 0;
2695}
2696
2697
2698static int
2699bnx2_enable_nvram_write(struct bnx2 *bp)
2700{
2701 u32 val;
2702
2703 val = REG_RD(bp, BNX2_MISC_CFG);
2704 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
2705
2706 if (!bp->flash_info->buffered) {
2707 int j;
2708
2709 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
2710 REG_WR(bp, BNX2_NVM_COMMAND,
2711 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
2712
2713 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2714 udelay(5);
2715
2716 val = REG_RD(bp, BNX2_NVM_COMMAND);
2717 if (val & BNX2_NVM_COMMAND_DONE)
2718 break;
2719 }
2720
2721 if (j >= NVRAM_TIMEOUT_COUNT)
2722 return -EBUSY;
2723 }
2724 return 0;
2725}
2726
2727static void
2728bnx2_disable_nvram_write(struct bnx2 *bp)
2729{
2730 u32 val;
2731
2732 val = REG_RD(bp, BNX2_MISC_CFG);
2733 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
2734}
2735
2736
2737static void
2738bnx2_enable_nvram_access(struct bnx2 *bp)
2739{
2740 u32 val;
2741
2742 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
2743 /* Enable both bits, even on read. */
2744 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
2745 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
2746}
2747
2748static void
2749bnx2_disable_nvram_access(struct bnx2 *bp)
2750{
2751 u32 val;
2752
2753 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
2754 /* Disable both bits, even after read. */
2755 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
2756 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
2757 BNX2_NVM_ACCESS_ENABLE_WR_EN));
2758}
2759
2760static int
2761bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
2762{
2763 u32 cmd;
2764 int j;
2765
2766 if (bp->flash_info->buffered)
2767 /* Buffered flash, no erase needed */
2768 return 0;
2769
2770 /* Build an erase command */
2771 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
2772 BNX2_NVM_COMMAND_DOIT;
2773
2774 /* Need to clear DONE bit separately. */
2775 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
2776
2777 /* Address of the NVRAM to read from. */
2778 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
2779
2780 /* Issue an erase command. */
2781 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
2782
2783 /* Wait for completion. */
2784 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2785 u32 val;
2786
2787 udelay(5);
2788
2789 val = REG_RD(bp, BNX2_NVM_COMMAND);
2790 if (val & BNX2_NVM_COMMAND_DONE)
2791 break;
2792 }
2793
2794 if (j >= NVRAM_TIMEOUT_COUNT)
2795 return -EBUSY;
2796
2797 return 0;
2798}
2799
2800static int
2801bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
2802{
2803 u32 cmd;
2804 int j;
2805
2806 /* Build the command word. */
2807 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
2808
2809 /* Calculate an offset of a buffered flash. */
2810 if (bp->flash_info->buffered) {
2811 offset = ((offset / bp->flash_info->page_size) <<
2812 bp->flash_info->page_bits) +
2813 (offset % bp->flash_info->page_size);
2814 }
2815
2816 /* Need to clear DONE bit separately. */
2817 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
2818
2819 /* Address of the NVRAM to read from. */
2820 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
2821
2822 /* Issue a read command. */
2823 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
2824
2825 /* Wait for completion. */
2826 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2827 u32 val;
2828
2829 udelay(5);
2830
2831 val = REG_RD(bp, BNX2_NVM_COMMAND);
2832 if (val & BNX2_NVM_COMMAND_DONE) {
2833 val = REG_RD(bp, BNX2_NVM_READ);
2834
2835 val = be32_to_cpu(val);
2836 memcpy(ret_val, &val, 4);
2837 break;
2838 }
2839 }
2840 if (j >= NVRAM_TIMEOUT_COUNT)
2841 return -EBUSY;
2842
2843 return 0;
2844}
2845
2846
2847static int
2848bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
2849{
2850 u32 cmd, val32;
2851 int j;
2852
2853 /* Build the command word. */
2854 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
2855
2856 /* Calculate an offset of a buffered flash. */
2857 if (bp->flash_info->buffered) {
2858 offset = ((offset / bp->flash_info->page_size) <<
2859 bp->flash_info->page_bits) +
2860 (offset % bp->flash_info->page_size);
2861 }
2862
2863 /* Need to clear DONE bit separately. */
2864 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
2865
2866 memcpy(&val32, val, 4);
2867 val32 = cpu_to_be32(val32);
2868
2869 /* Write the data. */
2870 REG_WR(bp, BNX2_NVM_WRITE, val32);
2871
2872 /* Address of the NVRAM to write to. */
2873 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
2874
2875 /* Issue the write command. */
2876 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
2877
2878 /* Wait for completion. */
2879 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
2880 udelay(5);
2881
2882 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
2883 break;
2884 }
2885 if (j >= NVRAM_TIMEOUT_COUNT)
2886 return -EBUSY;
2887
2888 return 0;
2889}
2890
2891static int
2892bnx2_init_nvram(struct bnx2 *bp)
2893{
2894 u32 val;
2895 int j, entry_count, rc;
2896 struct flash_spec *flash;
2897
2898 /* Determine the selected interface. */
2899 val = REG_RD(bp, BNX2_NVM_CFG1);
2900
2901 entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
2902
2903 rc = 0;
2904 if (val & 0x40000000) {
2905
2906 /* Flash interface has been reconfigured */
2907 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08002908 j++, flash++) {
2909 if ((val & FLASH_BACKUP_STRAP_MASK) ==
2910 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002911 bp->flash_info = flash;
2912 break;
2913 }
2914 }
2915 }
2916 else {
Michael Chan37137702005-11-04 08:49:17 -08002917 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07002918 /* Not yet been reconfigured */
2919
Michael Chan37137702005-11-04 08:49:17 -08002920 if (val & (1 << 23))
2921 mask = FLASH_BACKUP_STRAP_MASK;
2922 else
2923 mask = FLASH_STRAP_MASK;
2924
Michael Chanb6016b72005-05-26 13:03:09 -07002925 for (j = 0, flash = &flash_table[0]; j < entry_count;
2926 j++, flash++) {
2927
Michael Chan37137702005-11-04 08:49:17 -08002928 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002929 bp->flash_info = flash;
2930
2931 /* Request access to the flash interface. */
2932 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
2933 return rc;
2934
2935 /* Enable access to flash interface */
2936 bnx2_enable_nvram_access(bp);
2937
2938 /* Reconfigure the flash interface */
2939 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
2940 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
2941 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
2942 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
2943
2944 /* Disable access to flash interface */
2945 bnx2_disable_nvram_access(bp);
2946 bnx2_release_nvram_lock(bp);
2947
2948 break;
2949 }
2950 }
2951 } /* if (val & 0x40000000) */
2952
2953 if (j == entry_count) {
2954 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08002955 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08002956 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07002957 }
2958
Michael Chan1122db72006-01-23 16:11:42 -08002959 val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
2960 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
2961 if (val)
2962 bp->flash_size = val;
2963 else
2964 bp->flash_size = bp->flash_info->total_size;
2965
Michael Chanb6016b72005-05-26 13:03:09 -07002966 return rc;
2967}
2968
2969static int
2970bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
2971 int buf_size)
2972{
2973 int rc = 0;
2974 u32 cmd_flags, offset32, len32, extra;
2975
2976 if (buf_size == 0)
2977 return 0;
2978
2979 /* Request access to the flash interface. */
2980 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
2981 return rc;
2982
2983 /* Enable access to flash interface */
2984 bnx2_enable_nvram_access(bp);
2985
2986 len32 = buf_size;
2987 offset32 = offset;
2988 extra = 0;
2989
2990 cmd_flags = 0;
2991
2992 if (offset32 & 3) {
2993 u8 buf[4];
2994 u32 pre_len;
2995
2996 offset32 &= ~3;
2997 pre_len = 4 - (offset & 3);
2998
2999 if (pre_len >= len32) {
3000 pre_len = len32;
3001 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3002 BNX2_NVM_COMMAND_LAST;
3003 }
3004 else {
3005 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3006 }
3007
3008 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3009
3010 if (rc)
3011 return rc;
3012
3013 memcpy(ret_buf, buf + (offset & 3), pre_len);
3014
3015 offset32 += 4;
3016 ret_buf += pre_len;
3017 len32 -= pre_len;
3018 }
3019 if (len32 & 3) {
3020 extra = 4 - (len32 & 3);
3021 len32 = (len32 + 4) & ~3;
3022 }
3023
3024 if (len32 == 4) {
3025 u8 buf[4];
3026
3027 if (cmd_flags)
3028 cmd_flags = BNX2_NVM_COMMAND_LAST;
3029 else
3030 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3031 BNX2_NVM_COMMAND_LAST;
3032
3033 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3034
3035 memcpy(ret_buf, buf, 4 - extra);
3036 }
3037 else if (len32 > 0) {
3038 u8 buf[4];
3039
3040 /* Read the first word. */
3041 if (cmd_flags)
3042 cmd_flags = 0;
3043 else
3044 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3045
3046 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
3047
3048 /* Advance to the next dword. */
3049 offset32 += 4;
3050 ret_buf += 4;
3051 len32 -= 4;
3052
3053 while (len32 > 4 && rc == 0) {
3054 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
3055
3056 /* Advance to the next dword. */
3057 offset32 += 4;
3058 ret_buf += 4;
3059 len32 -= 4;
3060 }
3061
3062 if (rc)
3063 return rc;
3064
3065 cmd_flags = BNX2_NVM_COMMAND_LAST;
3066 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3067
3068 memcpy(ret_buf, buf, 4 - extra);
3069 }
3070
3071 /* Disable access to flash interface */
3072 bnx2_disable_nvram_access(bp);
3073
3074 bnx2_release_nvram_lock(bp);
3075
3076 return rc;
3077}
3078
3079static int
3080bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
3081 int buf_size)
3082{
3083 u32 written, offset32, len32;
Michael Chanae181bc2006-05-22 16:39:20 -07003084 u8 *buf, start[4], end[4], *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07003085 int rc = 0;
3086 int align_start, align_end;
3087
3088 buf = data_buf;
3089 offset32 = offset;
3090 len32 = buf_size;
3091 align_start = align_end = 0;
3092
3093 if ((align_start = (offset32 & 3))) {
3094 offset32 &= ~3;
3095 len32 += align_start;
3096 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
3097 return rc;
3098 }
3099
3100 if (len32 & 3) {
3101 if ((len32 > 4) || !align_start) {
3102 align_end = 4 - (len32 & 3);
3103 len32 += align_end;
3104 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4,
3105 end, 4))) {
3106 return rc;
3107 }
3108 }
3109 }
3110
3111 if (align_start || align_end) {
3112 buf = kmalloc(len32, GFP_KERNEL);
3113 if (buf == 0)
3114 return -ENOMEM;
3115 if (align_start) {
3116 memcpy(buf, start, 4);
3117 }
3118 if (align_end) {
3119 memcpy(buf + len32 - 4, end, 4);
3120 }
3121 memcpy(buf + align_start, data_buf, buf_size);
3122 }
3123
Michael Chanae181bc2006-05-22 16:39:20 -07003124 if (bp->flash_info->buffered == 0) {
3125 flash_buffer = kmalloc(264, GFP_KERNEL);
3126 if (flash_buffer == NULL) {
3127 rc = -ENOMEM;
3128 goto nvram_write_end;
3129 }
3130 }
3131
Michael Chanb6016b72005-05-26 13:03:09 -07003132 written = 0;
3133 while ((written < len32) && (rc == 0)) {
3134 u32 page_start, page_end, data_start, data_end;
3135 u32 addr, cmd_flags;
3136 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003137
3138 /* Find the page_start addr */
3139 page_start = offset32 + written;
3140 page_start -= (page_start % bp->flash_info->page_size);
3141 /* Find the page_end addr */
3142 page_end = page_start + bp->flash_info->page_size;
3143 /* Find the data_start addr */
3144 data_start = (written == 0) ? offset32 : page_start;
3145 /* Find the data_end addr */
3146 data_end = (page_end > offset32 + len32) ?
3147 (offset32 + len32) : page_end;
3148
3149 /* Request access to the flash interface. */
3150 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3151 goto nvram_write_end;
3152
3153 /* Enable access to flash interface */
3154 bnx2_enable_nvram_access(bp);
3155
3156 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3157 if (bp->flash_info->buffered == 0) {
3158 int j;
3159
3160 /* Read the whole page into the buffer
3161 * (non-buffer flash only) */
3162 for (j = 0; j < bp->flash_info->page_size; j += 4) {
3163 if (j == (bp->flash_info->page_size - 4)) {
3164 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3165 }
3166 rc = bnx2_nvram_read_dword(bp,
3167 page_start + j,
3168 &flash_buffer[j],
3169 cmd_flags);
3170
3171 if (rc)
3172 goto nvram_write_end;
3173
3174 cmd_flags = 0;
3175 }
3176 }
3177
3178 /* Enable writes to flash interface (unlock write-protect) */
3179 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
3180 goto nvram_write_end;
3181
3182 /* Erase the page */
3183 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
3184 goto nvram_write_end;
3185
3186 /* Re-enable the write again for the actual write */
3187 bnx2_enable_nvram_write(bp);
3188
3189 /* Loop to write back the buffer data from page_start to
3190 * data_start */
3191 i = 0;
3192 if (bp->flash_info->buffered == 0) {
3193 for (addr = page_start; addr < data_start;
3194 addr += 4, i += 4) {
3195
3196 rc = bnx2_nvram_write_dword(bp, addr,
3197 &flash_buffer[i], cmd_flags);
3198
3199 if (rc != 0)
3200 goto nvram_write_end;
3201
3202 cmd_flags = 0;
3203 }
3204 }
3205
3206 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07003207 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07003208 if ((addr == page_end - 4) ||
3209 ((bp->flash_info->buffered) &&
3210 (addr == data_end - 4))) {
3211
3212 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3213 }
3214 rc = bnx2_nvram_write_dword(bp, addr, buf,
3215 cmd_flags);
3216
3217 if (rc != 0)
3218 goto nvram_write_end;
3219
3220 cmd_flags = 0;
3221 buf += 4;
3222 }
3223
3224 /* Loop to write back the buffer data from data_end
3225 * to page_end */
3226 if (bp->flash_info->buffered == 0) {
3227 for (addr = data_end; addr < page_end;
3228 addr += 4, i += 4) {
3229
3230 if (addr == page_end-4) {
3231 cmd_flags = BNX2_NVM_COMMAND_LAST;
3232 }
3233 rc = bnx2_nvram_write_dword(bp, addr,
3234 &flash_buffer[i], cmd_flags);
3235
3236 if (rc != 0)
3237 goto nvram_write_end;
3238
3239 cmd_flags = 0;
3240 }
3241 }
3242
3243 /* Disable writes to flash interface (lock write-protect) */
3244 bnx2_disable_nvram_write(bp);
3245
3246 /* Disable access to flash interface */
3247 bnx2_disable_nvram_access(bp);
3248 bnx2_release_nvram_lock(bp);
3249
3250 /* Increment written */
3251 written += data_end - data_start;
3252 }
3253
3254nvram_write_end:
Michael Chanae181bc2006-05-22 16:39:20 -07003255 if (bp->flash_info->buffered == 0)
3256 kfree(flash_buffer);
3257
Michael Chanb6016b72005-05-26 13:03:09 -07003258 if (align_start || align_end)
3259 kfree(buf);
3260 return rc;
3261}
3262
3263static int
3264bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
3265{
3266 u32 val;
3267 int i, rc = 0;
3268
3269 /* Wait for the current PCI transaction to complete before
3270 * issuing a reset. */
3271 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
3272 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
3273 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
3274 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
3275 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
3276 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
3277 udelay(5);
3278
Michael Chanb090ae22006-01-23 16:07:10 -08003279 /* Wait for the firmware to tell us it is ok to issue a reset. */
3280 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
3281
Michael Chanb6016b72005-05-26 13:03:09 -07003282 /* Deposit a driver reset signature so the firmware knows that
3283 * this is a soft reset. */
Michael Chane3648b32005-11-04 08:51:21 -08003284 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
Michael Chanb6016b72005-05-26 13:03:09 -07003285 BNX2_DRV_RESET_SIGNATURE_MAGIC);
3286
Michael Chanb6016b72005-05-26 13:03:09 -07003287 /* Do a dummy read to force the chip to complete all current transaction
3288 * before we issue a reset. */
3289 val = REG_RD(bp, BNX2_MISC_ID);
3290
3291 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3292 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
3293 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
3294
3295 /* Chip reset. */
3296 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
3297
3298 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3299 (CHIP_ID(bp) == CHIP_ID_5706_A1))
3300 msleep(15);
3301
3302 /* Reset takes approximate 30 usec */
3303 for (i = 0; i < 10; i++) {
3304 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
3305 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3306 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0) {
3307 break;
3308 }
3309 udelay(10);
3310 }
3311
3312 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3313 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
3314 printk(KERN_ERR PFX "Chip reset did not complete\n");
3315 return -EBUSY;
3316 }
3317
3318 /* Make sure byte swapping is properly configured. */
3319 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
3320 if (val != 0x01020304) {
3321 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
3322 return -ENODEV;
3323 }
3324
Michael Chanb6016b72005-05-26 13:03:09 -07003325 /* Wait for the firmware to finish its initialization. */
Michael Chanb090ae22006-01-23 16:07:10 -08003326 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
3327 if (rc)
3328 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003329
3330 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
3331 /* Adjust the voltage regular to two steps lower. The default
3332 * of this register is 0x0000000e. */
3333 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
3334
3335 /* Remove bad rbuf memory from the free pool. */
3336 rc = bnx2_alloc_bad_rbuf(bp);
3337 }
3338
3339 return rc;
3340}
3341
3342static int
3343bnx2_init_chip(struct bnx2 *bp)
3344{
3345 u32 val;
Michael Chanb090ae22006-01-23 16:07:10 -08003346 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003347
3348 /* Make sure the interrupt is not active. */
3349 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3350
3351 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
3352 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
3353#ifdef __BIG_ENDIAN
3354 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
3355#endif
3356 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
3357 DMA_READ_CHANS << 12 |
3358 DMA_WRITE_CHANS << 16;
3359
3360 val |= (0x2 << 20) | (1 << 11);
3361
Michael Chandda1e392006-01-23 16:08:14 -08003362 if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07003363 val |= (1 << 23);
3364
3365 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
3366 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG))
3367 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
3368
3369 REG_WR(bp, BNX2_DMA_CONFIG, val);
3370
3371 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
3372 val = REG_RD(bp, BNX2_TDMA_CONFIG);
3373 val |= BNX2_TDMA_CONFIG_ONE_DMA;
3374 REG_WR(bp, BNX2_TDMA_CONFIG, val);
3375 }
3376
3377 if (bp->flags & PCIX_FLAG) {
3378 u16 val16;
3379
3380 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
3381 &val16);
3382 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
3383 val16 & ~PCI_X_CMD_ERO);
3384 }
3385
3386 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3387 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
3388 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
3389 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
3390
3391 /* Initialize context mapping and zero out the quick contexts. The
3392 * context block must have already been enabled. */
3393 bnx2_init_context(bp);
3394
Michael Chanfba9fe92006-06-12 22:21:25 -07003395 if ((rc = bnx2_init_cpus(bp)) != 0)
3396 return rc;
3397
Michael Chanb6016b72005-05-26 13:03:09 -07003398 bnx2_init_nvram(bp);
3399
3400 bnx2_set_mac_addr(bp);
3401
3402 val = REG_RD(bp, BNX2_MQ_CONFIG);
3403 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
3404 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
3405 REG_WR(bp, BNX2_MQ_CONFIG, val);
3406
3407 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
3408 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
3409 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
3410
3411 val = (BCM_PAGE_BITS - 8) << 24;
3412 REG_WR(bp, BNX2_RV2P_CONFIG, val);
3413
3414 /* Configure page size. */
3415 val = REG_RD(bp, BNX2_TBDR_CONFIG);
3416 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
3417 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
3418 REG_WR(bp, BNX2_TBDR_CONFIG, val);
3419
3420 val = bp->mac_addr[0] +
3421 (bp->mac_addr[1] << 8) +
3422 (bp->mac_addr[2] << 16) +
3423 bp->mac_addr[3] +
3424 (bp->mac_addr[4] << 8) +
3425 (bp->mac_addr[5] << 16);
3426 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
3427
3428 /* Program the MTU. Also include 4 bytes for CRC32. */
3429 val = bp->dev->mtu + ETH_HLEN + 4;
3430 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
3431 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
3432 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
3433
3434 bp->last_status_idx = 0;
3435 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
3436
3437 /* Set up how to generate a link change interrupt. */
3438 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
3439
3440 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
3441 (u64) bp->status_blk_mapping & 0xffffffff);
3442 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
3443
3444 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
3445 (u64) bp->stats_blk_mapping & 0xffffffff);
3446 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
3447 (u64) bp->stats_blk_mapping >> 32);
3448
3449 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
3450 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
3451
3452 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
3453 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
3454
3455 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
3456 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
3457
3458 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
3459
3460 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
3461
3462 REG_WR(bp, BNX2_HC_COM_TICKS,
3463 (bp->com_ticks_int << 16) | bp->com_ticks);
3464
3465 REG_WR(bp, BNX2_HC_CMD_TICKS,
3466 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
3467
3468 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
3469 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
3470
3471 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
3472 REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_COLLECT_STATS);
3473 else {
3474 REG_WR(bp, BNX2_HC_CONFIG, BNX2_HC_CONFIG_RX_TMR_MODE |
3475 BNX2_HC_CONFIG_TX_TMR_MODE |
3476 BNX2_HC_CONFIG_COLLECT_STATS);
3477 }
3478
3479 /* Clear internal stats counters. */
3480 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
3481
3482 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_BITS_LINK_STATE);
3483
Michael Chane29054f2006-01-23 16:06:06 -08003484 if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
3485 BNX2_PORT_FEATURE_ASF_ENABLED)
3486 bp->flags |= ASF_ENABLE_FLAG;
3487
Michael Chanb6016b72005-05-26 13:03:09 -07003488 /* Initialize the receive filter. */
3489 bnx2_set_rx_mode(bp->dev);
3490
Michael Chanb090ae22006-01-23 16:07:10 -08003491 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
3492 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003493
3494 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, 0x5ffffff);
3495 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
3496
3497 udelay(20);
3498
Michael Chanbf5295b2006-03-23 01:11:56 -08003499 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
3500
Michael Chanb090ae22006-01-23 16:07:10 -08003501 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003502}
3503
3504
3505static void
3506bnx2_init_tx_ring(struct bnx2 *bp)
3507{
3508 struct tx_bd *txbd;
3509 u32 val;
3510
Michael Chan2f8af122006-08-15 01:39:10 -07003511 bp->tx_wake_thresh = bp->tx_ring_size / 2;
3512
Michael Chanb6016b72005-05-26 13:03:09 -07003513 txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
3514
3515 txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
3516 txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
3517
3518 bp->tx_prod = 0;
3519 bp->tx_cons = 0;
Michael Chanf4e418f2005-11-04 08:53:48 -08003520 bp->hw_tx_cons = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003521 bp->tx_prod_bseq = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003522
3523 val = BNX2_L2CTX_TYPE_TYPE_L2;
3524 val |= BNX2_L2CTX_TYPE_SIZE_L2;
3525 CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TYPE, val);
3526
3527 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2;
3528 val |= 8 << 16;
3529 CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_CMD_TYPE, val);
3530
3531 val = (u64) bp->tx_desc_mapping >> 32;
3532 CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TBDR_BHADDR_HI, val);
3533
3534 val = (u64) bp->tx_desc_mapping & 0xffffffff;
3535 CTX_WR(bp, GET_CID_ADDR(TX_CID), BNX2_L2CTX_TBDR_BHADDR_LO, val);
3536}
3537
3538static void
3539bnx2_init_rx_ring(struct bnx2 *bp)
3540{
3541 struct rx_bd *rxbd;
3542 int i;
3543 u16 prod, ring_prod;
3544 u32 val;
3545
3546 /* 8 for CRC and VLAN */
3547 bp->rx_buf_use_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
3548 /* 8 for alignment */
3549 bp->rx_buf_size = bp->rx_buf_use_size + 8;
3550
3551 ring_prod = prod = bp->rx_prod = 0;
3552 bp->rx_cons = 0;
Michael Chanf4e418f2005-11-04 08:53:48 -08003553 bp->hw_rx_cons = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003554 bp->rx_prod_bseq = 0;
3555
Michael Chan13daffa2006-03-20 17:49:20 -08003556 for (i = 0; i < bp->rx_max_ring; i++) {
3557 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07003558
Michael Chan13daffa2006-03-20 17:49:20 -08003559 rxbd = &bp->rx_desc_ring[i][0];
3560 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
3561 rxbd->rx_bd_len = bp->rx_buf_use_size;
3562 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
3563 }
3564 if (i == (bp->rx_max_ring - 1))
3565 j = 0;
3566 else
3567 j = i + 1;
3568 rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32;
3569 rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] &
3570 0xffffffff;
3571 }
Michael Chanb6016b72005-05-26 13:03:09 -07003572
3573 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
3574 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
3575 val |= 0x02 << 8;
3576 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
3577
Michael Chan13daffa2006-03-20 17:49:20 -08003578 val = (u64) bp->rx_desc_mapping[0] >> 32;
Michael Chanb6016b72005-05-26 13:03:09 -07003579 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
3580
Michael Chan13daffa2006-03-20 17:49:20 -08003581 val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07003582 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
3583
Michael Chan236b6392006-03-20 17:49:02 -08003584 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07003585 if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
3586 break;
3587 }
3588 prod = NEXT_RX_BD(prod);
3589 ring_prod = RX_RING_IDX(prod);
3590 }
3591 bp->rx_prod = prod;
3592
3593 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
3594
3595 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
3596}
3597
3598static void
Michael Chan13daffa2006-03-20 17:49:20 -08003599bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
3600{
3601 u32 num_rings, max;
3602
3603 bp->rx_ring_size = size;
3604 num_rings = 1;
3605 while (size > MAX_RX_DESC_CNT) {
3606 size -= MAX_RX_DESC_CNT;
3607 num_rings++;
3608 }
3609 /* round to next power of 2 */
3610 max = MAX_RX_RINGS;
3611 while ((max & num_rings) == 0)
3612 max >>= 1;
3613
3614 if (num_rings != max)
3615 max <<= 1;
3616
3617 bp->rx_max_ring = max;
3618 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
3619}
3620
3621static void
Michael Chanb6016b72005-05-26 13:03:09 -07003622bnx2_free_tx_skbs(struct bnx2 *bp)
3623{
3624 int i;
3625
3626 if (bp->tx_buf_ring == NULL)
3627 return;
3628
3629 for (i = 0; i < TX_DESC_CNT; ) {
3630 struct sw_bd *tx_buf = &bp->tx_buf_ring[i];
3631 struct sk_buff *skb = tx_buf->skb;
3632 int j, last;
3633
3634 if (skb == NULL) {
3635 i++;
3636 continue;
3637 }
3638
3639 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
3640 skb_headlen(skb), PCI_DMA_TODEVICE);
3641
3642 tx_buf->skb = NULL;
3643
3644 last = skb_shinfo(skb)->nr_frags;
3645 for (j = 0; j < last; j++) {
3646 tx_buf = &bp->tx_buf_ring[i + j + 1];
3647 pci_unmap_page(bp->pdev,
3648 pci_unmap_addr(tx_buf, mapping),
3649 skb_shinfo(skb)->frags[j].size,
3650 PCI_DMA_TODEVICE);
3651 }
Michael Chan745720e2006-06-29 12:37:41 -07003652 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003653 i += j + 1;
3654 }
3655
3656}
3657
3658static void
3659bnx2_free_rx_skbs(struct bnx2 *bp)
3660{
3661 int i;
3662
3663 if (bp->rx_buf_ring == NULL)
3664 return;
3665
Michael Chan13daffa2006-03-20 17:49:20 -08003666 for (i = 0; i < bp->rx_max_ring_idx; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07003667 struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
3668 struct sk_buff *skb = rx_buf->skb;
3669
Michael Chan05d0f1c2005-11-04 08:53:48 -08003670 if (skb == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07003671 continue;
3672
3673 pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
3674 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
3675
3676 rx_buf->skb = NULL;
3677
Michael Chan745720e2006-06-29 12:37:41 -07003678 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07003679 }
3680}
3681
3682static void
3683bnx2_free_skbs(struct bnx2 *bp)
3684{
3685 bnx2_free_tx_skbs(bp);
3686 bnx2_free_rx_skbs(bp);
3687}
3688
3689static int
3690bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
3691{
3692 int rc;
3693
3694 rc = bnx2_reset_chip(bp, reset_code);
3695 bnx2_free_skbs(bp);
3696 if (rc)
3697 return rc;
3698
Michael Chanfba9fe92006-06-12 22:21:25 -07003699 if ((rc = bnx2_init_chip(bp)) != 0)
3700 return rc;
3701
Michael Chanb6016b72005-05-26 13:03:09 -07003702 bnx2_init_tx_ring(bp);
3703 bnx2_init_rx_ring(bp);
3704 return 0;
3705}
3706
3707static int
3708bnx2_init_nic(struct bnx2 *bp)
3709{
3710 int rc;
3711
3712 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
3713 return rc;
3714
3715 bnx2_init_phy(bp);
3716 bnx2_set_link(bp);
3717 return 0;
3718}
3719
3720static int
3721bnx2_test_registers(struct bnx2 *bp)
3722{
3723 int ret;
3724 int i;
Arjan van de Venf71e1302006-03-03 21:33:57 -05003725 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07003726 u16 offset;
3727 u16 flags;
3728 u32 rw_mask;
3729 u32 ro_mask;
3730 } reg_tbl[] = {
3731 { 0x006c, 0, 0x00000000, 0x0000003f },
3732 { 0x0090, 0, 0xffffffff, 0x00000000 },
3733 { 0x0094, 0, 0x00000000, 0x00000000 },
3734
3735 { 0x0404, 0, 0x00003f00, 0x00000000 },
3736 { 0x0418, 0, 0x00000000, 0xffffffff },
3737 { 0x041c, 0, 0x00000000, 0xffffffff },
3738 { 0x0420, 0, 0x00000000, 0x80ffffff },
3739 { 0x0424, 0, 0x00000000, 0x00000000 },
3740 { 0x0428, 0, 0x00000000, 0x00000001 },
3741 { 0x0450, 0, 0x00000000, 0x0000ffff },
3742 { 0x0454, 0, 0x00000000, 0xffffffff },
3743 { 0x0458, 0, 0x00000000, 0xffffffff },
3744
3745 { 0x0808, 0, 0x00000000, 0xffffffff },
3746 { 0x0854, 0, 0x00000000, 0xffffffff },
3747 { 0x0868, 0, 0x00000000, 0x77777777 },
3748 { 0x086c, 0, 0x00000000, 0x77777777 },
3749 { 0x0870, 0, 0x00000000, 0x77777777 },
3750 { 0x0874, 0, 0x00000000, 0x77777777 },
3751
3752 { 0x0c00, 0, 0x00000000, 0x00000001 },
3753 { 0x0c04, 0, 0x00000000, 0x03ff0001 },
3754 { 0x0c08, 0, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07003755
3756 { 0x1000, 0, 0x00000000, 0x00000001 },
3757 { 0x1004, 0, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07003758
3759 { 0x1408, 0, 0x01c00800, 0x00000000 },
3760 { 0x149c, 0, 0x8000ffff, 0x00000000 },
3761 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08003762 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07003763 { 0x14b0, 0, 0x00000002, 0x00000001 },
3764 { 0x14b8, 0, 0x00000000, 0x00000000 },
3765 { 0x14c0, 0, 0x00000000, 0x00000009 },
3766 { 0x14c4, 0, 0x00003fff, 0x00000000 },
3767 { 0x14cc, 0, 0x00000000, 0x00000001 },
3768 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07003769
3770 { 0x1800, 0, 0x00000000, 0x00000001 },
3771 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07003772
3773 { 0x2800, 0, 0x00000000, 0x00000001 },
3774 { 0x2804, 0, 0x00000000, 0x00003f01 },
3775 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
3776 { 0x2810, 0, 0xffff0000, 0x00000000 },
3777 { 0x2814, 0, 0xffff0000, 0x00000000 },
3778 { 0x2818, 0, 0xffff0000, 0x00000000 },
3779 { 0x281c, 0, 0xffff0000, 0x00000000 },
3780 { 0x2834, 0, 0xffffffff, 0x00000000 },
3781 { 0x2840, 0, 0x00000000, 0xffffffff },
3782 { 0x2844, 0, 0x00000000, 0xffffffff },
3783 { 0x2848, 0, 0xffffffff, 0x00000000 },
3784 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
3785
3786 { 0x2c00, 0, 0x00000000, 0x00000011 },
3787 { 0x2c04, 0, 0x00000000, 0x00030007 },
3788
Michael Chanb6016b72005-05-26 13:03:09 -07003789 { 0x3c00, 0, 0x00000000, 0x00000001 },
3790 { 0x3c04, 0, 0x00000000, 0x00070000 },
3791 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
3792 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
3793 { 0x3c10, 0, 0xffffffff, 0x00000000 },
3794 { 0x3c14, 0, 0x00000000, 0xffffffff },
3795 { 0x3c18, 0, 0x00000000, 0xffffffff },
3796 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
3797 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07003798
3799 { 0x5004, 0, 0x00000000, 0x0000007f },
3800 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
3801 { 0x500c, 0, 0xf800f800, 0x07ff07ff },
3802
Michael Chanb6016b72005-05-26 13:03:09 -07003803 { 0x5c00, 0, 0x00000000, 0x00000001 },
3804 { 0x5c04, 0, 0x00000000, 0x0003000f },
3805 { 0x5c08, 0, 0x00000003, 0x00000000 },
3806 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
3807 { 0x5c10, 0, 0x00000000, 0xffffffff },
3808 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
3809 { 0x5c84, 0, 0x00000000, 0x0000f333 },
3810 { 0x5c88, 0, 0x00000000, 0x00077373 },
3811 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
3812
3813 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
3814 { 0x680c, 0, 0xffffffff, 0x00000000 },
3815 { 0x6810, 0, 0xffffffff, 0x00000000 },
3816 { 0x6814, 0, 0xffffffff, 0x00000000 },
3817 { 0x6818, 0, 0xffffffff, 0x00000000 },
3818 { 0x681c, 0, 0xffffffff, 0x00000000 },
3819 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
3820 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
3821 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
3822 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
3823 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
3824 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
3825 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
3826 { 0x683c, 0, 0x0000ffff, 0x00000000 },
3827 { 0x6840, 0, 0x00000ff0, 0x00000000 },
3828 { 0x6844, 0, 0x00ffff00, 0x00000000 },
3829 { 0x684c, 0, 0xffffffff, 0x00000000 },
3830 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
3831 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
3832 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
3833 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
3834 { 0x6908, 0, 0x00000000, 0x0001ff0f },
3835 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
3836
3837 { 0xffff, 0, 0x00000000, 0x00000000 },
3838 };
3839
3840 ret = 0;
3841 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
3842 u32 offset, rw_mask, ro_mask, save_val, val;
3843
3844 offset = (u32) reg_tbl[i].offset;
3845 rw_mask = reg_tbl[i].rw_mask;
3846 ro_mask = reg_tbl[i].ro_mask;
3847
Peter Hagervall14ab9b82005-08-10 14:18:16 -07003848 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07003849
Peter Hagervall14ab9b82005-08-10 14:18:16 -07003850 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07003851
Peter Hagervall14ab9b82005-08-10 14:18:16 -07003852 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07003853 if ((val & rw_mask) != 0) {
3854 goto reg_test_err;
3855 }
3856
3857 if ((val & ro_mask) != (save_val & ro_mask)) {
3858 goto reg_test_err;
3859 }
3860
Peter Hagervall14ab9b82005-08-10 14:18:16 -07003861 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07003862
Peter Hagervall14ab9b82005-08-10 14:18:16 -07003863 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07003864 if ((val & rw_mask) != rw_mask) {
3865 goto reg_test_err;
3866 }
3867
3868 if ((val & ro_mask) != (save_val & ro_mask)) {
3869 goto reg_test_err;
3870 }
3871
Peter Hagervall14ab9b82005-08-10 14:18:16 -07003872 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07003873 continue;
3874
3875reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07003876 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07003877 ret = -ENODEV;
3878 break;
3879 }
3880 return ret;
3881}
3882
3883static int
3884bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
3885{
Arjan van de Venf71e1302006-03-03 21:33:57 -05003886 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07003887 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
3888 int i;
3889
3890 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
3891 u32 offset;
3892
3893 for (offset = 0; offset < size; offset += 4) {
3894
3895 REG_WR_IND(bp, start + offset, test_pattern[i]);
3896
3897 if (REG_RD_IND(bp, start + offset) !=
3898 test_pattern[i]) {
3899 return -ENODEV;
3900 }
3901 }
3902 }
3903 return 0;
3904}
3905
3906static int
3907bnx2_test_memory(struct bnx2 *bp)
3908{
3909 int ret = 0;
3910 int i;
Arjan van de Venf71e1302006-03-03 21:33:57 -05003911 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07003912 u32 offset;
3913 u32 len;
3914 } mem_tbl[] = {
3915 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08003916 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07003917 { 0xe0000, 0x4000 },
3918 { 0x120000, 0x4000 },
3919 { 0x1a0000, 0x4000 },
3920 { 0x160000, 0x4000 },
3921 { 0xffffffff, 0 },
3922 };
3923
3924 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
3925 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
3926 mem_tbl[i].len)) != 0) {
3927 return ret;
3928 }
3929 }
3930
3931 return ret;
3932}
3933
Michael Chanbc5a0692006-01-23 16:13:22 -08003934#define BNX2_MAC_LOOPBACK 0
3935#define BNX2_PHY_LOOPBACK 1
3936
Michael Chanb6016b72005-05-26 13:03:09 -07003937static int
Michael Chanbc5a0692006-01-23 16:13:22 -08003938bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07003939{
3940 unsigned int pkt_size, num_pkts, i;
3941 struct sk_buff *skb, *rx_skb;
3942 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08003943 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07003944 dma_addr_t map;
3945 struct tx_bd *txbd;
3946 struct sw_bd *rx_buf;
3947 struct l2_fhdr *rx_hdr;
3948 int ret = -ENODEV;
3949
Michael Chanbc5a0692006-01-23 16:13:22 -08003950 if (loopback_mode == BNX2_MAC_LOOPBACK) {
3951 bp->loopback = MAC_LOOPBACK;
3952 bnx2_set_mac_loopback(bp);
3953 }
3954 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
3955 bp->loopback = 0;
3956 bnx2_set_phy_loopback(bp);
3957 }
3958 else
3959 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07003960
3961 pkt_size = 1514;
Michael Chan932f3772006-08-15 01:39:36 -07003962 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08003963 if (!skb)
3964 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07003965 packet = skb_put(skb, pkt_size);
3966 memcpy(packet, bp->mac_addr, 6);
3967 memset(packet + 6, 0x0, 8);
3968 for (i = 14; i < pkt_size; i++)
3969 packet[i] = (unsigned char) (i & 0xff);
3970
3971 map = pci_map_single(bp->pdev, skb->data, pkt_size,
3972 PCI_DMA_TODEVICE);
3973
Michael Chanbf5295b2006-03-23 01:11:56 -08003974 REG_WR(bp, BNX2_HC_COMMAND,
3975 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
3976
Michael Chanb6016b72005-05-26 13:03:09 -07003977 REG_RD(bp, BNX2_HC_COMMAND);
3978
3979 udelay(5);
3980 rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0;
3981
Michael Chanb6016b72005-05-26 13:03:09 -07003982 num_pkts = 0;
3983
Michael Chanbc5a0692006-01-23 16:13:22 -08003984 txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07003985
3986 txbd->tx_bd_haddr_hi = (u64) map >> 32;
3987 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
3988 txbd->tx_bd_mss_nbytes = pkt_size;
3989 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
3990
3991 num_pkts++;
Michael Chanbc5a0692006-01-23 16:13:22 -08003992 bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
3993 bp->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07003994
Michael Chanbc5a0692006-01-23 16:13:22 -08003995 REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, bp->tx_prod);
3996 REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07003997
3998 udelay(100);
3999
Michael Chanbf5295b2006-03-23 01:11:56 -08004000 REG_WR(bp, BNX2_HC_COMMAND,
4001 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
4002
Michael Chanb6016b72005-05-26 13:03:09 -07004003 REG_RD(bp, BNX2_HC_COMMAND);
4004
4005 udelay(5);
4006
4007 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07004008 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004009
Michael Chanbc5a0692006-01-23 16:13:22 -08004010 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) {
Michael Chanb6016b72005-05-26 13:03:09 -07004011 goto loopback_test_done;
4012 }
4013
4014 rx_idx = bp->status_blk->status_rx_quick_consumer_index0;
4015 if (rx_idx != rx_start_idx + num_pkts) {
4016 goto loopback_test_done;
4017 }
4018
4019 rx_buf = &bp->rx_buf_ring[rx_start_idx];
4020 rx_skb = rx_buf->skb;
4021
4022 rx_hdr = (struct l2_fhdr *) rx_skb->data;
4023 skb_reserve(rx_skb, bp->rx_offset);
4024
4025 pci_dma_sync_single_for_cpu(bp->pdev,
4026 pci_unmap_addr(rx_buf, mapping),
4027 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
4028
Michael Chanade2bfe2006-01-23 16:09:51 -08004029 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07004030 (L2_FHDR_ERRORS_BAD_CRC |
4031 L2_FHDR_ERRORS_PHY_DECODE |
4032 L2_FHDR_ERRORS_ALIGNMENT |
4033 L2_FHDR_ERRORS_TOO_SHORT |
4034 L2_FHDR_ERRORS_GIANT_FRAME)) {
4035
4036 goto loopback_test_done;
4037 }
4038
4039 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
4040 goto loopback_test_done;
4041 }
4042
4043 for (i = 14; i < pkt_size; i++) {
4044 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
4045 goto loopback_test_done;
4046 }
4047 }
4048
4049 ret = 0;
4050
4051loopback_test_done:
4052 bp->loopback = 0;
4053 return ret;
4054}
4055
Michael Chanbc5a0692006-01-23 16:13:22 -08004056#define BNX2_MAC_LOOPBACK_FAILED 1
4057#define BNX2_PHY_LOOPBACK_FAILED 2
4058#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
4059 BNX2_PHY_LOOPBACK_FAILED)
4060
4061static int
4062bnx2_test_loopback(struct bnx2 *bp)
4063{
4064 int rc = 0;
4065
4066 if (!netif_running(bp->dev))
4067 return BNX2_LOOPBACK_FAILED;
4068
4069 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
4070 spin_lock_bh(&bp->phy_lock);
4071 bnx2_init_phy(bp);
4072 spin_unlock_bh(&bp->phy_lock);
4073 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
4074 rc |= BNX2_MAC_LOOPBACK_FAILED;
4075 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
4076 rc |= BNX2_PHY_LOOPBACK_FAILED;
4077 return rc;
4078}
4079
Michael Chanb6016b72005-05-26 13:03:09 -07004080#define NVRAM_SIZE 0x200
4081#define CRC32_RESIDUAL 0xdebb20e3
4082
4083static int
4084bnx2_test_nvram(struct bnx2 *bp)
4085{
4086 u32 buf[NVRAM_SIZE / 4];
4087 u8 *data = (u8 *) buf;
4088 int rc = 0;
4089 u32 magic, csum;
4090
4091 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
4092 goto test_nvram_done;
4093
4094 magic = be32_to_cpu(buf[0]);
4095 if (magic != 0x669955aa) {
4096 rc = -ENODEV;
4097 goto test_nvram_done;
4098 }
4099
4100 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
4101 goto test_nvram_done;
4102
4103 csum = ether_crc_le(0x100, data);
4104 if (csum != CRC32_RESIDUAL) {
4105 rc = -ENODEV;
4106 goto test_nvram_done;
4107 }
4108
4109 csum = ether_crc_le(0x100, data + 0x100);
4110 if (csum != CRC32_RESIDUAL) {
4111 rc = -ENODEV;
4112 }
4113
4114test_nvram_done:
4115 return rc;
4116}
4117
4118static int
4119bnx2_test_link(struct bnx2 *bp)
4120{
4121 u32 bmsr;
4122
Michael Chanc770a652005-08-25 15:38:39 -07004123 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004124 bnx2_read_phy(bp, MII_BMSR, &bmsr);
4125 bnx2_read_phy(bp, MII_BMSR, &bmsr);
Michael Chanc770a652005-08-25 15:38:39 -07004126 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004127
4128 if (bmsr & BMSR_LSTATUS) {
4129 return 0;
4130 }
4131 return -ENODEV;
4132}
4133
4134static int
4135bnx2_test_intr(struct bnx2 *bp)
4136{
4137 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004138 u16 status_idx;
4139
4140 if (!netif_running(bp->dev))
4141 return -ENODEV;
4142
4143 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
4144
4145 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08004146 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07004147 REG_RD(bp, BNX2_HC_COMMAND);
4148
4149 for (i = 0; i < 10; i++) {
4150 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
4151 status_idx) {
4152
4153 break;
4154 }
4155
4156 msleep_interruptible(10);
4157 }
4158 if (i < 10)
4159 return 0;
4160
4161 return -ENODEV;
4162}
4163
4164static void
4165bnx2_timer(unsigned long data)
4166{
4167 struct bnx2 *bp = (struct bnx2 *) data;
4168 u32 msg;
4169
Michael Chancd339a02005-08-25 15:35:24 -07004170 if (!netif_running(bp->dev))
4171 return;
4172
Michael Chanb6016b72005-05-26 13:03:09 -07004173 if (atomic_read(&bp->intr_sem) != 0)
4174 goto bnx2_restart_timer;
4175
4176 msg = (u32) ++bp->fw_drv_pulse_wr_seq;
Michael Chane3648b32005-11-04 08:51:21 -08004177 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_PULSE_MB, msg);
Michael Chanb6016b72005-05-26 13:03:09 -07004178
Michael Chancea94db2006-06-12 22:16:13 -07004179 bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
4180
Michael Chanb6016b72005-05-26 13:03:09 -07004181 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
4182 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
Michael Chanb6016b72005-05-26 13:03:09 -07004183
Michael Chanc770a652005-08-25 15:38:39 -07004184 spin_lock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004185 if (bp->serdes_an_pending) {
4186 bp->serdes_an_pending--;
4187 }
4188 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
4189 u32 bmcr;
4190
Michael Chancd339a02005-08-25 15:35:24 -07004191 bp->current_interval = bp->timer_interval;
4192
Michael Chanb6016b72005-05-26 13:03:09 -07004193 bnx2_read_phy(bp, MII_BMCR, &bmcr);
4194
4195 if (bmcr & BMCR_ANENABLE) {
4196 u32 phy1, phy2;
4197
4198 bnx2_write_phy(bp, 0x1c, 0x7c00);
4199 bnx2_read_phy(bp, 0x1c, &phy1);
4200
4201 bnx2_write_phy(bp, 0x17, 0x0f01);
4202 bnx2_read_phy(bp, 0x15, &phy2);
4203 bnx2_write_phy(bp, 0x17, 0x0f01);
4204 bnx2_read_phy(bp, 0x15, &phy2);
4205
4206 if ((phy1 & 0x10) && /* SIGNAL DETECT */
4207 !(phy2 & 0x20)) { /* no CONFIG */
4208
4209 bmcr &= ~BMCR_ANENABLE;
4210 bmcr |= BMCR_SPEED1000 |
4211 BMCR_FULLDPLX;
4212 bnx2_write_phy(bp, MII_BMCR, bmcr);
4213 bp->phy_flags |=
4214 PHY_PARALLEL_DETECT_FLAG;
4215 }
4216 }
4217 }
4218 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
4219 (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
4220 u32 phy2;
4221
4222 bnx2_write_phy(bp, 0x17, 0x0f01);
4223 bnx2_read_phy(bp, 0x15, &phy2);
4224 if (phy2 & 0x20) {
4225 u32 bmcr;
4226
4227 bnx2_read_phy(bp, MII_BMCR, &bmcr);
4228 bmcr |= BMCR_ANENABLE;
4229 bnx2_write_phy(bp, MII_BMCR, bmcr);
4230
4231 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
4232
4233 }
4234 }
Michael Chancd339a02005-08-25 15:35:24 -07004235 else
4236 bp->current_interval = bp->timer_interval;
Michael Chanb6016b72005-05-26 13:03:09 -07004237
Michael Chanc770a652005-08-25 15:38:39 -07004238 spin_unlock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004239 }
4240
4241bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07004242 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07004243}
4244
4245/* Called with rtnl_lock */
4246static int
4247bnx2_open(struct net_device *dev)
4248{
Michael Chan972ec0d2006-01-23 16:12:43 -08004249 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004250 int rc;
4251
Pavel Machek829ca9a2005-09-03 15:56:56 -07004252 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07004253 bnx2_disable_int(bp);
4254
4255 rc = bnx2_alloc_mem(bp);
4256 if (rc)
4257 return rc;
4258
4259 if ((CHIP_ID(bp) != CHIP_ID_5706_A0) &&
4260 (CHIP_ID(bp) != CHIP_ID_5706_A1) &&
4261 !disable_msi) {
4262
4263 if (pci_enable_msi(bp->pdev) == 0) {
4264 bp->flags |= USING_MSI_FLAG;
4265 rc = request_irq(bp->pdev->irq, bnx2_msi, 0, dev->name,
4266 dev);
4267 }
4268 else {
4269 rc = request_irq(bp->pdev->irq, bnx2_interrupt,
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07004270 IRQF_SHARED, dev->name, dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004271 }
4272 }
4273 else {
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07004274 rc = request_irq(bp->pdev->irq, bnx2_interrupt, IRQF_SHARED,
Michael Chanb6016b72005-05-26 13:03:09 -07004275 dev->name, dev);
4276 }
4277 if (rc) {
4278 bnx2_free_mem(bp);
4279 return rc;
4280 }
4281
4282 rc = bnx2_init_nic(bp);
4283
4284 if (rc) {
4285 free_irq(bp->pdev->irq, dev);
4286 if (bp->flags & USING_MSI_FLAG) {
4287 pci_disable_msi(bp->pdev);
4288 bp->flags &= ~USING_MSI_FLAG;
4289 }
4290 bnx2_free_skbs(bp);
4291 bnx2_free_mem(bp);
4292 return rc;
4293 }
4294
Michael Chancd339a02005-08-25 15:35:24 -07004295 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07004296
4297 atomic_set(&bp->intr_sem, 0);
4298
4299 bnx2_enable_int(bp);
4300
4301 if (bp->flags & USING_MSI_FLAG) {
4302 /* Test MSI to make sure it is working
4303 * If MSI test fails, go back to INTx mode
4304 */
4305 if (bnx2_test_intr(bp) != 0) {
4306 printk(KERN_WARNING PFX "%s: No interrupt was generated"
4307 " using MSI, switching to INTx mode. Please"
4308 " report this failure to the PCI maintainer"
4309 " and include system chipset information.\n",
4310 bp->dev->name);
4311
4312 bnx2_disable_int(bp);
4313 free_irq(bp->pdev->irq, dev);
4314 pci_disable_msi(bp->pdev);
4315 bp->flags &= ~USING_MSI_FLAG;
4316
4317 rc = bnx2_init_nic(bp);
4318
4319 if (!rc) {
4320 rc = request_irq(bp->pdev->irq, bnx2_interrupt,
Thomas Gleixner1fb9df52006-07-01 19:29:39 -07004321 IRQF_SHARED, dev->name, dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004322 }
4323 if (rc) {
4324 bnx2_free_skbs(bp);
4325 bnx2_free_mem(bp);
4326 del_timer_sync(&bp->timer);
4327 return rc;
4328 }
4329 bnx2_enable_int(bp);
4330 }
4331 }
4332 if (bp->flags & USING_MSI_FLAG) {
4333 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
4334 }
4335
4336 netif_start_queue(dev);
4337
4338 return 0;
4339}
4340
4341static void
4342bnx2_reset_task(void *data)
4343{
4344 struct bnx2 *bp = data;
4345
Michael Chanafdc08b2005-08-25 15:34:29 -07004346 if (!netif_running(bp->dev))
4347 return;
4348
4349 bp->in_reset_task = 1;
Michael Chanb6016b72005-05-26 13:03:09 -07004350 bnx2_netif_stop(bp);
4351
4352 bnx2_init_nic(bp);
4353
4354 atomic_set(&bp->intr_sem, 1);
4355 bnx2_netif_start(bp);
Michael Chanafdc08b2005-08-25 15:34:29 -07004356 bp->in_reset_task = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004357}
4358
4359static void
4360bnx2_tx_timeout(struct net_device *dev)
4361{
Michael Chan972ec0d2006-01-23 16:12:43 -08004362 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004363
4364 /* This allows the netif to be shutdown gracefully before resetting */
4365 schedule_work(&bp->reset_task);
4366}
4367
4368#ifdef BCM_VLAN
4369/* Called with rtnl_lock */
4370static void
4371bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
4372{
Michael Chan972ec0d2006-01-23 16:12:43 -08004373 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004374
4375 bnx2_netif_stop(bp);
4376
4377 bp->vlgrp = vlgrp;
4378 bnx2_set_rx_mode(dev);
4379
4380 bnx2_netif_start(bp);
4381}
4382
4383/* Called with rtnl_lock */
4384static void
4385bnx2_vlan_rx_kill_vid(struct net_device *dev, uint16_t vid)
4386{
Michael Chan972ec0d2006-01-23 16:12:43 -08004387 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004388
4389 bnx2_netif_stop(bp);
4390
4391 if (bp->vlgrp)
4392 bp->vlgrp->vlan_devices[vid] = NULL;
4393 bnx2_set_rx_mode(dev);
4394
4395 bnx2_netif_start(bp);
4396}
4397#endif
4398
Herbert Xu932ff272006-06-09 12:20:56 -07004399/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07004400 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
4401 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07004402 */
4403static int
4404bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
4405{
Michael Chan972ec0d2006-01-23 16:12:43 -08004406 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004407 dma_addr_t mapping;
4408 struct tx_bd *txbd;
4409 struct sw_bd *tx_buf;
4410 u32 len, vlan_tag_flags, last_frag, mss;
4411 u16 prod, ring_prod;
4412 int i;
4413
Michael Chane89bbf12005-08-25 15:36:58 -07004414 if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) {
Michael Chanb6016b72005-05-26 13:03:09 -07004415 netif_stop_queue(dev);
4416 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
4417 dev->name);
4418
4419 return NETDEV_TX_BUSY;
4420 }
4421 len = skb_headlen(skb);
4422 prod = bp->tx_prod;
4423 ring_prod = TX_RING_IDX(prod);
4424
4425 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07004426 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07004427 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
4428 }
4429
4430 if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) {
4431 vlan_tag_flags |=
4432 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
4433 }
4434#ifdef BCM_TSO
Herbert Xu79671682006-06-22 02:40:14 -07004435 if ((mss = skb_shinfo(skb)->gso_size) &&
Michael Chanb6016b72005-05-26 13:03:09 -07004436 (skb->len > (bp->dev->mtu + ETH_HLEN))) {
4437 u32 tcp_opt_len, ip_tcp_len;
4438
4439 if (skb_header_cloned(skb) &&
4440 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
4441 dev_kfree_skb(skb);
4442 return NETDEV_TX_OK;
4443 }
4444
4445 tcp_opt_len = ((skb->h.th->doff - 5) * 4);
4446 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
4447
4448 tcp_opt_len = 0;
4449 if (skb->h.th->doff > 5) {
4450 tcp_opt_len = (skb->h.th->doff - 5) << 2;
4451 }
4452 ip_tcp_len = (skb->nh.iph->ihl << 2) + sizeof(struct tcphdr);
4453
4454 skb->nh.iph->check = 0;
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07004455 skb->nh.iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
Michael Chanb6016b72005-05-26 13:03:09 -07004456 skb->h.th->check =
4457 ~csum_tcpudp_magic(skb->nh.iph->saddr,
4458 skb->nh.iph->daddr,
4459 0, IPPROTO_TCP, 0);
4460
4461 if (tcp_opt_len || (skb->nh.iph->ihl > 5)) {
4462 vlan_tag_flags |= ((skb->nh.iph->ihl - 5) +
4463 (tcp_opt_len >> 2)) << 8;
4464 }
4465 }
4466 else
4467#endif
4468 {
4469 mss = 0;
4470 }
4471
4472 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
4473
4474 tx_buf = &bp->tx_buf_ring[ring_prod];
4475 tx_buf->skb = skb;
4476 pci_unmap_addr_set(tx_buf, mapping, mapping);
4477
4478 txbd = &bp->tx_desc_ring[ring_prod];
4479
4480 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
4481 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
4482 txbd->tx_bd_mss_nbytes = len | (mss << 16);
4483 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
4484
4485 last_frag = skb_shinfo(skb)->nr_frags;
4486
4487 for (i = 0; i < last_frag; i++) {
4488 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
4489
4490 prod = NEXT_TX_BD(prod);
4491 ring_prod = TX_RING_IDX(prod);
4492 txbd = &bp->tx_desc_ring[ring_prod];
4493
4494 len = frag->size;
4495 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
4496 len, PCI_DMA_TODEVICE);
4497 pci_unmap_addr_set(&bp->tx_buf_ring[ring_prod],
4498 mapping, mapping);
4499
4500 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
4501 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
4502 txbd->tx_bd_mss_nbytes = len | (mss << 16);
4503 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
4504
4505 }
4506 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
4507
4508 prod = NEXT_TX_BD(prod);
4509 bp->tx_prod_bseq += skb->len;
4510
Michael Chanb6016b72005-05-26 13:03:09 -07004511 REG_WR16(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BIDX, prod);
4512 REG_WR(bp, MB_TX_CID_ADDR + BNX2_L2CTX_TX_HOST_BSEQ, bp->tx_prod_bseq);
4513
4514 mmiowb();
4515
4516 bp->tx_prod = prod;
4517 dev->trans_start = jiffies;
4518
Michael Chane89bbf12005-08-25 15:36:58 -07004519 if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) {
Michael Chane89bbf12005-08-25 15:36:58 -07004520 netif_stop_queue(dev);
Michael Chan2f8af122006-08-15 01:39:10 -07004521 if (bnx2_tx_avail(bp) > bp->tx_wake_thresh)
Michael Chane89bbf12005-08-25 15:36:58 -07004522 netif_wake_queue(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004523 }
4524
4525 return NETDEV_TX_OK;
4526}
4527
4528/* Called with rtnl_lock */
4529static int
4530bnx2_close(struct net_device *dev)
4531{
Michael Chan972ec0d2006-01-23 16:12:43 -08004532 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004533 u32 reset_code;
4534
Michael Chanafdc08b2005-08-25 15:34:29 -07004535 /* Calling flush_scheduled_work() may deadlock because
4536 * linkwatch_event() may be on the workqueue and it will try to get
4537 * the rtnl_lock which we are holding.
4538 */
4539 while (bp->in_reset_task)
4540 msleep(1);
4541
Michael Chanb6016b72005-05-26 13:03:09 -07004542 bnx2_netif_stop(bp);
4543 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08004544 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07004545 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08004546 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07004547 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
4548 else
4549 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
4550 bnx2_reset_chip(bp, reset_code);
4551 free_irq(bp->pdev->irq, dev);
4552 if (bp->flags & USING_MSI_FLAG) {
4553 pci_disable_msi(bp->pdev);
4554 bp->flags &= ~USING_MSI_FLAG;
4555 }
4556 bnx2_free_skbs(bp);
4557 bnx2_free_mem(bp);
4558 bp->link_up = 0;
4559 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07004560 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07004561 return 0;
4562}
4563
4564#define GET_NET_STATS64(ctr) \
4565 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
4566 (unsigned long) (ctr##_lo)
4567
4568#define GET_NET_STATS32(ctr) \
4569 (ctr##_lo)
4570
4571#if (BITS_PER_LONG == 64)
4572#define GET_NET_STATS GET_NET_STATS64
4573#else
4574#define GET_NET_STATS GET_NET_STATS32
4575#endif
4576
4577static struct net_device_stats *
4578bnx2_get_stats(struct net_device *dev)
4579{
Michael Chan972ec0d2006-01-23 16:12:43 -08004580 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004581 struct statistics_block *stats_blk = bp->stats_blk;
4582 struct net_device_stats *net_stats = &bp->net_stats;
4583
4584 if (bp->stats_blk == NULL) {
4585 return net_stats;
4586 }
4587 net_stats->rx_packets =
4588 GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
4589 GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
4590 GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
4591
4592 net_stats->tx_packets =
4593 GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
4594 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
4595 GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
4596
4597 net_stats->rx_bytes =
4598 GET_NET_STATS(stats_blk->stat_IfHCInOctets);
4599
4600 net_stats->tx_bytes =
4601 GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
4602
4603 net_stats->multicast =
4604 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
4605
4606 net_stats->collisions =
4607 (unsigned long) stats_blk->stat_EtherStatsCollisions;
4608
4609 net_stats->rx_length_errors =
4610 (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
4611 stats_blk->stat_EtherStatsOverrsizePkts);
4612
4613 net_stats->rx_over_errors =
4614 (unsigned long) stats_blk->stat_IfInMBUFDiscards;
4615
4616 net_stats->rx_frame_errors =
4617 (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
4618
4619 net_stats->rx_crc_errors =
4620 (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
4621
4622 net_stats->rx_errors = net_stats->rx_length_errors +
4623 net_stats->rx_over_errors + net_stats->rx_frame_errors +
4624 net_stats->rx_crc_errors;
4625
4626 net_stats->tx_aborted_errors =
4627 (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
4628 stats_blk->stat_Dot3StatsLateCollisions);
4629
Michael Chan5b0c76a2005-11-04 08:45:49 -08004630 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
4631 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07004632 net_stats->tx_carrier_errors = 0;
4633 else {
4634 net_stats->tx_carrier_errors =
4635 (unsigned long)
4636 stats_blk->stat_Dot3StatsCarrierSenseErrors;
4637 }
4638
4639 net_stats->tx_errors =
4640 (unsigned long)
4641 stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
4642 +
4643 net_stats->tx_aborted_errors +
4644 net_stats->tx_carrier_errors;
4645
Michael Chancea94db2006-06-12 22:16:13 -07004646 net_stats->rx_missed_errors =
4647 (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
4648 stats_blk->stat_FwRxDrop);
4649
Michael Chanb6016b72005-05-26 13:03:09 -07004650 return net_stats;
4651}
4652
4653/* All ethtool functions called with rtnl_lock */
4654
4655static int
4656bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
4657{
Michael Chan972ec0d2006-01-23 16:12:43 -08004658 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004659
4660 cmd->supported = SUPPORTED_Autoneg;
4661 if (bp->phy_flags & PHY_SERDES_FLAG) {
4662 cmd->supported |= SUPPORTED_1000baseT_Full |
4663 SUPPORTED_FIBRE;
4664
4665 cmd->port = PORT_FIBRE;
4666 }
4667 else {
4668 cmd->supported |= SUPPORTED_10baseT_Half |
4669 SUPPORTED_10baseT_Full |
4670 SUPPORTED_100baseT_Half |
4671 SUPPORTED_100baseT_Full |
4672 SUPPORTED_1000baseT_Full |
4673 SUPPORTED_TP;
4674
4675 cmd->port = PORT_TP;
4676 }
4677
4678 cmd->advertising = bp->advertising;
4679
4680 if (bp->autoneg & AUTONEG_SPEED) {
4681 cmd->autoneg = AUTONEG_ENABLE;
4682 }
4683 else {
4684 cmd->autoneg = AUTONEG_DISABLE;
4685 }
4686
4687 if (netif_carrier_ok(dev)) {
4688 cmd->speed = bp->line_speed;
4689 cmd->duplex = bp->duplex;
4690 }
4691 else {
4692 cmd->speed = -1;
4693 cmd->duplex = -1;
4694 }
4695
4696 cmd->transceiver = XCVR_INTERNAL;
4697 cmd->phy_address = bp->phy_addr;
4698
4699 return 0;
4700}
4701
4702static int
4703bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
4704{
Michael Chan972ec0d2006-01-23 16:12:43 -08004705 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004706 u8 autoneg = bp->autoneg;
4707 u8 req_duplex = bp->req_duplex;
4708 u16 req_line_speed = bp->req_line_speed;
4709 u32 advertising = bp->advertising;
4710
4711 if (cmd->autoneg == AUTONEG_ENABLE) {
4712 autoneg |= AUTONEG_SPEED;
4713
4714 cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
4715
4716 /* allow advertising 1 speed */
4717 if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
4718 (cmd->advertising == ADVERTISED_10baseT_Full) ||
4719 (cmd->advertising == ADVERTISED_100baseT_Half) ||
4720 (cmd->advertising == ADVERTISED_100baseT_Full)) {
4721
4722 if (bp->phy_flags & PHY_SERDES_FLAG)
4723 return -EINVAL;
4724
4725 advertising = cmd->advertising;
4726
4727 }
4728 else if (cmd->advertising == ADVERTISED_1000baseT_Full) {
4729 advertising = cmd->advertising;
4730 }
4731 else if (cmd->advertising == ADVERTISED_1000baseT_Half) {
4732 return -EINVAL;
4733 }
4734 else {
4735 if (bp->phy_flags & PHY_SERDES_FLAG) {
4736 advertising = ETHTOOL_ALL_FIBRE_SPEED;
4737 }
4738 else {
4739 advertising = ETHTOOL_ALL_COPPER_SPEED;
4740 }
4741 }
4742 advertising |= ADVERTISED_Autoneg;
4743 }
4744 else {
4745 if (bp->phy_flags & PHY_SERDES_FLAG) {
4746 if ((cmd->speed != SPEED_1000) ||
4747 (cmd->duplex != DUPLEX_FULL)) {
4748 return -EINVAL;
4749 }
4750 }
4751 else if (cmd->speed == SPEED_1000) {
4752 return -EINVAL;
4753 }
4754 autoneg &= ~AUTONEG_SPEED;
4755 req_line_speed = cmd->speed;
4756 req_duplex = cmd->duplex;
4757 advertising = 0;
4758 }
4759
4760 bp->autoneg = autoneg;
4761 bp->advertising = advertising;
4762 bp->req_line_speed = req_line_speed;
4763 bp->req_duplex = req_duplex;
4764
Michael Chanc770a652005-08-25 15:38:39 -07004765 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004766
4767 bnx2_setup_phy(bp);
4768
Michael Chanc770a652005-08-25 15:38:39 -07004769 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004770
4771 return 0;
4772}
4773
4774static void
4775bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
4776{
Michael Chan972ec0d2006-01-23 16:12:43 -08004777 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004778
4779 strcpy(info->driver, DRV_MODULE_NAME);
4780 strcpy(info->version, DRV_MODULE_VERSION);
4781 strcpy(info->bus_info, pci_name(bp->pdev));
4782 info->fw_version[0] = ((bp->fw_ver & 0xff000000) >> 24) + '0';
4783 info->fw_version[2] = ((bp->fw_ver & 0xff0000) >> 16) + '0';
4784 info->fw_version[4] = ((bp->fw_ver & 0xff00) >> 8) + '0';
Michael Chan206cc832006-01-23 16:14:05 -08004785 info->fw_version[1] = info->fw_version[3] = '.';
4786 info->fw_version[5] = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004787}
4788
Michael Chan244ac4f2006-03-20 17:48:46 -08004789#define BNX2_REGDUMP_LEN (32 * 1024)
4790
4791static int
4792bnx2_get_regs_len(struct net_device *dev)
4793{
4794 return BNX2_REGDUMP_LEN;
4795}
4796
4797static void
4798bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
4799{
4800 u32 *p = _p, i, offset;
4801 u8 *orig_p = _p;
4802 struct bnx2 *bp = netdev_priv(dev);
4803 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
4804 0x0800, 0x0880, 0x0c00, 0x0c10,
4805 0x0c30, 0x0d08, 0x1000, 0x101c,
4806 0x1040, 0x1048, 0x1080, 0x10a4,
4807 0x1400, 0x1490, 0x1498, 0x14f0,
4808 0x1500, 0x155c, 0x1580, 0x15dc,
4809 0x1600, 0x1658, 0x1680, 0x16d8,
4810 0x1800, 0x1820, 0x1840, 0x1854,
4811 0x1880, 0x1894, 0x1900, 0x1984,
4812 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
4813 0x1c80, 0x1c94, 0x1d00, 0x1d84,
4814 0x2000, 0x2030, 0x23c0, 0x2400,
4815 0x2800, 0x2820, 0x2830, 0x2850,
4816 0x2b40, 0x2c10, 0x2fc0, 0x3058,
4817 0x3c00, 0x3c94, 0x4000, 0x4010,
4818 0x4080, 0x4090, 0x43c0, 0x4458,
4819 0x4c00, 0x4c18, 0x4c40, 0x4c54,
4820 0x4fc0, 0x5010, 0x53c0, 0x5444,
4821 0x5c00, 0x5c18, 0x5c80, 0x5c90,
4822 0x5fc0, 0x6000, 0x6400, 0x6428,
4823 0x6800, 0x6848, 0x684c, 0x6860,
4824 0x6888, 0x6910, 0x8000 };
4825
4826 regs->version = 0;
4827
4828 memset(p, 0, BNX2_REGDUMP_LEN);
4829
4830 if (!netif_running(bp->dev))
4831 return;
4832
4833 i = 0;
4834 offset = reg_boundaries[0];
4835 p += offset;
4836 while (offset < BNX2_REGDUMP_LEN) {
4837 *p++ = REG_RD(bp, offset);
4838 offset += 4;
4839 if (offset == reg_boundaries[i + 1]) {
4840 offset = reg_boundaries[i + 2];
4841 p = (u32 *) (orig_p + offset);
4842 i += 2;
4843 }
4844 }
4845}
4846
Michael Chanb6016b72005-05-26 13:03:09 -07004847static void
4848bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
4849{
Michael Chan972ec0d2006-01-23 16:12:43 -08004850 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004851
4852 if (bp->flags & NO_WOL_FLAG) {
4853 wol->supported = 0;
4854 wol->wolopts = 0;
4855 }
4856 else {
4857 wol->supported = WAKE_MAGIC;
4858 if (bp->wol)
4859 wol->wolopts = WAKE_MAGIC;
4860 else
4861 wol->wolopts = 0;
4862 }
4863 memset(&wol->sopass, 0, sizeof(wol->sopass));
4864}
4865
4866static int
4867bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
4868{
Michael Chan972ec0d2006-01-23 16:12:43 -08004869 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004870
4871 if (wol->wolopts & ~WAKE_MAGIC)
4872 return -EINVAL;
4873
4874 if (wol->wolopts & WAKE_MAGIC) {
4875 if (bp->flags & NO_WOL_FLAG)
4876 return -EINVAL;
4877
4878 bp->wol = 1;
4879 }
4880 else {
4881 bp->wol = 0;
4882 }
4883 return 0;
4884}
4885
4886static int
4887bnx2_nway_reset(struct net_device *dev)
4888{
Michael Chan972ec0d2006-01-23 16:12:43 -08004889 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004890 u32 bmcr;
4891
4892 if (!(bp->autoneg & AUTONEG_SPEED)) {
4893 return -EINVAL;
4894 }
4895
Michael Chanc770a652005-08-25 15:38:39 -07004896 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004897
4898 /* Force a link down visible on the other side */
4899 if (bp->phy_flags & PHY_SERDES_FLAG) {
4900 bnx2_write_phy(bp, MII_BMCR, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07004901 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004902
4903 msleep(20);
4904
Michael Chanc770a652005-08-25 15:38:39 -07004905 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004906 if (CHIP_NUM(bp) == CHIP_NUM_5706) {
Michael Chancd339a02005-08-25 15:35:24 -07004907 bp->current_interval = SERDES_AN_TIMEOUT;
4908 bp->serdes_an_pending = 1;
4909 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07004910 }
4911 }
4912
4913 bnx2_read_phy(bp, MII_BMCR, &bmcr);
4914 bmcr &= ~BMCR_LOOPBACK;
4915 bnx2_write_phy(bp, MII_BMCR, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
4916
Michael Chanc770a652005-08-25 15:38:39 -07004917 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004918
4919 return 0;
4920}
4921
4922static int
4923bnx2_get_eeprom_len(struct net_device *dev)
4924{
Michael Chan972ec0d2006-01-23 16:12:43 -08004925 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004926
Michael Chan1122db72006-01-23 16:11:42 -08004927 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004928 return 0;
4929
Michael Chan1122db72006-01-23 16:11:42 -08004930 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07004931}
4932
4933static int
4934bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
4935 u8 *eebuf)
4936{
Michael Chan972ec0d2006-01-23 16:12:43 -08004937 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004938 int rc;
4939
John W. Linville1064e942005-11-10 12:58:24 -08004940 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07004941
4942 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
4943
4944 return rc;
4945}
4946
4947static int
4948bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
4949 u8 *eebuf)
4950{
Michael Chan972ec0d2006-01-23 16:12:43 -08004951 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004952 int rc;
4953
John W. Linville1064e942005-11-10 12:58:24 -08004954 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07004955
4956 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
4957
4958 return rc;
4959}
4960
4961static int
4962bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
4963{
Michael Chan972ec0d2006-01-23 16:12:43 -08004964 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004965
4966 memset(coal, 0, sizeof(struct ethtool_coalesce));
4967
4968 coal->rx_coalesce_usecs = bp->rx_ticks;
4969 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
4970 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
4971 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
4972
4973 coal->tx_coalesce_usecs = bp->tx_ticks;
4974 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
4975 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
4976 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
4977
4978 coal->stats_block_coalesce_usecs = bp->stats_ticks;
4979
4980 return 0;
4981}
4982
4983static int
4984bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
4985{
Michael Chan972ec0d2006-01-23 16:12:43 -08004986 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07004987
4988 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
4989 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
4990
4991 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
4992 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
4993
4994 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
4995 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
4996
4997 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
4998 if (bp->rx_quick_cons_trip_int > 0xff)
4999 bp->rx_quick_cons_trip_int = 0xff;
5000
5001 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
5002 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
5003
5004 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
5005 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
5006
5007 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
5008 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
5009
5010 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
5011 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
5012 0xff;
5013
5014 bp->stats_ticks = coal->stats_block_coalesce_usecs;
5015 if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
5016 bp->stats_ticks &= 0xffff00;
5017
5018 if (netif_running(bp->dev)) {
5019 bnx2_netif_stop(bp);
5020 bnx2_init_nic(bp);
5021 bnx2_netif_start(bp);
5022 }
5023
5024 return 0;
5025}
5026
5027static void
5028bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
5029{
Michael Chan972ec0d2006-01-23 16:12:43 -08005030 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005031
Michael Chan13daffa2006-03-20 17:49:20 -08005032 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07005033 ering->rx_mini_max_pending = 0;
5034 ering->rx_jumbo_max_pending = 0;
5035
5036 ering->rx_pending = bp->rx_ring_size;
5037 ering->rx_mini_pending = 0;
5038 ering->rx_jumbo_pending = 0;
5039
5040 ering->tx_max_pending = MAX_TX_DESC_CNT;
5041 ering->tx_pending = bp->tx_ring_size;
5042}
5043
5044static int
5045bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
5046{
Michael Chan972ec0d2006-01-23 16:12:43 -08005047 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005048
Michael Chan13daffa2006-03-20 17:49:20 -08005049 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
Michael Chanb6016b72005-05-26 13:03:09 -07005050 (ering->tx_pending > MAX_TX_DESC_CNT) ||
5051 (ering->tx_pending <= MAX_SKB_FRAGS)) {
5052
5053 return -EINVAL;
5054 }
Michael Chan13daffa2006-03-20 17:49:20 -08005055 if (netif_running(bp->dev)) {
5056 bnx2_netif_stop(bp);
5057 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
5058 bnx2_free_skbs(bp);
5059 bnx2_free_mem(bp);
5060 }
5061
5062 bnx2_set_rx_ring_size(bp, ering->rx_pending);
Michael Chanb6016b72005-05-26 13:03:09 -07005063 bp->tx_ring_size = ering->tx_pending;
5064
5065 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08005066 int rc;
5067
5068 rc = bnx2_alloc_mem(bp);
5069 if (rc)
5070 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005071 bnx2_init_nic(bp);
5072 bnx2_netif_start(bp);
5073 }
5074
5075 return 0;
5076}
5077
5078static void
5079bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
5080{
Michael Chan972ec0d2006-01-23 16:12:43 -08005081 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005082
5083 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
5084 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
5085 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
5086}
5087
5088static int
5089bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
5090{
Michael Chan972ec0d2006-01-23 16:12:43 -08005091 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005092
5093 bp->req_flow_ctrl = 0;
5094 if (epause->rx_pause)
5095 bp->req_flow_ctrl |= FLOW_CTRL_RX;
5096 if (epause->tx_pause)
5097 bp->req_flow_ctrl |= FLOW_CTRL_TX;
5098
5099 if (epause->autoneg) {
5100 bp->autoneg |= AUTONEG_FLOW_CTRL;
5101 }
5102 else {
5103 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
5104 }
5105
Michael Chanc770a652005-08-25 15:38:39 -07005106 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005107
5108 bnx2_setup_phy(bp);
5109
Michael Chanc770a652005-08-25 15:38:39 -07005110 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005111
5112 return 0;
5113}
5114
5115static u32
5116bnx2_get_rx_csum(struct net_device *dev)
5117{
Michael Chan972ec0d2006-01-23 16:12:43 -08005118 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005119
5120 return bp->rx_csum;
5121}
5122
5123static int
5124bnx2_set_rx_csum(struct net_device *dev, u32 data)
5125{
Michael Chan972ec0d2006-01-23 16:12:43 -08005126 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005127
5128 bp->rx_csum = data;
5129 return 0;
5130}
5131
Michael Chanb11d6212006-06-29 12:31:21 -07005132static int
5133bnx2_set_tso(struct net_device *dev, u32 data)
5134{
5135 if (data)
5136 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
5137 else
5138 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO_ECN);
5139 return 0;
5140}
5141
Michael Chancea94db2006-06-12 22:16:13 -07005142#define BNX2_NUM_STATS 46
Michael Chanb6016b72005-05-26 13:03:09 -07005143
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005144static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005145 char string[ETH_GSTRING_LEN];
5146} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
5147 { "rx_bytes" },
5148 { "rx_error_bytes" },
5149 { "tx_bytes" },
5150 { "tx_error_bytes" },
5151 { "rx_ucast_packets" },
5152 { "rx_mcast_packets" },
5153 { "rx_bcast_packets" },
5154 { "tx_ucast_packets" },
5155 { "tx_mcast_packets" },
5156 { "tx_bcast_packets" },
5157 { "tx_mac_errors" },
5158 { "tx_carrier_errors" },
5159 { "rx_crc_errors" },
5160 { "rx_align_errors" },
5161 { "tx_single_collisions" },
5162 { "tx_multi_collisions" },
5163 { "tx_deferred" },
5164 { "tx_excess_collisions" },
5165 { "tx_late_collisions" },
5166 { "tx_total_collisions" },
5167 { "rx_fragments" },
5168 { "rx_jabbers" },
5169 { "rx_undersize_packets" },
5170 { "rx_oversize_packets" },
5171 { "rx_64_byte_packets" },
5172 { "rx_65_to_127_byte_packets" },
5173 { "rx_128_to_255_byte_packets" },
5174 { "rx_256_to_511_byte_packets" },
5175 { "rx_512_to_1023_byte_packets" },
5176 { "rx_1024_to_1522_byte_packets" },
5177 { "rx_1523_to_9022_byte_packets" },
5178 { "tx_64_byte_packets" },
5179 { "tx_65_to_127_byte_packets" },
5180 { "tx_128_to_255_byte_packets" },
5181 { "tx_256_to_511_byte_packets" },
5182 { "tx_512_to_1023_byte_packets" },
5183 { "tx_1024_to_1522_byte_packets" },
5184 { "tx_1523_to_9022_byte_packets" },
5185 { "rx_xon_frames" },
5186 { "rx_xoff_frames" },
5187 { "tx_xon_frames" },
5188 { "tx_xoff_frames" },
5189 { "rx_mac_ctrl_frames" },
5190 { "rx_filtered_packets" },
5191 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07005192 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07005193};
5194
5195#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
5196
Arjan van de Venf71e1302006-03-03 21:33:57 -05005197static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005198 STATS_OFFSET32(stat_IfHCInOctets_hi),
5199 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
5200 STATS_OFFSET32(stat_IfHCOutOctets_hi),
5201 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
5202 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
5203 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
5204 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
5205 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
5206 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
5207 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
5208 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
5209 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
5210 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
5211 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
5212 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
5213 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
5214 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
5215 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
5216 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
5217 STATS_OFFSET32(stat_EtherStatsCollisions),
5218 STATS_OFFSET32(stat_EtherStatsFragments),
5219 STATS_OFFSET32(stat_EtherStatsJabbers),
5220 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
5221 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
5222 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
5223 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
5224 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
5225 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
5226 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
5227 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
5228 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
5229 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
5230 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
5231 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
5232 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
5233 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
5234 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
5235 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
5236 STATS_OFFSET32(stat_XonPauseFramesReceived),
5237 STATS_OFFSET32(stat_XoffPauseFramesReceived),
5238 STATS_OFFSET32(stat_OutXonSent),
5239 STATS_OFFSET32(stat_OutXoffSent),
5240 STATS_OFFSET32(stat_MacControlFramesReceived),
5241 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
5242 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07005243 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07005244};
5245
5246/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
5247 * skipped because of errata.
5248 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005249static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005250 8,0,8,8,8,8,8,8,8,8,
5251 4,0,4,4,4,4,4,4,4,4,
5252 4,4,4,4,4,4,4,4,4,4,
5253 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07005254 4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07005255};
5256
Michael Chan5b0c76a2005-11-04 08:45:49 -08005257static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
5258 8,0,8,8,8,8,8,8,8,8,
5259 4,4,4,4,4,4,4,4,4,4,
5260 4,4,4,4,4,4,4,4,4,4,
5261 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07005262 4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08005263};
5264
Michael Chanb6016b72005-05-26 13:03:09 -07005265#define BNX2_NUM_TESTS 6
5266
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005267static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005268 char string[ETH_GSTRING_LEN];
5269} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
5270 { "register_test (offline)" },
5271 { "memory_test (offline)" },
5272 { "loopback_test (offline)" },
5273 { "nvram_test (online)" },
5274 { "interrupt_test (online)" },
5275 { "link_test (online)" },
5276};
5277
5278static int
5279bnx2_self_test_count(struct net_device *dev)
5280{
5281 return BNX2_NUM_TESTS;
5282}
5283
5284static void
5285bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
5286{
Michael Chan972ec0d2006-01-23 16:12:43 -08005287 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005288
5289 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
5290 if (etest->flags & ETH_TEST_FL_OFFLINE) {
5291 bnx2_netif_stop(bp);
5292 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
5293 bnx2_free_skbs(bp);
5294
5295 if (bnx2_test_registers(bp) != 0) {
5296 buf[0] = 1;
5297 etest->flags |= ETH_TEST_FL_FAILED;
5298 }
5299 if (bnx2_test_memory(bp) != 0) {
5300 buf[1] = 1;
5301 etest->flags |= ETH_TEST_FL_FAILED;
5302 }
Michael Chanbc5a0692006-01-23 16:13:22 -08005303 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07005304 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07005305
5306 if (!netif_running(bp->dev)) {
5307 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
5308 }
5309 else {
5310 bnx2_init_nic(bp);
5311 bnx2_netif_start(bp);
5312 }
5313
5314 /* wait for link up */
5315 msleep_interruptible(3000);
5316 if ((!bp->link_up) && !(bp->phy_flags & PHY_SERDES_FLAG))
5317 msleep_interruptible(4000);
5318 }
5319
5320 if (bnx2_test_nvram(bp) != 0) {
5321 buf[3] = 1;
5322 etest->flags |= ETH_TEST_FL_FAILED;
5323 }
5324 if (bnx2_test_intr(bp) != 0) {
5325 buf[4] = 1;
5326 etest->flags |= ETH_TEST_FL_FAILED;
5327 }
5328
5329 if (bnx2_test_link(bp) != 0) {
5330 buf[5] = 1;
5331 etest->flags |= ETH_TEST_FL_FAILED;
5332
5333 }
5334}
5335
5336static void
5337bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
5338{
5339 switch (stringset) {
5340 case ETH_SS_STATS:
5341 memcpy(buf, bnx2_stats_str_arr,
5342 sizeof(bnx2_stats_str_arr));
5343 break;
5344 case ETH_SS_TEST:
5345 memcpy(buf, bnx2_tests_str_arr,
5346 sizeof(bnx2_tests_str_arr));
5347 break;
5348 }
5349}
5350
5351static int
5352bnx2_get_stats_count(struct net_device *dev)
5353{
5354 return BNX2_NUM_STATS;
5355}
5356
5357static void
5358bnx2_get_ethtool_stats(struct net_device *dev,
5359 struct ethtool_stats *stats, u64 *buf)
5360{
Michael Chan972ec0d2006-01-23 16:12:43 -08005361 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005362 int i;
5363 u32 *hw_stats = (u32 *) bp->stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005364 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005365
5366 if (hw_stats == NULL) {
5367 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
5368 return;
5369 }
5370
Michael Chan5b0c76a2005-11-04 08:45:49 -08005371 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
5372 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
5373 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
5374 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07005375 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08005376 else
5377 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07005378
5379 for (i = 0; i < BNX2_NUM_STATS; i++) {
5380 if (stats_len_arr[i] == 0) {
5381 /* skip this counter */
5382 buf[i] = 0;
5383 continue;
5384 }
5385 if (stats_len_arr[i] == 4) {
5386 /* 4-byte counter */
5387 buf[i] = (u64)
5388 *(hw_stats + bnx2_stats_offset_arr[i]);
5389 continue;
5390 }
5391 /* 8-byte counter */
5392 buf[i] = (((u64) *(hw_stats +
5393 bnx2_stats_offset_arr[i])) << 32) +
5394 *(hw_stats + bnx2_stats_offset_arr[i] + 1);
5395 }
5396}
5397
5398static int
5399bnx2_phys_id(struct net_device *dev, u32 data)
5400{
Michael Chan972ec0d2006-01-23 16:12:43 -08005401 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005402 int i;
5403 u32 save;
5404
5405 if (data == 0)
5406 data = 2;
5407
5408 save = REG_RD(bp, BNX2_MISC_CFG);
5409 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
5410
5411 for (i = 0; i < (data * 2); i++) {
5412 if ((i % 2) == 0) {
5413 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
5414 }
5415 else {
5416 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
5417 BNX2_EMAC_LED_1000MB_OVERRIDE |
5418 BNX2_EMAC_LED_100MB_OVERRIDE |
5419 BNX2_EMAC_LED_10MB_OVERRIDE |
5420 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
5421 BNX2_EMAC_LED_TRAFFIC);
5422 }
5423 msleep_interruptible(500);
5424 if (signal_pending(current))
5425 break;
5426 }
5427 REG_WR(bp, BNX2_EMAC_LED, 0);
5428 REG_WR(bp, BNX2_MISC_CFG, save);
5429 return 0;
5430}
5431
5432static struct ethtool_ops bnx2_ethtool_ops = {
5433 .get_settings = bnx2_get_settings,
5434 .set_settings = bnx2_set_settings,
5435 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08005436 .get_regs_len = bnx2_get_regs_len,
5437 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07005438 .get_wol = bnx2_get_wol,
5439 .set_wol = bnx2_set_wol,
5440 .nway_reset = bnx2_nway_reset,
5441 .get_link = ethtool_op_get_link,
5442 .get_eeprom_len = bnx2_get_eeprom_len,
5443 .get_eeprom = bnx2_get_eeprom,
5444 .set_eeprom = bnx2_set_eeprom,
5445 .get_coalesce = bnx2_get_coalesce,
5446 .set_coalesce = bnx2_set_coalesce,
5447 .get_ringparam = bnx2_get_ringparam,
5448 .set_ringparam = bnx2_set_ringparam,
5449 .get_pauseparam = bnx2_get_pauseparam,
5450 .set_pauseparam = bnx2_set_pauseparam,
5451 .get_rx_csum = bnx2_get_rx_csum,
5452 .set_rx_csum = bnx2_set_rx_csum,
5453 .get_tx_csum = ethtool_op_get_tx_csum,
5454 .set_tx_csum = ethtool_op_set_tx_csum,
5455 .get_sg = ethtool_op_get_sg,
5456 .set_sg = ethtool_op_set_sg,
5457#ifdef BCM_TSO
5458 .get_tso = ethtool_op_get_tso,
Michael Chanb11d6212006-06-29 12:31:21 -07005459 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07005460#endif
5461 .self_test_count = bnx2_self_test_count,
5462 .self_test = bnx2_self_test,
5463 .get_strings = bnx2_get_strings,
5464 .phys_id = bnx2_phys_id,
5465 .get_stats_count = bnx2_get_stats_count,
5466 .get_ethtool_stats = bnx2_get_ethtool_stats,
John W. Linville24b8e052005-09-12 14:45:08 -07005467 .get_perm_addr = ethtool_op_get_perm_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07005468};
5469
5470/* Called with rtnl_lock */
5471static int
5472bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
5473{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005474 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08005475 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005476 int err;
5477
5478 switch(cmd) {
5479 case SIOCGMIIPHY:
5480 data->phy_id = bp->phy_addr;
5481
5482 /* fallthru */
5483 case SIOCGMIIREG: {
5484 u32 mii_regval;
5485
Michael Chanc770a652005-08-25 15:38:39 -07005486 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005487 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07005488 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005489
5490 data->val_out = mii_regval;
5491
5492 return err;
5493 }
5494
5495 case SIOCSMIIREG:
5496 if (!capable(CAP_NET_ADMIN))
5497 return -EPERM;
5498
Michael Chanc770a652005-08-25 15:38:39 -07005499 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005500 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07005501 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005502
5503 return err;
5504
5505 default:
5506 /* do nothing */
5507 break;
5508 }
5509 return -EOPNOTSUPP;
5510}
5511
5512/* Called with rtnl_lock */
5513static int
5514bnx2_change_mac_addr(struct net_device *dev, void *p)
5515{
5516 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08005517 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005518
Michael Chan73eef4c2005-08-25 15:39:15 -07005519 if (!is_valid_ether_addr(addr->sa_data))
5520 return -EINVAL;
5521
Michael Chanb6016b72005-05-26 13:03:09 -07005522 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
5523 if (netif_running(dev))
5524 bnx2_set_mac_addr(bp);
5525
5526 return 0;
5527}
5528
5529/* Called with rtnl_lock */
5530static int
5531bnx2_change_mtu(struct net_device *dev, int new_mtu)
5532{
Michael Chan972ec0d2006-01-23 16:12:43 -08005533 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005534
5535 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
5536 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
5537 return -EINVAL;
5538
5539 dev->mtu = new_mtu;
5540 if (netif_running(dev)) {
5541 bnx2_netif_stop(bp);
5542
5543 bnx2_init_nic(bp);
5544
5545 bnx2_netif_start(bp);
5546 }
5547 return 0;
5548}
5549
5550#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
5551static void
5552poll_bnx2(struct net_device *dev)
5553{
Michael Chan972ec0d2006-01-23 16:12:43 -08005554 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005555
5556 disable_irq(bp->pdev->irq);
5557 bnx2_interrupt(bp->pdev->irq, dev, NULL);
5558 enable_irq(bp->pdev->irq);
5559}
5560#endif
5561
5562static int __devinit
5563bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
5564{
5565 struct bnx2 *bp;
5566 unsigned long mem_len;
5567 int rc;
5568 u32 reg;
5569
5570 SET_MODULE_OWNER(dev);
5571 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08005572 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005573
5574 bp->flags = 0;
5575 bp->phy_flags = 0;
5576
5577 /* enable device (incl. PCI PM wakeup), and bus-mastering */
5578 rc = pci_enable_device(pdev);
5579 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005580 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
Michael Chanb6016b72005-05-26 13:03:09 -07005581 goto err_out;
5582 }
5583
5584 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005585 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04005586 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005587 rc = -ENODEV;
5588 goto err_out_disable;
5589 }
5590
5591 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
5592 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005593 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005594 goto err_out_disable;
5595 }
5596
5597 pci_set_master(pdev);
5598
5599 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
5600 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005601 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04005602 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005603 rc = -EIO;
5604 goto err_out_release;
5605 }
5606
5607 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
5608 if (bp->pcix_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005609 dev_err(&pdev->dev, "Cannot find PCIX capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005610 rc = -EIO;
5611 goto err_out_release;
5612 }
5613
5614 if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) {
5615 bp->flags |= USING_DAC_FLAG;
5616 if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005617 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04005618 "pci_set_consistent_dma_mask failed, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005619 rc = -EIO;
5620 goto err_out_release;
5621 }
5622 }
5623 else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005624 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005625 rc = -EIO;
5626 goto err_out_release;
5627 }
5628
5629 bp->dev = dev;
5630 bp->pdev = pdev;
5631
5632 spin_lock_init(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005633 INIT_WORK(&bp->reset_task, bnx2_reset_task, bp);
5634
5635 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
5636 mem_len = MB_GET_CID_ADDR(17);
5637 dev->mem_end = dev->mem_start + mem_len;
5638 dev->irq = pdev->irq;
5639
5640 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
5641
5642 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005643 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005644 rc = -ENOMEM;
5645 goto err_out_release;
5646 }
5647
5648 /* Configure byte swap and enable write to the reg_window registers.
5649 * Rely on CPU to do target byte swapping on big endian systems
5650 * The chip's target access swapping will not swap all accesses
5651 */
5652 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
5653 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
5654 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
5655
Pavel Machek829ca9a2005-09-03 15:56:56 -07005656 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07005657
5658 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
5659
Michael Chanb6016b72005-05-26 13:03:09 -07005660 /* Get bus information. */
5661 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
5662 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
5663 u32 clkreg;
5664
5665 bp->flags |= PCIX_FLAG;
5666
5667 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
5668
5669 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
5670 switch (clkreg) {
5671 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
5672 bp->bus_speed_mhz = 133;
5673 break;
5674
5675 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
5676 bp->bus_speed_mhz = 100;
5677 break;
5678
5679 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
5680 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
5681 bp->bus_speed_mhz = 66;
5682 break;
5683
5684 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
5685 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
5686 bp->bus_speed_mhz = 50;
5687 break;
5688
5689 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
5690 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
5691 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
5692 bp->bus_speed_mhz = 33;
5693 break;
5694 }
5695 }
5696 else {
5697 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
5698 bp->bus_speed_mhz = 66;
5699 else
5700 bp->bus_speed_mhz = 33;
5701 }
5702
5703 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
5704 bp->flags |= PCI_32BIT_FLAG;
5705
5706 /* 5706A0 may falsely detect SERR and PERR. */
5707 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
5708 reg = REG_RD(bp, PCI_COMMAND);
5709 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
5710 REG_WR(bp, PCI_COMMAND, reg);
5711 }
5712 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
5713 !(bp->flags & PCIX_FLAG)) {
5714
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005715 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04005716 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005717 goto err_out_unmap;
5718 }
5719
5720 bnx2_init_nvram(bp);
5721
Michael Chane3648b32005-11-04 08:51:21 -08005722 reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
5723
5724 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
5725 BNX2_SHM_HDR_SIGNATURE_SIG)
5726 bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0);
5727 else
5728 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
5729
Michael Chanb6016b72005-05-26 13:03:09 -07005730 /* Get the permanent MAC address. First we need to make sure the
5731 * firmware is actually running.
5732 */
Michael Chane3648b32005-11-04 08:51:21 -08005733 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07005734
5735 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
5736 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005737 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005738 rc = -ENODEV;
5739 goto err_out_unmap;
5740 }
5741
Michael Chane3648b32005-11-04 08:51:21 -08005742 bp->fw_ver = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
Michael Chanb6016b72005-05-26 13:03:09 -07005743
Michael Chane3648b32005-11-04 08:51:21 -08005744 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07005745 bp->mac_addr[0] = (u8) (reg >> 8);
5746 bp->mac_addr[1] = (u8) reg;
5747
Michael Chane3648b32005-11-04 08:51:21 -08005748 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07005749 bp->mac_addr[2] = (u8) (reg >> 24);
5750 bp->mac_addr[3] = (u8) (reg >> 16);
5751 bp->mac_addr[4] = (u8) (reg >> 8);
5752 bp->mac_addr[5] = (u8) reg;
5753
5754 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07005755 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07005756
5757 bp->rx_csum = 1;
5758
5759 bp->rx_offset = sizeof(struct l2_fhdr) + 2;
5760
5761 bp->tx_quick_cons_trip_int = 20;
5762 bp->tx_quick_cons_trip = 20;
5763 bp->tx_ticks_int = 80;
5764 bp->tx_ticks = 80;
5765
5766 bp->rx_quick_cons_trip_int = 6;
5767 bp->rx_quick_cons_trip = 6;
5768 bp->rx_ticks_int = 18;
5769 bp->rx_ticks = 18;
5770
5771 bp->stats_ticks = 1000000 & 0xffff00;
5772
5773 bp->timer_interval = HZ;
Michael Chancd339a02005-08-25 15:35:24 -07005774 bp->current_interval = HZ;
Michael Chanb6016b72005-05-26 13:03:09 -07005775
Michael Chan5b0c76a2005-11-04 08:45:49 -08005776 bp->phy_addr = 1;
5777
Michael Chanb6016b72005-05-26 13:03:09 -07005778 /* Disable WOL support if we are running on a SERDES chip. */
5779 if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT) {
5780 bp->phy_flags |= PHY_SERDES_FLAG;
5781 bp->flags |= NO_WOL_FLAG;
Michael Chan5b0c76a2005-11-04 08:45:49 -08005782 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
5783 bp->phy_addr = 2;
Michael Chane3648b32005-11-04 08:51:21 -08005784 reg = REG_RD_IND(bp, bp->shmem_base +
Michael Chan5b0c76a2005-11-04 08:45:49 -08005785 BNX2_SHARED_HW_CFG_CONFIG);
5786 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
5787 bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
5788 }
Michael Chanb6016b72005-05-26 13:03:09 -07005789 }
5790
Michael Chan16088272006-06-12 22:16:43 -07005791 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
5792 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
5793 (CHIP_ID(bp) == CHIP_ID_5708_B1))
Michael Chandda1e392006-01-23 16:08:14 -08005794 bp->flags |= NO_WOL_FLAG;
5795
Michael Chanb6016b72005-05-26 13:03:09 -07005796 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
5797 bp->tx_quick_cons_trip_int =
5798 bp->tx_quick_cons_trip;
5799 bp->tx_ticks_int = bp->tx_ticks;
5800 bp->rx_quick_cons_trip_int =
5801 bp->rx_quick_cons_trip;
5802 bp->rx_ticks_int = bp->rx_ticks;
5803 bp->comp_prod_trip_int = bp->comp_prod_trip;
5804 bp->com_ticks_int = bp->com_ticks;
5805 bp->cmd_ticks_int = bp->cmd_ticks;
5806 }
5807
5808 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
5809 bp->req_line_speed = 0;
5810 if (bp->phy_flags & PHY_SERDES_FLAG) {
5811 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
Michael Chancd339a02005-08-25 15:35:24 -07005812
Michael Chane3648b32005-11-04 08:51:21 -08005813 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
Michael Chancd339a02005-08-25 15:35:24 -07005814 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
5815 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
5816 bp->autoneg = 0;
5817 bp->req_line_speed = bp->line_speed = SPEED_1000;
5818 bp->req_duplex = DUPLEX_FULL;
5819 }
Michael Chanb6016b72005-05-26 13:03:09 -07005820 }
5821 else {
5822 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
5823 }
5824
5825 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
5826
Michael Chancd339a02005-08-25 15:35:24 -07005827 init_timer(&bp->timer);
5828 bp->timer.expires = RUN_AT(bp->timer_interval);
5829 bp->timer.data = (unsigned long) bp;
5830 bp->timer.function = bnx2_timer;
5831
Michael Chanb6016b72005-05-26 13:03:09 -07005832 return 0;
5833
5834err_out_unmap:
5835 if (bp->regview) {
5836 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07005837 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07005838 }
5839
5840err_out_release:
5841 pci_release_regions(pdev);
5842
5843err_out_disable:
5844 pci_disable_device(pdev);
5845 pci_set_drvdata(pdev, NULL);
5846
5847err_out:
5848 return rc;
5849}
5850
5851static int __devinit
5852bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
5853{
5854 static int version_printed = 0;
5855 struct net_device *dev = NULL;
5856 struct bnx2 *bp;
5857 int rc, i;
5858
5859 if (version_printed++ == 0)
5860 printk(KERN_INFO "%s", version);
5861
5862 /* dev zeroed in init_etherdev */
5863 dev = alloc_etherdev(sizeof(*bp));
5864
5865 if (!dev)
5866 return -ENOMEM;
5867
5868 rc = bnx2_init_board(pdev, dev);
5869 if (rc < 0) {
5870 free_netdev(dev);
5871 return rc;
5872 }
5873
5874 dev->open = bnx2_open;
5875 dev->hard_start_xmit = bnx2_start_xmit;
5876 dev->stop = bnx2_close;
5877 dev->get_stats = bnx2_get_stats;
5878 dev->set_multicast_list = bnx2_set_rx_mode;
5879 dev->do_ioctl = bnx2_ioctl;
5880 dev->set_mac_address = bnx2_change_mac_addr;
5881 dev->change_mtu = bnx2_change_mtu;
5882 dev->tx_timeout = bnx2_tx_timeout;
5883 dev->watchdog_timeo = TX_TIMEOUT;
5884#ifdef BCM_VLAN
5885 dev->vlan_rx_register = bnx2_vlan_rx_register;
5886 dev->vlan_rx_kill_vid = bnx2_vlan_rx_kill_vid;
5887#endif
5888 dev->poll = bnx2_poll;
5889 dev->ethtool_ops = &bnx2_ethtool_ops;
5890 dev->weight = 64;
5891
Michael Chan972ec0d2006-01-23 16:12:43 -08005892 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005893
5894#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
5895 dev->poll_controller = poll_bnx2;
5896#endif
5897
5898 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04005899 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chanb6016b72005-05-26 13:03:09 -07005900 if (bp->regview)
5901 iounmap(bp->regview);
5902 pci_release_regions(pdev);
5903 pci_disable_device(pdev);
5904 pci_set_drvdata(pdev, NULL);
5905 free_netdev(dev);
5906 return rc;
5907 }
5908
5909 pci_set_drvdata(pdev, dev);
5910
5911 memcpy(dev->dev_addr, bp->mac_addr, 6);
John W. Linville24b8e052005-09-12 14:45:08 -07005912 memcpy(dev->perm_addr, bp->mac_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07005913 bp->name = board_info[ent->driver_data].name,
5914 printk(KERN_INFO "%s: %s (%c%d) PCI%s %s %dMHz found at mem %lx, "
5915 "IRQ %d, ",
5916 dev->name,
5917 bp->name,
5918 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
5919 ((CHIP_ID(bp) & 0x0ff0) >> 4),
5920 ((bp->flags & PCIX_FLAG) ? "-X" : ""),
5921 ((bp->flags & PCI_32BIT_FLAG) ? "32-bit" : "64-bit"),
5922 bp->bus_speed_mhz,
5923 dev->base_addr,
5924 bp->pdev->irq);
5925
5926 printk("node addr ");
5927 for (i = 0; i < 6; i++)
5928 printk("%2.2x", dev->dev_addr[i]);
5929 printk("\n");
5930
5931 dev->features |= NETIF_F_SG;
5932 if (bp->flags & USING_DAC_FLAG)
5933 dev->features |= NETIF_F_HIGHDMA;
5934 dev->features |= NETIF_F_IP_CSUM;
5935#ifdef BCM_VLAN
5936 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
5937#endif
5938#ifdef BCM_TSO
Michael Chanb11d6212006-06-29 12:31:21 -07005939 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chanb6016b72005-05-26 13:03:09 -07005940#endif
5941
5942 netif_carrier_off(bp->dev);
5943
5944 return 0;
5945}
5946
5947static void __devexit
5948bnx2_remove_one(struct pci_dev *pdev)
5949{
5950 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08005951 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005952
Michael Chanafdc08b2005-08-25 15:34:29 -07005953 flush_scheduled_work();
5954
Michael Chanb6016b72005-05-26 13:03:09 -07005955 unregister_netdev(dev);
5956
5957 if (bp->regview)
5958 iounmap(bp->regview);
5959
5960 free_netdev(dev);
5961 pci_release_regions(pdev);
5962 pci_disable_device(pdev);
5963 pci_set_drvdata(pdev, NULL);
5964}
5965
5966static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07005967bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07005968{
5969 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08005970 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005971 u32 reset_code;
5972
5973 if (!netif_running(dev))
5974 return 0;
5975
Michael Chan1d60290f2006-03-20 17:50:08 -08005976 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07005977 bnx2_netif_stop(bp);
5978 netif_device_detach(dev);
5979 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08005980 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07005981 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08005982 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07005983 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5984 else
5985 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5986 bnx2_reset_chip(bp, reset_code);
5987 bnx2_free_skbs(bp);
Pavel Machek829ca9a2005-09-03 15:56:56 -07005988 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07005989 return 0;
5990}
5991
5992static int
5993bnx2_resume(struct pci_dev *pdev)
5994{
5995 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08005996 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005997
5998 if (!netif_running(dev))
5999 return 0;
6000
Pavel Machek829ca9a2005-09-03 15:56:56 -07006001 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006002 netif_device_attach(dev);
6003 bnx2_init_nic(bp);
6004 bnx2_netif_start(bp);
6005 return 0;
6006}
6007
6008static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006009 .name = DRV_MODULE_NAME,
6010 .id_table = bnx2_pci_tbl,
6011 .probe = bnx2_init_one,
6012 .remove = __devexit_p(bnx2_remove_one),
6013 .suspend = bnx2_suspend,
6014 .resume = bnx2_resume,
Michael Chanb6016b72005-05-26 13:03:09 -07006015};
6016
6017static int __init bnx2_init(void)
6018{
6019 return pci_module_init(&bnx2_pci_driver);
6020}
6021
6022static void __exit bnx2_cleanup(void)
6023{
6024 pci_unregister_driver(&bnx2_pci_driver);
6025}
6026
6027module_init(bnx2_init);
6028module_exit(bnx2_cleanup);
6029
6030
6031