blob: 311c8595c64b8d61fa1fd7cbbd97c7f1b2e08ef3 [file] [log] [blame]
Michael Chanb6016b72005-05-26 13:03:09 -07001/* bnx2.c: Broadcom NX2 network driver.
2 *
Michael Chan72fbaeb2007-05-03 13:25:32 -07003 * Copyright (c) 2004-2007 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
Michael Chanf2a4f052006-03-23 01:13:12 -080042#include <net/ip.h>
Linus Torvaldsde081fa2007-07-12 16:40:08 -070043#include <net/tcp.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080044#include <net/checksum.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080045#include <linux/workqueue.h>
46#include <linux/crc32.h>
47#include <linux/prefetch.h>
Michael Chan29b12172006-03-23 01:13:43 -080048#include <linux/cache.h>
Michael Chanfba9fe92006-06-12 22:21:25 -070049#include <linux/zlib.h>
Michael Chanf2a4f052006-03-23 01:13:12 -080050
Michael Chanb6016b72005-05-26 13:03:09 -070051#include "bnx2.h"
52#include "bnx2_fw.h"
Michael Chand43584c2006-11-19 14:14:35 -080053#include "bnx2_fw2.h"
Michael Chanb6016b72005-05-26 13:03:09 -070054
55#define DRV_MODULE_NAME "bnx2"
56#define PFX DRV_MODULE_NAME ": "
Michael Chan3a334b32007-07-07 22:52:37 -070057#define DRV_MODULE_VERSION "1.6.2"
58#define DRV_MODULE_RELDATE "July 6, 2007"
Michael Chanb6016b72005-05-26 13:03:09 -070059
60#define RUN_AT(x) (jiffies + (x))
61
62/* Time in jiffies before concluding the transmitter is hung. */
63#define TX_TIMEOUT (5*HZ)
64
Randy Dunlape19360f2006-04-10 23:22:06 -070065static const char version[] __devinitdata =
Michael Chanb6016b72005-05-26 13:03:09 -070066 "Broadcom NetXtreme II Gigabit Ethernet Driver " DRV_MODULE_NAME " v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
67
68MODULE_AUTHOR("Michael Chan <mchan@broadcom.com>");
Michael Chan05d0f1c2005-11-04 08:53:48 -080069MODULE_DESCRIPTION("Broadcom NetXtreme II BCM5706/5708 Driver");
Michael Chanb6016b72005-05-26 13:03:09 -070070MODULE_LICENSE("GPL");
71MODULE_VERSION(DRV_MODULE_VERSION);
72
73static int disable_msi = 0;
74
75module_param(disable_msi, int, 0);
76MODULE_PARM_DESC(disable_msi, "Disable Message Signaled Interrupt (MSI)");
77
78typedef enum {
79 BCM5706 = 0,
80 NC370T,
81 NC370I,
82 BCM5706S,
83 NC370F,
Michael Chan5b0c76a2005-11-04 08:45:49 -080084 BCM5708,
85 BCM5708S,
Michael Chanbac0dff2006-11-19 14:15:05 -080086 BCM5709,
Michael Chan27a005b2007-05-03 13:23:41 -070087 BCM5709S,
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 Chanbac0dff2006-11-19 14:15:05 -0800101 { "Broadcom NetXtreme II BCM5709 1000Base-T" },
Michael Chan27a005b2007-05-03 13:23:41 -0700102 { "Broadcom NetXtreme II BCM5709 1000Base-SX" },
Michael Chanb6016b72005-05-26 13:03:09 -0700103 };
104
105static struct pci_device_id bnx2_pci_tbl[] = {
106 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
107 PCI_VENDOR_ID_HP, 0x3101, 0, 0, NC370T },
108 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
109 PCI_VENDOR_ID_HP, 0x3106, 0, 0, NC370I },
110 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706,
111 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706 },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800112 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708,
113 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708 },
Michael Chanb6016b72005-05-26 13:03:09 -0700114 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
115 PCI_VENDOR_ID_HP, 0x3102, 0, 0, NC370F },
116 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5706S,
117 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5706S },
Michael Chan5b0c76a2005-11-04 08:45:49 -0800118 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5708S,
119 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5708S },
Michael Chanbac0dff2006-11-19 14:15:05 -0800120 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709,
121 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709 },
Michael Chan27a005b2007-05-03 13:23:41 -0700122 { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_NX2_5709S,
123 PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S },
Michael Chanb6016b72005-05-26 13:03:09 -0700124 { 0, }
125};
126
127static struct flash_spec flash_table[] =
128{
Michael Chane30372c2007-07-16 18:26:23 -0700129#define BUFFERED_FLAGS (BNX2_NV_BUFFERED | BNX2_NV_TRANSLATE)
130#define NONBUFFERED_FLAGS (BNX2_NV_WREN)
Michael Chanb6016b72005-05-26 13:03:09 -0700131 /* Slow EEPROM */
Michael Chan37137702005-11-04 08:49:17 -0800132 {0x00000000, 0x40830380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700133 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700134 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
135 "EEPROM - slow"},
Michael Chan37137702005-11-04 08:49:17 -0800136 /* Expansion entry 0001 */
137 {0x08000002, 0x4b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700138 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800139 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
140 "Entry 0001"},
Michael Chanb6016b72005-05-26 13:03:09 -0700141 /* Saifun SA25F010 (non-buffered flash) */
142 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800143 {0x04000001, 0x47808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700144 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700145 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*2,
146 "Non-buffered flash (128kB)"},
147 /* Saifun SA25F020 (non-buffered flash) */
148 /* strap, cfg1, & write1 need updates */
Michael Chan37137702005-11-04 08:49:17 -0800149 {0x0c000003, 0x4f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700150 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chanb6016b72005-05-26 13:03:09 -0700151 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE*4,
152 "Non-buffered flash (256kB)"},
Michael Chan37137702005-11-04 08:49:17 -0800153 /* Expansion entry 0100 */
154 {0x11000000, 0x53808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700155 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800156 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
157 "Entry 0100"},
158 /* Entry 0101: ST M45PE10 (non-buffered flash, TetonII B0) */
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400159 {0x19000002, 0x5b808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700160 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800161 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*2,
162 "Entry 0101: ST M45PE10 (128kB non-bufferred)"},
163 /* Entry 0110: ST M45PE20 (non-buffered flash)*/
164 {0x15000001, 0x57808201, 0x000500db, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700165 NONBUFFERED_FLAGS, ST_MICRO_FLASH_PAGE_BITS, ST_MICRO_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800166 ST_MICRO_FLASH_BYTE_ADDR_MASK, ST_MICRO_FLASH_BASE_TOTAL_SIZE*4,
167 "Entry 0110: ST M45PE20 (256kB non-bufferred)"},
168 /* Saifun SA25F005 (non-buffered flash) */
169 /* strap, cfg1, & write1 need updates */
170 {0x1d000003, 0x5f808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700171 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800172 SAIFUN_FLASH_BYTE_ADDR_MASK, SAIFUN_FLASH_BASE_TOTAL_SIZE,
173 "Non-buffered flash (64kB)"},
174 /* Fast EEPROM */
175 {0x22000000, 0x62808380, 0x009f0081, 0xa184a053, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700176 BUFFERED_FLAGS, SEEPROM_PAGE_BITS, SEEPROM_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800177 SEEPROM_BYTE_ADDR_MASK, SEEPROM_TOTAL_SIZE,
178 "EEPROM - fast"},
179 /* Expansion entry 1001 */
180 {0x2a000002, 0x6b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700181 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800182 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
183 "Entry 1001"},
184 /* Expansion entry 1010 */
185 {0x26000001, 0x67808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700186 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800187 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
188 "Entry 1010"},
189 /* ATMEL AT45DB011B (buffered flash) */
190 {0x2e000003, 0x6e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700191 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800192 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE,
193 "Buffered flash (128kB)"},
194 /* Expansion entry 1100 */
195 {0x33000000, 0x73808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700196 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800197 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
198 "Entry 1100"},
199 /* Expansion entry 1101 */
200 {0x3b000002, 0x7b808201, 0x00050081, 0x03840253, 0xaf020406,
Michael Chane30372c2007-07-16 18:26:23 -0700201 NONBUFFERED_FLAGS, SAIFUN_FLASH_PAGE_BITS, SAIFUN_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800202 SAIFUN_FLASH_BYTE_ADDR_MASK, 0,
203 "Entry 1101"},
204 /* Ateml Expansion entry 1110 */
205 {0x37000001, 0x76808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700206 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800207 BUFFERED_FLASH_BYTE_ADDR_MASK, 0,
208 "Entry 1110 (Atmel)"},
209 /* ATMEL AT45DB021B (buffered flash) */
210 {0x3f000003, 0x7e808273, 0x00570081, 0x68848353, 0xaf000400,
Michael Chane30372c2007-07-16 18:26:23 -0700211 BUFFERED_FLAGS, BUFFERED_FLASH_PAGE_BITS, BUFFERED_FLASH_PAGE_SIZE,
Michael Chan37137702005-11-04 08:49:17 -0800212 BUFFERED_FLASH_BYTE_ADDR_MASK, BUFFERED_FLASH_TOTAL_SIZE*2,
213 "Buffered flash (256kB)"},
Michael Chanb6016b72005-05-26 13:03:09 -0700214};
215
Michael Chane30372c2007-07-16 18:26:23 -0700216static struct flash_spec flash_5709 = {
217 .flags = BNX2_NV_BUFFERED,
218 .page_bits = BCM5709_FLASH_PAGE_BITS,
219 .page_size = BCM5709_FLASH_PAGE_SIZE,
220 .addr_mask = BCM5709_FLASH_BYTE_ADDR_MASK,
221 .total_size = BUFFERED_FLASH_TOTAL_SIZE*2,
222 .name = "5709 Buffered flash (256kB)",
223};
224
Michael Chanb6016b72005-05-26 13:03:09 -0700225MODULE_DEVICE_TABLE(pci, bnx2_pci_tbl);
226
Michael Chane89bbf12005-08-25 15:36:58 -0700227static inline u32 bnx2_tx_avail(struct bnx2 *bp)
228{
Michael Chan2f8af122006-08-15 01:39:10 -0700229 u32 diff;
Michael Chane89bbf12005-08-25 15:36:58 -0700230
Michael Chan2f8af122006-08-15 01:39:10 -0700231 smp_mb();
Michael Chanfaac9c42006-12-14 15:56:32 -0800232
233 /* The ring uses 256 indices for 255 entries, one of them
234 * needs to be skipped.
235 */
236 diff = bp->tx_prod - bp->tx_cons;
237 if (unlikely(diff >= TX_DESC_CNT)) {
238 diff &= 0xffff;
239 if (diff == TX_DESC_CNT)
240 diff = MAX_TX_DESC_CNT;
241 }
Michael Chane89bbf12005-08-25 15:36:58 -0700242 return (bp->tx_ring_size - diff);
243}
244
Michael Chanb6016b72005-05-26 13:03:09 -0700245static u32
246bnx2_reg_rd_ind(struct bnx2 *bp, u32 offset)
247{
Michael Chan1b8227c2007-05-03 13:24:05 -0700248 u32 val;
249
250 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700251 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
Michael Chan1b8227c2007-05-03 13:24:05 -0700252 val = REG_RD(bp, BNX2_PCICFG_REG_WINDOW);
253 spin_unlock_bh(&bp->indirect_lock);
254 return val;
Michael Chanb6016b72005-05-26 13:03:09 -0700255}
256
257static void
258bnx2_reg_wr_ind(struct bnx2 *bp, u32 offset, u32 val)
259{
Michael Chan1b8227c2007-05-03 13:24:05 -0700260 spin_lock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700261 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, offset);
262 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, val);
Michael Chan1b8227c2007-05-03 13:24:05 -0700263 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700264}
265
266static void
267bnx2_ctx_wr(struct bnx2 *bp, u32 cid_addr, u32 offset, u32 val)
268{
269 offset += cid_addr;
Michael Chan1b8227c2007-05-03 13:24:05 -0700270 spin_lock_bh(&bp->indirect_lock);
Michael Chan59b47d82006-11-19 14:10:45 -0800271 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
272 int i;
273
274 REG_WR(bp, BNX2_CTX_CTX_DATA, val);
275 REG_WR(bp, BNX2_CTX_CTX_CTRL,
276 offset | BNX2_CTX_CTX_CTRL_WRITE_REQ);
277 for (i = 0; i < 5; i++) {
278 u32 val;
279 val = REG_RD(bp, BNX2_CTX_CTX_CTRL);
280 if ((val & BNX2_CTX_CTX_CTRL_WRITE_REQ) == 0)
281 break;
282 udelay(5);
283 }
284 } else {
285 REG_WR(bp, BNX2_CTX_DATA_ADR, offset);
286 REG_WR(bp, BNX2_CTX_DATA, val);
287 }
Michael Chan1b8227c2007-05-03 13:24:05 -0700288 spin_unlock_bh(&bp->indirect_lock);
Michael Chanb6016b72005-05-26 13:03:09 -0700289}
290
291static int
292bnx2_read_phy(struct bnx2 *bp, u32 reg, u32 *val)
293{
294 u32 val1;
295 int i, ret;
296
297 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
298 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
299 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
300
301 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
302 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
303
304 udelay(40);
305 }
306
307 val1 = (bp->phy_addr << 21) | (reg << 16) |
308 BNX2_EMAC_MDIO_COMM_COMMAND_READ | BNX2_EMAC_MDIO_COMM_DISEXT |
309 BNX2_EMAC_MDIO_COMM_START_BUSY;
310 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
311
312 for (i = 0; i < 50; i++) {
313 udelay(10);
314
315 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
316 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
317 udelay(5);
318
319 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
320 val1 &= BNX2_EMAC_MDIO_COMM_DATA;
321
322 break;
323 }
324 }
325
326 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY) {
327 *val = 0x0;
328 ret = -EBUSY;
329 }
330 else {
331 *val = val1;
332 ret = 0;
333 }
334
335 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
336 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
337 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
338
339 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
340 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
341
342 udelay(40);
343 }
344
345 return ret;
346}
347
348static int
349bnx2_write_phy(struct bnx2 *bp, u32 reg, u32 val)
350{
351 u32 val1;
352 int i, ret;
353
354 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
355 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
356 val1 &= ~BNX2_EMAC_MDIO_MODE_AUTO_POLL;
357
358 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
359 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
360
361 udelay(40);
362 }
363
364 val1 = (bp->phy_addr << 21) | (reg << 16) | val |
365 BNX2_EMAC_MDIO_COMM_COMMAND_WRITE |
366 BNX2_EMAC_MDIO_COMM_START_BUSY | BNX2_EMAC_MDIO_COMM_DISEXT;
367 REG_WR(bp, BNX2_EMAC_MDIO_COMM, val1);
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400368
Michael Chanb6016b72005-05-26 13:03:09 -0700369 for (i = 0; i < 50; i++) {
370 udelay(10);
371
372 val1 = REG_RD(bp, BNX2_EMAC_MDIO_COMM);
373 if (!(val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)) {
374 udelay(5);
375 break;
376 }
377 }
378
379 if (val1 & BNX2_EMAC_MDIO_COMM_START_BUSY)
380 ret = -EBUSY;
381 else
382 ret = 0;
383
384 if (bp->phy_flags & PHY_INT_MODE_AUTO_POLLING_FLAG) {
385 val1 = REG_RD(bp, BNX2_EMAC_MDIO_MODE);
386 val1 |= BNX2_EMAC_MDIO_MODE_AUTO_POLL;
387
388 REG_WR(bp, BNX2_EMAC_MDIO_MODE, val1);
389 REG_RD(bp, BNX2_EMAC_MDIO_MODE);
390
391 udelay(40);
392 }
393
394 return ret;
395}
396
397static void
398bnx2_disable_int(struct bnx2 *bp)
399{
400 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
401 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
402 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
403}
404
405static void
406bnx2_enable_int(struct bnx2 *bp)
407{
Michael Chanb6016b72005-05-26 13:03:09 -0700408 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chan1269a8a2006-01-23 16:11:03 -0800409 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
410 BNX2_PCICFG_INT_ACK_CMD_MASK_INT | bp->last_status_idx);
411
412 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chanb6016b72005-05-26 13:03:09 -0700413 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bp->last_status_idx);
414
Michael Chanbf5295b2006-03-23 01:11:56 -0800415 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -0700416}
417
418static void
419bnx2_disable_int_sync(struct bnx2 *bp)
420{
421 atomic_inc(&bp->intr_sem);
422 bnx2_disable_int(bp);
423 synchronize_irq(bp->pdev->irq);
424}
425
426static void
427bnx2_netif_stop(struct bnx2 *bp)
428{
429 bnx2_disable_int_sync(bp);
430 if (netif_running(bp->dev)) {
431 netif_poll_disable(bp->dev);
432 netif_tx_disable(bp->dev);
433 bp->dev->trans_start = jiffies; /* prevent tx timeout */
434 }
435}
436
437static void
438bnx2_netif_start(struct bnx2 *bp)
439{
440 if (atomic_dec_and_test(&bp->intr_sem)) {
441 if (netif_running(bp->dev)) {
442 netif_wake_queue(bp->dev);
443 netif_poll_enable(bp->dev);
444 bnx2_enable_int(bp);
445 }
446 }
447}
448
449static void
450bnx2_free_mem(struct bnx2 *bp)
451{
Michael Chan13daffa2006-03-20 17:49:20 -0800452 int i;
453
Michael Chan59b47d82006-11-19 14:10:45 -0800454 for (i = 0; i < bp->ctx_pages; i++) {
455 if (bp->ctx_blk[i]) {
456 pci_free_consistent(bp->pdev, BCM_PAGE_SIZE,
457 bp->ctx_blk[i],
458 bp->ctx_blk_mapping[i]);
459 bp->ctx_blk[i] = NULL;
460 }
461 }
Michael Chanb6016b72005-05-26 13:03:09 -0700462 if (bp->status_blk) {
Michael Chan0f31f992006-03-23 01:12:38 -0800463 pci_free_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700464 bp->status_blk, bp->status_blk_mapping);
465 bp->status_blk = NULL;
Michael Chan0f31f992006-03-23 01:12:38 -0800466 bp->stats_blk = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700467 }
468 if (bp->tx_desc_ring) {
469 pci_free_consistent(bp->pdev,
470 sizeof(struct tx_bd) * TX_DESC_CNT,
471 bp->tx_desc_ring, bp->tx_desc_mapping);
472 bp->tx_desc_ring = NULL;
473 }
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400474 kfree(bp->tx_buf_ring);
475 bp->tx_buf_ring = NULL;
Michael Chan13daffa2006-03-20 17:49:20 -0800476 for (i = 0; i < bp->rx_max_ring; i++) {
477 if (bp->rx_desc_ring[i])
478 pci_free_consistent(bp->pdev,
479 sizeof(struct rx_bd) * RX_DESC_CNT,
480 bp->rx_desc_ring[i],
481 bp->rx_desc_mapping[i]);
482 bp->rx_desc_ring[i] = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700483 }
Michael Chan13daffa2006-03-20 17:49:20 -0800484 vfree(bp->rx_buf_ring);
Jesper Juhlb4558ea2005-10-28 16:53:13 -0400485 bp->rx_buf_ring = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -0700486}
487
488static int
489bnx2_alloc_mem(struct bnx2 *bp)
490{
Michael Chan0f31f992006-03-23 01:12:38 -0800491 int i, status_blk_size;
Michael Chan13daffa2006-03-20 17:49:20 -0800492
Michael Chan0f31f992006-03-23 01:12:38 -0800493 bp->tx_buf_ring = kzalloc(sizeof(struct sw_bd) * TX_DESC_CNT,
494 GFP_KERNEL);
Michael Chanb6016b72005-05-26 13:03:09 -0700495 if (bp->tx_buf_ring == NULL)
496 return -ENOMEM;
497
Michael Chanb6016b72005-05-26 13:03:09 -0700498 bp->tx_desc_ring = pci_alloc_consistent(bp->pdev,
499 sizeof(struct tx_bd) *
500 TX_DESC_CNT,
501 &bp->tx_desc_mapping);
502 if (bp->tx_desc_ring == NULL)
503 goto alloc_mem_err;
504
Michael Chan13daffa2006-03-20 17:49:20 -0800505 bp->rx_buf_ring = vmalloc(sizeof(struct sw_bd) * RX_DESC_CNT *
506 bp->rx_max_ring);
Michael Chanb6016b72005-05-26 13:03:09 -0700507 if (bp->rx_buf_ring == NULL)
508 goto alloc_mem_err;
509
Michael Chan13daffa2006-03-20 17:49:20 -0800510 memset(bp->rx_buf_ring, 0, sizeof(struct sw_bd) * RX_DESC_CNT *
511 bp->rx_max_ring);
512
513 for (i = 0; i < bp->rx_max_ring; i++) {
514 bp->rx_desc_ring[i] =
515 pci_alloc_consistent(bp->pdev,
516 sizeof(struct rx_bd) * RX_DESC_CNT,
517 &bp->rx_desc_mapping[i]);
518 if (bp->rx_desc_ring[i] == NULL)
519 goto alloc_mem_err;
520
521 }
Michael Chanb6016b72005-05-26 13:03:09 -0700522
Michael Chan0f31f992006-03-23 01:12:38 -0800523 /* Combine status and statistics blocks into one allocation. */
524 status_blk_size = L1_CACHE_ALIGN(sizeof(struct status_block));
525 bp->status_stats_size = status_blk_size +
526 sizeof(struct statistics_block);
527
528 bp->status_blk = pci_alloc_consistent(bp->pdev, bp->status_stats_size,
Michael Chanb6016b72005-05-26 13:03:09 -0700529 &bp->status_blk_mapping);
530 if (bp->status_blk == NULL)
531 goto alloc_mem_err;
532
Michael Chan0f31f992006-03-23 01:12:38 -0800533 memset(bp->status_blk, 0, bp->status_stats_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700534
Michael Chan0f31f992006-03-23 01:12:38 -0800535 bp->stats_blk = (void *) ((unsigned long) bp->status_blk +
536 status_blk_size);
Michael Chanb6016b72005-05-26 13:03:09 -0700537
Michael Chan0f31f992006-03-23 01:12:38 -0800538 bp->stats_blk_mapping = bp->status_blk_mapping + status_blk_size;
Michael Chanb6016b72005-05-26 13:03:09 -0700539
Michael Chan59b47d82006-11-19 14:10:45 -0800540 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
541 bp->ctx_pages = 0x2000 / BCM_PAGE_SIZE;
542 if (bp->ctx_pages == 0)
543 bp->ctx_pages = 1;
544 for (i = 0; i < bp->ctx_pages; i++) {
545 bp->ctx_blk[i] = pci_alloc_consistent(bp->pdev,
546 BCM_PAGE_SIZE,
547 &bp->ctx_blk_mapping[i]);
548 if (bp->ctx_blk[i] == NULL)
549 goto alloc_mem_err;
550 }
551 }
Michael Chanb6016b72005-05-26 13:03:09 -0700552 return 0;
553
554alloc_mem_err:
555 bnx2_free_mem(bp);
556 return -ENOMEM;
557}
558
559static void
Michael Chane3648b32005-11-04 08:51:21 -0800560bnx2_report_fw_link(struct bnx2 *bp)
561{
562 u32 fw_link_status = 0;
563
Michael Chan0d8a6572007-07-07 22:49:43 -0700564 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
565 return;
566
Michael Chane3648b32005-11-04 08:51:21 -0800567 if (bp->link_up) {
568 u32 bmsr;
569
570 switch (bp->line_speed) {
571 case SPEED_10:
572 if (bp->duplex == DUPLEX_HALF)
573 fw_link_status = BNX2_LINK_STATUS_10HALF;
574 else
575 fw_link_status = BNX2_LINK_STATUS_10FULL;
576 break;
577 case SPEED_100:
578 if (bp->duplex == DUPLEX_HALF)
579 fw_link_status = BNX2_LINK_STATUS_100HALF;
580 else
581 fw_link_status = BNX2_LINK_STATUS_100FULL;
582 break;
583 case SPEED_1000:
584 if (bp->duplex == DUPLEX_HALF)
585 fw_link_status = BNX2_LINK_STATUS_1000HALF;
586 else
587 fw_link_status = BNX2_LINK_STATUS_1000FULL;
588 break;
589 case SPEED_2500:
590 if (bp->duplex == DUPLEX_HALF)
591 fw_link_status = BNX2_LINK_STATUS_2500HALF;
592 else
593 fw_link_status = BNX2_LINK_STATUS_2500FULL;
594 break;
595 }
596
597 fw_link_status |= BNX2_LINK_STATUS_LINK_UP;
598
599 if (bp->autoneg) {
600 fw_link_status |= BNX2_LINK_STATUS_AN_ENABLED;
601
Michael Chanca58c3a2007-05-03 13:22:52 -0700602 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
603 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chane3648b32005-11-04 08:51:21 -0800604
605 if (!(bmsr & BMSR_ANEGCOMPLETE) ||
606 bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)
607 fw_link_status |= BNX2_LINK_STATUS_PARALLEL_DET;
608 else
609 fw_link_status |= BNX2_LINK_STATUS_AN_COMPLETE;
610 }
611 }
612 else
613 fw_link_status = BNX2_LINK_STATUS_LINK_DOWN;
614
615 REG_WR_IND(bp, bp->shmem_base + BNX2_LINK_STATUS, fw_link_status);
616}
617
Michael Chan9b1084b2007-07-07 22:50:37 -0700618static char *
619bnx2_xceiver_str(struct bnx2 *bp)
620{
621 return ((bp->phy_port == PORT_FIBRE) ? "SerDes" :
622 ((bp->phy_flags & PHY_SERDES_FLAG) ? "Remote Copper" :
623 "Copper"));
624}
625
Michael Chane3648b32005-11-04 08:51:21 -0800626static void
Michael Chanb6016b72005-05-26 13:03:09 -0700627bnx2_report_link(struct bnx2 *bp)
628{
629 if (bp->link_up) {
630 netif_carrier_on(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700631 printk(KERN_INFO PFX "%s NIC %s Link is Up, ", bp->dev->name,
632 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700633
634 printk("%d Mbps ", bp->line_speed);
635
636 if (bp->duplex == DUPLEX_FULL)
637 printk("full duplex");
638 else
639 printk("half duplex");
640
641 if (bp->flow_ctrl) {
642 if (bp->flow_ctrl & FLOW_CTRL_RX) {
643 printk(", receive ");
644 if (bp->flow_ctrl & FLOW_CTRL_TX)
645 printk("& transmit ");
646 }
647 else {
648 printk(", transmit ");
649 }
650 printk("flow control ON");
651 }
652 printk("\n");
653 }
654 else {
655 netif_carrier_off(bp->dev);
Michael Chan9b1084b2007-07-07 22:50:37 -0700656 printk(KERN_ERR PFX "%s NIC %s Link is Down\n", bp->dev->name,
657 bnx2_xceiver_str(bp));
Michael Chanb6016b72005-05-26 13:03:09 -0700658 }
Michael Chane3648b32005-11-04 08:51:21 -0800659
660 bnx2_report_fw_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -0700661}
662
663static void
664bnx2_resolve_flow_ctrl(struct bnx2 *bp)
665{
666 u32 local_adv, remote_adv;
667
668 bp->flow_ctrl = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -0400669 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
Michael Chanb6016b72005-05-26 13:03:09 -0700670 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
671
672 if (bp->duplex == DUPLEX_FULL) {
673 bp->flow_ctrl = bp->req_flow_ctrl;
674 }
675 return;
676 }
677
678 if (bp->duplex != DUPLEX_FULL) {
679 return;
680 }
681
Michael Chan5b0c76a2005-11-04 08:45:49 -0800682 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
683 (CHIP_NUM(bp) == CHIP_NUM_5708)) {
684 u32 val;
685
686 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
687 if (val & BCM5708S_1000X_STAT1_TX_PAUSE)
688 bp->flow_ctrl |= FLOW_CTRL_TX;
689 if (val & BCM5708S_1000X_STAT1_RX_PAUSE)
690 bp->flow_ctrl |= FLOW_CTRL_RX;
691 return;
692 }
693
Michael Chanca58c3a2007-05-03 13:22:52 -0700694 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
695 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700696
697 if (bp->phy_flags & PHY_SERDES_FLAG) {
698 u32 new_local_adv = 0;
699 u32 new_remote_adv = 0;
700
701 if (local_adv & ADVERTISE_1000XPAUSE)
702 new_local_adv |= ADVERTISE_PAUSE_CAP;
703 if (local_adv & ADVERTISE_1000XPSE_ASYM)
704 new_local_adv |= ADVERTISE_PAUSE_ASYM;
705 if (remote_adv & ADVERTISE_1000XPAUSE)
706 new_remote_adv |= ADVERTISE_PAUSE_CAP;
707 if (remote_adv & ADVERTISE_1000XPSE_ASYM)
708 new_remote_adv |= ADVERTISE_PAUSE_ASYM;
709
710 local_adv = new_local_adv;
711 remote_adv = new_remote_adv;
712 }
713
714 /* See Table 28B-3 of 802.3ab-1999 spec. */
715 if (local_adv & ADVERTISE_PAUSE_CAP) {
716 if(local_adv & ADVERTISE_PAUSE_ASYM) {
717 if (remote_adv & ADVERTISE_PAUSE_CAP) {
718 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
719 }
720 else if (remote_adv & ADVERTISE_PAUSE_ASYM) {
721 bp->flow_ctrl = FLOW_CTRL_RX;
722 }
723 }
724 else {
725 if (remote_adv & ADVERTISE_PAUSE_CAP) {
726 bp->flow_ctrl = FLOW_CTRL_TX | FLOW_CTRL_RX;
727 }
728 }
729 }
730 else if (local_adv & ADVERTISE_PAUSE_ASYM) {
731 if ((remote_adv & ADVERTISE_PAUSE_CAP) &&
732 (remote_adv & ADVERTISE_PAUSE_ASYM)) {
733
734 bp->flow_ctrl = FLOW_CTRL_TX;
735 }
736 }
737}
738
739static int
Michael Chan27a005b2007-05-03 13:23:41 -0700740bnx2_5709s_linkup(struct bnx2 *bp)
741{
742 u32 val, speed;
743
744 bp->link_up = 1;
745
746 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_GP_STATUS);
747 bnx2_read_phy(bp, MII_BNX2_GP_TOP_AN_STATUS1, &val);
748 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
749
750 if ((bp->autoneg & AUTONEG_SPEED) == 0) {
751 bp->line_speed = bp->req_line_speed;
752 bp->duplex = bp->req_duplex;
753 return 0;
754 }
755 speed = val & MII_BNX2_GP_TOP_AN_SPEED_MSK;
756 switch (speed) {
757 case MII_BNX2_GP_TOP_AN_SPEED_10:
758 bp->line_speed = SPEED_10;
759 break;
760 case MII_BNX2_GP_TOP_AN_SPEED_100:
761 bp->line_speed = SPEED_100;
762 break;
763 case MII_BNX2_GP_TOP_AN_SPEED_1G:
764 case MII_BNX2_GP_TOP_AN_SPEED_1GKV:
765 bp->line_speed = SPEED_1000;
766 break;
767 case MII_BNX2_GP_TOP_AN_SPEED_2_5G:
768 bp->line_speed = SPEED_2500;
769 break;
770 }
771 if (val & MII_BNX2_GP_TOP_AN_FD)
772 bp->duplex = DUPLEX_FULL;
773 else
774 bp->duplex = DUPLEX_HALF;
775 return 0;
776}
777
778static int
Michael Chan5b0c76a2005-11-04 08:45:49 -0800779bnx2_5708s_linkup(struct bnx2 *bp)
780{
781 u32 val;
782
783 bp->link_up = 1;
784 bnx2_read_phy(bp, BCM5708S_1000X_STAT1, &val);
785 switch (val & BCM5708S_1000X_STAT1_SPEED_MASK) {
786 case BCM5708S_1000X_STAT1_SPEED_10:
787 bp->line_speed = SPEED_10;
788 break;
789 case BCM5708S_1000X_STAT1_SPEED_100:
790 bp->line_speed = SPEED_100;
791 break;
792 case BCM5708S_1000X_STAT1_SPEED_1G:
793 bp->line_speed = SPEED_1000;
794 break;
795 case BCM5708S_1000X_STAT1_SPEED_2G5:
796 bp->line_speed = SPEED_2500;
797 break;
798 }
799 if (val & BCM5708S_1000X_STAT1_FD)
800 bp->duplex = DUPLEX_FULL;
801 else
802 bp->duplex = DUPLEX_HALF;
803
804 return 0;
805}
806
807static int
808bnx2_5706s_linkup(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -0700809{
810 u32 bmcr, local_adv, remote_adv, common;
811
812 bp->link_up = 1;
813 bp->line_speed = SPEED_1000;
814
Michael Chanca58c3a2007-05-03 13:22:52 -0700815 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700816 if (bmcr & BMCR_FULLDPLX) {
817 bp->duplex = DUPLEX_FULL;
818 }
819 else {
820 bp->duplex = DUPLEX_HALF;
821 }
822
823 if (!(bmcr & BMCR_ANENABLE)) {
824 return 0;
825 }
826
Michael Chanca58c3a2007-05-03 13:22:52 -0700827 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
828 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700829
830 common = local_adv & remote_adv;
831 if (common & (ADVERTISE_1000XHALF | ADVERTISE_1000XFULL)) {
832
833 if (common & ADVERTISE_1000XFULL) {
834 bp->duplex = DUPLEX_FULL;
835 }
836 else {
837 bp->duplex = DUPLEX_HALF;
838 }
839 }
840
841 return 0;
842}
843
844static int
845bnx2_copper_linkup(struct bnx2 *bp)
846{
847 u32 bmcr;
848
Michael Chanca58c3a2007-05-03 13:22:52 -0700849 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -0700850 if (bmcr & BMCR_ANENABLE) {
851 u32 local_adv, remote_adv, common;
852
853 bnx2_read_phy(bp, MII_CTRL1000, &local_adv);
854 bnx2_read_phy(bp, MII_STAT1000, &remote_adv);
855
856 common = local_adv & (remote_adv >> 2);
857 if (common & ADVERTISE_1000FULL) {
858 bp->line_speed = SPEED_1000;
859 bp->duplex = DUPLEX_FULL;
860 }
861 else if (common & ADVERTISE_1000HALF) {
862 bp->line_speed = SPEED_1000;
863 bp->duplex = DUPLEX_HALF;
864 }
865 else {
Michael Chanca58c3a2007-05-03 13:22:52 -0700866 bnx2_read_phy(bp, bp->mii_adv, &local_adv);
867 bnx2_read_phy(bp, bp->mii_lpa, &remote_adv);
Michael Chanb6016b72005-05-26 13:03:09 -0700868
869 common = local_adv & remote_adv;
870 if (common & ADVERTISE_100FULL) {
871 bp->line_speed = SPEED_100;
872 bp->duplex = DUPLEX_FULL;
873 }
874 else if (common & ADVERTISE_100HALF) {
875 bp->line_speed = SPEED_100;
876 bp->duplex = DUPLEX_HALF;
877 }
878 else if (common & ADVERTISE_10FULL) {
879 bp->line_speed = SPEED_10;
880 bp->duplex = DUPLEX_FULL;
881 }
882 else if (common & ADVERTISE_10HALF) {
883 bp->line_speed = SPEED_10;
884 bp->duplex = DUPLEX_HALF;
885 }
886 else {
887 bp->line_speed = 0;
888 bp->link_up = 0;
889 }
890 }
891 }
892 else {
893 if (bmcr & BMCR_SPEED100) {
894 bp->line_speed = SPEED_100;
895 }
896 else {
897 bp->line_speed = SPEED_10;
898 }
899 if (bmcr & BMCR_FULLDPLX) {
900 bp->duplex = DUPLEX_FULL;
901 }
902 else {
903 bp->duplex = DUPLEX_HALF;
904 }
905 }
906
907 return 0;
908}
909
910static int
911bnx2_set_mac_link(struct bnx2 *bp)
912{
913 u32 val;
914
915 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x2620);
916 if (bp->link_up && (bp->line_speed == SPEED_1000) &&
917 (bp->duplex == DUPLEX_HALF)) {
918 REG_WR(bp, BNX2_EMAC_TX_LENGTHS, 0x26ff);
919 }
920
921 /* Configure the EMAC mode register. */
922 val = REG_RD(bp, BNX2_EMAC_MODE);
923
924 val &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
Michael Chan5b0c76a2005-11-04 08:45:49 -0800925 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -0800926 BNX2_EMAC_MODE_25G_MODE);
Michael Chanb6016b72005-05-26 13:03:09 -0700927
928 if (bp->link_up) {
Michael Chan5b0c76a2005-11-04 08:45:49 -0800929 switch (bp->line_speed) {
930 case SPEED_10:
Michael Chan59b47d82006-11-19 14:10:45 -0800931 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
932 val |= BNX2_EMAC_MODE_PORT_MII_10M;
Michael Chan5b0c76a2005-11-04 08:45:49 -0800933 break;
934 }
935 /* fall through */
936 case SPEED_100:
937 val |= BNX2_EMAC_MODE_PORT_MII;
938 break;
939 case SPEED_2500:
Michael Chan59b47d82006-11-19 14:10:45 -0800940 val |= BNX2_EMAC_MODE_25G_MODE;
Michael Chan5b0c76a2005-11-04 08:45:49 -0800941 /* fall through */
942 case SPEED_1000:
943 val |= BNX2_EMAC_MODE_PORT_GMII;
944 break;
945 }
Michael Chanb6016b72005-05-26 13:03:09 -0700946 }
947 else {
948 val |= BNX2_EMAC_MODE_PORT_GMII;
949 }
950
951 /* Set the MAC to operate in the appropriate duplex mode. */
952 if (bp->duplex == DUPLEX_HALF)
953 val |= BNX2_EMAC_MODE_HALF_DUPLEX;
954 REG_WR(bp, BNX2_EMAC_MODE, val);
955
956 /* Enable/disable rx PAUSE. */
957 bp->rx_mode &= ~BNX2_EMAC_RX_MODE_FLOW_EN;
958
959 if (bp->flow_ctrl & FLOW_CTRL_RX)
960 bp->rx_mode |= BNX2_EMAC_RX_MODE_FLOW_EN;
961 REG_WR(bp, BNX2_EMAC_RX_MODE, bp->rx_mode);
962
963 /* Enable/disable tx PAUSE. */
964 val = REG_RD(bp, BNX2_EMAC_TX_MODE);
965 val &= ~BNX2_EMAC_TX_MODE_FLOW_EN;
966
967 if (bp->flow_ctrl & FLOW_CTRL_TX)
968 val |= BNX2_EMAC_TX_MODE_FLOW_EN;
969 REG_WR(bp, BNX2_EMAC_TX_MODE, val);
970
971 /* Acknowledge the interrupt. */
972 REG_WR(bp, BNX2_EMAC_STATUS, BNX2_EMAC_STATUS_LINK_CHANGE);
973
974 return 0;
975}
976
Michael Chan27a005b2007-05-03 13:23:41 -0700977static void
978bnx2_enable_bmsr1(struct bnx2 *bp)
979{
980 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
981 (CHIP_NUM(bp) == CHIP_NUM_5709))
982 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
983 MII_BNX2_BLK_ADDR_GP_STATUS);
984}
985
986static void
987bnx2_disable_bmsr1(struct bnx2 *bp)
988{
989 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
990 (CHIP_NUM(bp) == CHIP_NUM_5709))
991 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
992 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
993}
994
Michael Chanb6016b72005-05-26 13:03:09 -0700995static int
Michael Chan605a9e22007-05-03 13:23:13 -0700996bnx2_test_and_enable_2g5(struct bnx2 *bp)
997{
998 u32 up1;
999 int ret = 1;
1000
1001 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1002 return 0;
1003
1004 if (bp->autoneg & AUTONEG_SPEED)
1005 bp->advertising |= ADVERTISED_2500baseX_Full;
1006
Michael Chan27a005b2007-05-03 13:23:41 -07001007 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1008 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1009
Michael Chan605a9e22007-05-03 13:23:13 -07001010 bnx2_read_phy(bp, bp->mii_up1, &up1);
1011 if (!(up1 & BCM5708S_UP1_2G5)) {
1012 up1 |= BCM5708S_UP1_2G5;
1013 bnx2_write_phy(bp, bp->mii_up1, up1);
1014 ret = 0;
1015 }
1016
Michael Chan27a005b2007-05-03 13:23:41 -07001017 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1018 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1019 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1020
Michael Chan605a9e22007-05-03 13:23:13 -07001021 return ret;
1022}
1023
1024static int
1025bnx2_test_and_disable_2g5(struct bnx2 *bp)
1026{
1027 u32 up1;
1028 int ret = 0;
1029
1030 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1031 return 0;
1032
Michael Chan27a005b2007-05-03 13:23:41 -07001033 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1034 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1035
Michael Chan605a9e22007-05-03 13:23:13 -07001036 bnx2_read_phy(bp, bp->mii_up1, &up1);
1037 if (up1 & BCM5708S_UP1_2G5) {
1038 up1 &= ~BCM5708S_UP1_2G5;
1039 bnx2_write_phy(bp, bp->mii_up1, up1);
1040 ret = 1;
1041 }
1042
Michael Chan27a005b2007-05-03 13:23:41 -07001043 if (CHIP_NUM(bp) == CHIP_NUM_5709)
1044 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1045 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1046
Michael Chan605a9e22007-05-03 13:23:13 -07001047 return ret;
1048}
1049
1050static void
1051bnx2_enable_forced_2g5(struct bnx2 *bp)
1052{
1053 u32 bmcr;
1054
1055 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1056 return;
1057
Michael Chan27a005b2007-05-03 13:23:41 -07001058 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1059 u32 val;
1060
1061 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1062 MII_BNX2_BLK_ADDR_SERDES_DIG);
1063 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1064 val &= ~MII_BNX2_SD_MISC1_FORCE_MSK;
1065 val |= MII_BNX2_SD_MISC1_FORCE | MII_BNX2_SD_MISC1_FORCE_2_5G;
1066 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1067
1068 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1069 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1070 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1071
1072 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001073 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1074 bmcr |= BCM5708S_BMCR_FORCE_2500;
1075 }
1076
1077 if (bp->autoneg & AUTONEG_SPEED) {
1078 bmcr &= ~BMCR_ANENABLE;
1079 if (bp->req_duplex == DUPLEX_FULL)
1080 bmcr |= BMCR_FULLDPLX;
1081 }
1082 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1083}
1084
1085static void
1086bnx2_disable_forced_2g5(struct bnx2 *bp)
1087{
1088 u32 bmcr;
1089
1090 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
1091 return;
1092
Michael Chan27a005b2007-05-03 13:23:41 -07001093 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1094 u32 val;
1095
1096 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1097 MII_BNX2_BLK_ADDR_SERDES_DIG);
1098 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_MISC1, &val);
1099 val &= ~MII_BNX2_SD_MISC1_FORCE;
1100 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_MISC1, val);
1101
1102 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR,
1103 MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1104 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1105
1106 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001107 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
1108 bmcr &= ~BCM5708S_BMCR_FORCE_2500;
1109 }
1110
1111 if (bp->autoneg & AUTONEG_SPEED)
1112 bmcr |= BMCR_SPEED1000 | BMCR_ANENABLE | BMCR_ANRESTART;
1113 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
1114}
1115
1116static int
Michael Chanb6016b72005-05-26 13:03:09 -07001117bnx2_set_link(struct bnx2 *bp)
1118{
1119 u32 bmsr;
1120 u8 link_up;
1121
Michael Chan80be4432006-11-19 14:07:28 -08001122 if (bp->loopback == MAC_LOOPBACK || bp->loopback == PHY_LOOPBACK) {
Michael Chanb6016b72005-05-26 13:03:09 -07001123 bp->link_up = 1;
1124 return 0;
1125 }
1126
Michael Chan0d8a6572007-07-07 22:49:43 -07001127 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1128 return 0;
1129
Michael Chanb6016b72005-05-26 13:03:09 -07001130 link_up = bp->link_up;
1131
Michael Chan27a005b2007-05-03 13:23:41 -07001132 bnx2_enable_bmsr1(bp);
1133 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1134 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
1135 bnx2_disable_bmsr1(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001136
1137 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
1138 (CHIP_NUM(bp) == CHIP_NUM_5706)) {
1139 u32 val;
1140
1141 val = REG_RD(bp, BNX2_EMAC_STATUS);
1142 if (val & BNX2_EMAC_STATUS_LINK)
1143 bmsr |= BMSR_LSTATUS;
1144 else
1145 bmsr &= ~BMSR_LSTATUS;
1146 }
1147
1148 if (bmsr & BMSR_LSTATUS) {
1149 bp->link_up = 1;
1150
1151 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001152 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1153 bnx2_5706s_linkup(bp);
1154 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1155 bnx2_5708s_linkup(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001156 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1157 bnx2_5709s_linkup(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001158 }
1159 else {
1160 bnx2_copper_linkup(bp);
1161 }
1162 bnx2_resolve_flow_ctrl(bp);
1163 }
1164 else {
1165 if ((bp->phy_flags & PHY_SERDES_FLAG) &&
Michael Chan605a9e22007-05-03 13:23:13 -07001166 (bp->autoneg & AUTONEG_SPEED))
1167 bnx2_disable_forced_2g5(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001168
Michael Chanb6016b72005-05-26 13:03:09 -07001169 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
1170 bp->link_up = 0;
1171 }
1172
1173 if (bp->link_up != link_up) {
1174 bnx2_report_link(bp);
1175 }
1176
1177 bnx2_set_mac_link(bp);
1178
1179 return 0;
1180}
1181
1182static int
1183bnx2_reset_phy(struct bnx2 *bp)
1184{
1185 int i;
1186 u32 reg;
1187
Michael Chanca58c3a2007-05-03 13:22:52 -07001188 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_RESET);
Michael Chanb6016b72005-05-26 13:03:09 -07001189
1190#define PHY_RESET_MAX_WAIT 100
1191 for (i = 0; i < PHY_RESET_MAX_WAIT; i++) {
1192 udelay(10);
1193
Michael Chanca58c3a2007-05-03 13:22:52 -07001194 bnx2_read_phy(bp, bp->mii_bmcr, &reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001195 if (!(reg & BMCR_RESET)) {
1196 udelay(20);
1197 break;
1198 }
1199 }
1200 if (i == PHY_RESET_MAX_WAIT) {
1201 return -EBUSY;
1202 }
1203 return 0;
1204}
1205
1206static u32
1207bnx2_phy_get_pause_adv(struct bnx2 *bp)
1208{
1209 u32 adv = 0;
1210
1211 if ((bp->req_flow_ctrl & (FLOW_CTRL_RX | FLOW_CTRL_TX)) ==
1212 (FLOW_CTRL_RX | FLOW_CTRL_TX)) {
1213
1214 if (bp->phy_flags & PHY_SERDES_FLAG) {
1215 adv = ADVERTISE_1000XPAUSE;
1216 }
1217 else {
1218 adv = ADVERTISE_PAUSE_CAP;
1219 }
1220 }
1221 else if (bp->req_flow_ctrl & FLOW_CTRL_TX) {
1222 if (bp->phy_flags & PHY_SERDES_FLAG) {
1223 adv = ADVERTISE_1000XPSE_ASYM;
1224 }
1225 else {
1226 adv = ADVERTISE_PAUSE_ASYM;
1227 }
1228 }
1229 else if (bp->req_flow_ctrl & FLOW_CTRL_RX) {
1230 if (bp->phy_flags & PHY_SERDES_FLAG) {
1231 adv = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM;
1232 }
1233 else {
1234 adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
1235 }
1236 }
1237 return adv;
1238}
1239
Michael Chan0d8a6572007-07-07 22:49:43 -07001240static int bnx2_fw_sync(struct bnx2 *, u32, int);
1241
Michael Chanb6016b72005-05-26 13:03:09 -07001242static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001243bnx2_setup_remote_phy(struct bnx2 *bp, u8 port)
1244{
1245 u32 speed_arg = 0, pause_adv;
1246
1247 pause_adv = bnx2_phy_get_pause_adv(bp);
1248
1249 if (bp->autoneg & AUTONEG_SPEED) {
1250 speed_arg |= BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG;
1251 if (bp->advertising & ADVERTISED_10baseT_Half)
1252 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1253 if (bp->advertising & ADVERTISED_10baseT_Full)
1254 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1255 if (bp->advertising & ADVERTISED_100baseT_Half)
1256 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1257 if (bp->advertising & ADVERTISED_100baseT_Full)
1258 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1259 if (bp->advertising & ADVERTISED_1000baseT_Full)
1260 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1261 if (bp->advertising & ADVERTISED_2500baseX_Full)
1262 speed_arg |= BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1263 } else {
1264 if (bp->req_line_speed == SPEED_2500)
1265 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_2G5FULL;
1266 else if (bp->req_line_speed == SPEED_1000)
1267 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_1GFULL;
1268 else if (bp->req_line_speed == SPEED_100) {
1269 if (bp->req_duplex == DUPLEX_FULL)
1270 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100FULL;
1271 else
1272 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_100HALF;
1273 } else if (bp->req_line_speed == SPEED_10) {
1274 if (bp->req_duplex == DUPLEX_FULL)
1275 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10FULL;
1276 else
1277 speed_arg = BNX2_NETLINK_SET_LINK_SPEED_10HALF;
1278 }
1279 }
1280
1281 if (pause_adv & (ADVERTISE_1000XPAUSE | ADVERTISE_PAUSE_CAP))
1282 speed_arg |= BNX2_NETLINK_SET_LINK_FC_SYM_PAUSE;
1283 if (pause_adv & (ADVERTISE_1000XPSE_ASYM | ADVERTISE_1000XPSE_ASYM))
1284 speed_arg |= BNX2_NETLINK_SET_LINK_FC_ASYM_PAUSE;
1285
1286 if (port == PORT_TP)
1287 speed_arg |= BNX2_NETLINK_SET_LINK_PHY_APP_REMOTE |
1288 BNX2_NETLINK_SET_LINK_ETH_AT_WIRESPEED;
1289
1290 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB_ARG0, speed_arg);
1291
1292 spin_unlock_bh(&bp->phy_lock);
1293 bnx2_fw_sync(bp, BNX2_DRV_MSG_CODE_CMD_SET_LINK, 0);
1294 spin_lock_bh(&bp->phy_lock);
1295
1296 return 0;
1297}
1298
1299static int
1300bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001301{
Michael Chan605a9e22007-05-03 13:23:13 -07001302 u32 adv, bmcr;
Michael Chanb6016b72005-05-26 13:03:09 -07001303 u32 new_adv = 0;
1304
Michael Chan0d8a6572007-07-07 22:49:43 -07001305 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1306 return (bnx2_setup_remote_phy(bp, port));
1307
Michael Chanb6016b72005-05-26 13:03:09 -07001308 if (!(bp->autoneg & AUTONEG_SPEED)) {
1309 u32 new_bmcr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001310 int force_link_down = 0;
1311
Michael Chan605a9e22007-05-03 13:23:13 -07001312 if (bp->req_line_speed == SPEED_2500) {
1313 if (!bnx2_test_and_enable_2g5(bp))
1314 force_link_down = 1;
1315 } else if (bp->req_line_speed == SPEED_1000) {
1316 if (bnx2_test_and_disable_2g5(bp))
1317 force_link_down = 1;
1318 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001319 bnx2_read_phy(bp, bp->mii_adv, &adv);
Michael Chan80be4432006-11-19 14:07:28 -08001320 adv &= ~(ADVERTISE_1000XFULL | ADVERTISE_1000XHALF);
1321
Michael Chanca58c3a2007-05-03 13:22:52 -07001322 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001323 new_bmcr = bmcr & ~BMCR_ANENABLE;
Michael Chan80be4432006-11-19 14:07:28 -08001324 new_bmcr |= BMCR_SPEED1000;
Michael Chan605a9e22007-05-03 13:23:13 -07001325
Michael Chan27a005b2007-05-03 13:23:41 -07001326 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
1327 if (bp->req_line_speed == SPEED_2500)
1328 bnx2_enable_forced_2g5(bp);
1329 else if (bp->req_line_speed == SPEED_1000) {
1330 bnx2_disable_forced_2g5(bp);
1331 new_bmcr &= ~0x2000;
1332 }
1333
1334 } else if (CHIP_NUM(bp) == CHIP_NUM_5708) {
Michael Chan605a9e22007-05-03 13:23:13 -07001335 if (bp->req_line_speed == SPEED_2500)
1336 new_bmcr |= BCM5708S_BMCR_FORCE_2500;
1337 else
1338 new_bmcr = bmcr & ~BCM5708S_BMCR_FORCE_2500;
Michael Chan5b0c76a2005-11-04 08:45:49 -08001339 }
1340
Michael Chanb6016b72005-05-26 13:03:09 -07001341 if (bp->req_duplex == DUPLEX_FULL) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001342 adv |= ADVERTISE_1000XFULL;
Michael Chanb6016b72005-05-26 13:03:09 -07001343 new_bmcr |= BMCR_FULLDPLX;
1344 }
1345 else {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001346 adv |= ADVERTISE_1000XHALF;
Michael Chanb6016b72005-05-26 13:03:09 -07001347 new_bmcr &= ~BMCR_FULLDPLX;
1348 }
Michael Chan5b0c76a2005-11-04 08:45:49 -08001349 if ((new_bmcr != bmcr) || (force_link_down)) {
Michael Chanb6016b72005-05-26 13:03:09 -07001350 /* Force a link down visible on the other side */
1351 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001352 bnx2_write_phy(bp, bp->mii_adv, adv &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001353 ~(ADVERTISE_1000XFULL |
1354 ADVERTISE_1000XHALF));
Michael Chanca58c3a2007-05-03 13:22:52 -07001355 bnx2_write_phy(bp, bp->mii_bmcr, bmcr |
Michael Chanb6016b72005-05-26 13:03:09 -07001356 BMCR_ANRESTART | BMCR_ANENABLE);
1357
1358 bp->link_up = 0;
1359 netif_carrier_off(bp->dev);
Michael Chanca58c3a2007-05-03 13:22:52 -07001360 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan80be4432006-11-19 14:07:28 -08001361 bnx2_report_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001362 }
Michael Chanca58c3a2007-05-03 13:22:52 -07001363 bnx2_write_phy(bp, bp->mii_adv, adv);
1364 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chan605a9e22007-05-03 13:23:13 -07001365 } else {
1366 bnx2_resolve_flow_ctrl(bp);
1367 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001368 }
1369 return 0;
1370 }
1371
Michael Chan605a9e22007-05-03 13:23:13 -07001372 bnx2_test_and_enable_2g5(bp);
Michael Chan5b0c76a2005-11-04 08:45:49 -08001373
Michael Chanb6016b72005-05-26 13:03:09 -07001374 if (bp->advertising & ADVERTISED_1000baseT_Full)
1375 new_adv |= ADVERTISE_1000XFULL;
1376
1377 new_adv |= bnx2_phy_get_pause_adv(bp);
1378
Michael Chanca58c3a2007-05-03 13:22:52 -07001379 bnx2_read_phy(bp, bp->mii_adv, &adv);
1380 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001381
1382 bp->serdes_an_pending = 0;
1383 if ((adv != new_adv) || ((bmcr & BMCR_ANENABLE) == 0)) {
1384 /* Force a link down visible on the other side */
1385 if (bp->link_up) {
Michael Chanca58c3a2007-05-03 13:22:52 -07001386 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chan80be4432006-11-19 14:07:28 -08001387 spin_unlock_bh(&bp->phy_lock);
1388 msleep(20);
1389 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07001390 }
1391
Michael Chanca58c3a2007-05-03 13:22:52 -07001392 bnx2_write_phy(bp, bp->mii_adv, new_adv);
1393 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001394 BMCR_ANENABLE);
Michael Chanf8dd0642006-11-19 14:08:29 -08001395 /* Speed up link-up time when the link partner
1396 * does not autonegotiate which is very common
1397 * in blade servers. Some blade servers use
1398 * IPMI for kerboard input and it's important
1399 * to minimize link disruptions. Autoneg. involves
1400 * exchanging base pages plus 3 next pages and
1401 * normally completes in about 120 msec.
1402 */
1403 bp->current_interval = SERDES_AN_TIMEOUT;
1404 bp->serdes_an_pending = 1;
1405 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chan605a9e22007-05-03 13:23:13 -07001406 } else {
1407 bnx2_resolve_flow_ctrl(bp);
1408 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001409 }
1410
1411 return 0;
1412}
1413
1414#define ETHTOOL_ALL_FIBRE_SPEED \
Michael Chandeaf3912007-07-07 22:48:00 -07001415 (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ? \
1416 (ADVERTISED_2500baseX_Full | ADVERTISED_1000baseT_Full) :\
1417 (ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07001418
1419#define ETHTOOL_ALL_COPPER_SPEED \
1420 (ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | \
1421 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full | \
1422 ADVERTISED_1000baseT_Full)
1423
1424#define PHY_ALL_10_100_SPEED (ADVERTISE_10HALF | ADVERTISE_10FULL | \
1425 ADVERTISE_100HALF | ADVERTISE_100FULL | ADVERTISE_CSMA)
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001426
Michael Chanb6016b72005-05-26 13:03:09 -07001427#define PHY_ALL_1000_SPEED (ADVERTISE_1000HALF | ADVERTISE_1000FULL)
1428
Michael Chandeaf3912007-07-07 22:48:00 -07001429static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001430bnx2_set_default_remote_link(struct bnx2 *bp)
1431{
1432 u32 link;
1433
1434 if (bp->phy_port == PORT_TP)
1435 link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_COPPER_LINK);
1436 else
1437 link = REG_RD_IND(bp, bp->shmem_base + BNX2_RPHY_SERDES_LINK);
1438
1439 if (link & BNX2_NETLINK_SET_LINK_ENABLE_AUTONEG) {
1440 bp->req_line_speed = 0;
1441 bp->autoneg |= AUTONEG_SPEED;
1442 bp->advertising = ADVERTISED_Autoneg;
1443 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1444 bp->advertising |= ADVERTISED_10baseT_Half;
1445 if (link & BNX2_NETLINK_SET_LINK_SPEED_10FULL)
1446 bp->advertising |= ADVERTISED_10baseT_Full;
1447 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1448 bp->advertising |= ADVERTISED_100baseT_Half;
1449 if (link & BNX2_NETLINK_SET_LINK_SPEED_100FULL)
1450 bp->advertising |= ADVERTISED_100baseT_Full;
1451 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1452 bp->advertising |= ADVERTISED_1000baseT_Full;
1453 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1454 bp->advertising |= ADVERTISED_2500baseX_Full;
1455 } else {
1456 bp->autoneg = 0;
1457 bp->advertising = 0;
1458 bp->req_duplex = DUPLEX_FULL;
1459 if (link & BNX2_NETLINK_SET_LINK_SPEED_10) {
1460 bp->req_line_speed = SPEED_10;
1461 if (link & BNX2_NETLINK_SET_LINK_SPEED_10HALF)
1462 bp->req_duplex = DUPLEX_HALF;
1463 }
1464 if (link & BNX2_NETLINK_SET_LINK_SPEED_100) {
1465 bp->req_line_speed = SPEED_100;
1466 if (link & BNX2_NETLINK_SET_LINK_SPEED_100HALF)
1467 bp->req_duplex = DUPLEX_HALF;
1468 }
1469 if (link & BNX2_NETLINK_SET_LINK_SPEED_1GFULL)
1470 bp->req_line_speed = SPEED_1000;
1471 if (link & BNX2_NETLINK_SET_LINK_SPEED_2G5FULL)
1472 bp->req_line_speed = SPEED_2500;
1473 }
1474}
1475
1476static void
Michael Chandeaf3912007-07-07 22:48:00 -07001477bnx2_set_default_link(struct bnx2 *bp)
1478{
Michael Chan0d8a6572007-07-07 22:49:43 -07001479 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1480 return bnx2_set_default_remote_link(bp);
1481
Michael Chandeaf3912007-07-07 22:48:00 -07001482 bp->autoneg = AUTONEG_SPEED | AUTONEG_FLOW_CTRL;
1483 bp->req_line_speed = 0;
1484 if (bp->phy_flags & PHY_SERDES_FLAG) {
1485 u32 reg;
1486
1487 bp->advertising = ETHTOOL_ALL_FIBRE_SPEED | ADVERTISED_Autoneg;
1488
1489 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG);
1490 reg &= BNX2_PORT_HW_CFG_CFG_DFLT_LINK_MASK;
1491 if (reg == BNX2_PORT_HW_CFG_CFG_DFLT_LINK_1G) {
1492 bp->autoneg = 0;
1493 bp->req_line_speed = bp->line_speed = SPEED_1000;
1494 bp->req_duplex = DUPLEX_FULL;
1495 }
1496 } else
1497 bp->advertising = ETHTOOL_ALL_COPPER_SPEED | ADVERTISED_Autoneg;
1498}
1499
Michael Chan0d8a6572007-07-07 22:49:43 -07001500static void
Michael Chandf149d72007-07-07 22:51:36 -07001501bnx2_send_heart_beat(struct bnx2 *bp)
1502{
1503 u32 msg;
1504 u32 addr;
1505
1506 spin_lock(&bp->indirect_lock);
1507 msg = (u32) (++bp->fw_drv_pulse_wr_seq & BNX2_DRV_PULSE_SEQ_MASK);
1508 addr = bp->shmem_base + BNX2_DRV_PULSE_MB;
1509 REG_WR(bp, BNX2_PCICFG_REG_WINDOW_ADDRESS, addr);
1510 REG_WR(bp, BNX2_PCICFG_REG_WINDOW, msg);
1511 spin_unlock(&bp->indirect_lock);
1512}
1513
1514static void
Michael Chan0d8a6572007-07-07 22:49:43 -07001515bnx2_remote_phy_event(struct bnx2 *bp)
1516{
1517 u32 msg;
1518 u8 link_up = bp->link_up;
1519 u8 old_port;
1520
1521 msg = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
1522
Michael Chandf149d72007-07-07 22:51:36 -07001523 if (msg & BNX2_LINK_STATUS_HEART_BEAT_EXPIRED)
1524 bnx2_send_heart_beat(bp);
1525
1526 msg &= ~BNX2_LINK_STATUS_HEART_BEAT_EXPIRED;
1527
Michael Chan0d8a6572007-07-07 22:49:43 -07001528 if ((msg & BNX2_LINK_STATUS_LINK_UP) == BNX2_LINK_STATUS_LINK_DOWN)
1529 bp->link_up = 0;
1530 else {
1531 u32 speed;
1532
1533 bp->link_up = 1;
1534 speed = msg & BNX2_LINK_STATUS_SPEED_MASK;
1535 bp->duplex = DUPLEX_FULL;
1536 switch (speed) {
1537 case BNX2_LINK_STATUS_10HALF:
1538 bp->duplex = DUPLEX_HALF;
1539 case BNX2_LINK_STATUS_10FULL:
1540 bp->line_speed = SPEED_10;
1541 break;
1542 case BNX2_LINK_STATUS_100HALF:
1543 bp->duplex = DUPLEX_HALF;
1544 case BNX2_LINK_STATUS_100BASE_T4:
1545 case BNX2_LINK_STATUS_100FULL:
1546 bp->line_speed = SPEED_100;
1547 break;
1548 case BNX2_LINK_STATUS_1000HALF:
1549 bp->duplex = DUPLEX_HALF;
1550 case BNX2_LINK_STATUS_1000FULL:
1551 bp->line_speed = SPEED_1000;
1552 break;
1553 case BNX2_LINK_STATUS_2500HALF:
1554 bp->duplex = DUPLEX_HALF;
1555 case BNX2_LINK_STATUS_2500FULL:
1556 bp->line_speed = SPEED_2500;
1557 break;
1558 default:
1559 bp->line_speed = 0;
1560 break;
1561 }
1562
1563 spin_lock(&bp->phy_lock);
1564 bp->flow_ctrl = 0;
1565 if ((bp->autoneg & (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) !=
1566 (AUTONEG_SPEED | AUTONEG_FLOW_CTRL)) {
1567 if (bp->duplex == DUPLEX_FULL)
1568 bp->flow_ctrl = bp->req_flow_ctrl;
1569 } else {
1570 if (msg & BNX2_LINK_STATUS_TX_FC_ENABLED)
1571 bp->flow_ctrl |= FLOW_CTRL_TX;
1572 if (msg & BNX2_LINK_STATUS_RX_FC_ENABLED)
1573 bp->flow_ctrl |= FLOW_CTRL_RX;
1574 }
1575
1576 old_port = bp->phy_port;
1577 if (msg & BNX2_LINK_STATUS_SERDES_LINK)
1578 bp->phy_port = PORT_FIBRE;
1579 else
1580 bp->phy_port = PORT_TP;
1581
1582 if (old_port != bp->phy_port)
1583 bnx2_set_default_link(bp);
1584
1585 spin_unlock(&bp->phy_lock);
1586 }
1587 if (bp->link_up != link_up)
1588 bnx2_report_link(bp);
1589
1590 bnx2_set_mac_link(bp);
1591}
1592
1593static int
1594bnx2_set_remote_link(struct bnx2 *bp)
1595{
1596 u32 evt_code;
1597
1598 evt_code = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_EVT_CODE_MB);
1599 switch (evt_code) {
1600 case BNX2_FW_EVT_CODE_LINK_EVENT:
1601 bnx2_remote_phy_event(bp);
1602 break;
1603 case BNX2_FW_EVT_CODE_SW_TIMER_EXPIRATION_EVENT:
1604 default:
Michael Chandf149d72007-07-07 22:51:36 -07001605 bnx2_send_heart_beat(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07001606 break;
1607 }
1608 return 0;
1609}
1610
Michael Chanb6016b72005-05-26 13:03:09 -07001611static int
1612bnx2_setup_copper_phy(struct bnx2 *bp)
1613{
1614 u32 bmcr;
1615 u32 new_bmcr;
1616
Michael Chanca58c3a2007-05-03 13:22:52 -07001617 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001618
1619 if (bp->autoneg & AUTONEG_SPEED) {
1620 u32 adv_reg, adv1000_reg;
1621 u32 new_adv_reg = 0;
1622 u32 new_adv1000_reg = 0;
1623
Michael Chanca58c3a2007-05-03 13:22:52 -07001624 bnx2_read_phy(bp, bp->mii_adv, &adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001625 adv_reg &= (PHY_ALL_10_100_SPEED | ADVERTISE_PAUSE_CAP |
1626 ADVERTISE_PAUSE_ASYM);
1627
1628 bnx2_read_phy(bp, MII_CTRL1000, &adv1000_reg);
1629 adv1000_reg &= PHY_ALL_1000_SPEED;
1630
1631 if (bp->advertising & ADVERTISED_10baseT_Half)
1632 new_adv_reg |= ADVERTISE_10HALF;
1633 if (bp->advertising & ADVERTISED_10baseT_Full)
1634 new_adv_reg |= ADVERTISE_10FULL;
1635 if (bp->advertising & ADVERTISED_100baseT_Half)
1636 new_adv_reg |= ADVERTISE_100HALF;
1637 if (bp->advertising & ADVERTISED_100baseT_Full)
1638 new_adv_reg |= ADVERTISE_100FULL;
1639 if (bp->advertising & ADVERTISED_1000baseT_Full)
1640 new_adv1000_reg |= ADVERTISE_1000FULL;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001641
Michael Chanb6016b72005-05-26 13:03:09 -07001642 new_adv_reg |= ADVERTISE_CSMA;
1643
1644 new_adv_reg |= bnx2_phy_get_pause_adv(bp);
1645
1646 if ((adv1000_reg != new_adv1000_reg) ||
1647 (adv_reg != new_adv_reg) ||
1648 ((bmcr & BMCR_ANENABLE) == 0)) {
1649
Michael Chanca58c3a2007-05-03 13:22:52 -07001650 bnx2_write_phy(bp, bp->mii_adv, new_adv_reg);
Michael Chanb6016b72005-05-26 13:03:09 -07001651 bnx2_write_phy(bp, MII_CTRL1000, new_adv1000_reg);
Michael Chanca58c3a2007-05-03 13:22:52 -07001652 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_ANRESTART |
Michael Chanb6016b72005-05-26 13:03:09 -07001653 BMCR_ANENABLE);
1654 }
1655 else if (bp->link_up) {
1656 /* Flow ctrl may have changed from auto to forced */
1657 /* or vice-versa. */
1658
1659 bnx2_resolve_flow_ctrl(bp);
1660 bnx2_set_mac_link(bp);
1661 }
1662 return 0;
1663 }
1664
1665 new_bmcr = 0;
1666 if (bp->req_line_speed == SPEED_100) {
1667 new_bmcr |= BMCR_SPEED100;
1668 }
1669 if (bp->req_duplex == DUPLEX_FULL) {
1670 new_bmcr |= BMCR_FULLDPLX;
1671 }
1672 if (new_bmcr != bmcr) {
1673 u32 bmsr;
Michael Chanb6016b72005-05-26 13:03:09 -07001674
Michael Chanca58c3a2007-05-03 13:22:52 -07001675 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1676 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04001677
Michael Chanb6016b72005-05-26 13:03:09 -07001678 if (bmsr & BMSR_LSTATUS) {
1679 /* Force link down */
Michael Chanca58c3a2007-05-03 13:22:52 -07001680 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chana16dda02006-11-19 14:08:56 -08001681 spin_unlock_bh(&bp->phy_lock);
1682 msleep(50);
1683 spin_lock_bh(&bp->phy_lock);
1684
Michael Chanca58c3a2007-05-03 13:22:52 -07001685 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
1686 bnx2_read_phy(bp, bp->mii_bmsr, &bmsr);
Michael Chanb6016b72005-05-26 13:03:09 -07001687 }
1688
Michael Chanca58c3a2007-05-03 13:22:52 -07001689 bnx2_write_phy(bp, bp->mii_bmcr, new_bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07001690
1691 /* Normally, the new speed is setup after the link has
1692 * gone down and up again. In some cases, link will not go
1693 * down so we need to set up the new speed here.
1694 */
1695 if (bmsr & BMSR_LSTATUS) {
1696 bp->line_speed = bp->req_line_speed;
1697 bp->duplex = bp->req_duplex;
1698 bnx2_resolve_flow_ctrl(bp);
1699 bnx2_set_mac_link(bp);
1700 }
Michael Chan27a005b2007-05-03 13:23:41 -07001701 } else {
1702 bnx2_resolve_flow_ctrl(bp);
1703 bnx2_set_mac_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001704 }
1705 return 0;
1706}
1707
1708static int
Michael Chan0d8a6572007-07-07 22:49:43 -07001709bnx2_setup_phy(struct bnx2 *bp, u8 port)
Michael Chanb6016b72005-05-26 13:03:09 -07001710{
1711 if (bp->loopback == MAC_LOOPBACK)
1712 return 0;
1713
1714 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan0d8a6572007-07-07 22:49:43 -07001715 return (bnx2_setup_serdes_phy(bp, port));
Michael Chanb6016b72005-05-26 13:03:09 -07001716 }
1717 else {
1718 return (bnx2_setup_copper_phy(bp));
1719 }
1720}
1721
1722static int
Michael Chan27a005b2007-05-03 13:23:41 -07001723bnx2_init_5709s_phy(struct bnx2 *bp)
1724{
1725 u32 val;
1726
1727 bp->mii_bmcr = MII_BMCR + 0x10;
1728 bp->mii_bmsr = MII_BMSR + 0x10;
1729 bp->mii_bmsr1 = MII_BNX2_GP_TOP_AN_STATUS1;
1730 bp->mii_adv = MII_ADVERTISE + 0x10;
1731 bp->mii_lpa = MII_LPA + 0x10;
1732 bp->mii_up1 = MII_BNX2_OVER1G_UP1;
1733
1734 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_AER);
1735 bnx2_write_phy(bp, MII_BNX2_AER_AER, MII_BNX2_AER_AER_AN_MMD);
1736
1737 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1738 bnx2_reset_phy(bp);
1739
1740 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_SERDES_DIG);
1741
1742 bnx2_read_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, &val);
1743 val &= ~MII_BNX2_SD_1000XCTL1_AUTODET;
1744 val |= MII_BNX2_SD_1000XCTL1_FIBER;
1745 bnx2_write_phy(bp, MII_BNX2_SERDES_DIG_1000XCTL1, val);
1746
1747 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_OVER1G);
1748 bnx2_read_phy(bp, MII_BNX2_OVER1G_UP1, &val);
1749 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
1750 val |= BCM5708S_UP1_2G5;
1751 else
1752 val &= ~BCM5708S_UP1_2G5;
1753 bnx2_write_phy(bp, MII_BNX2_OVER1G_UP1, val);
1754
1755 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_BAM_NXTPG);
1756 bnx2_read_phy(bp, MII_BNX2_BAM_NXTPG_CTL, &val);
1757 val |= MII_BNX2_NXTPG_CTL_T2 | MII_BNX2_NXTPG_CTL_BAM;
1758 bnx2_write_phy(bp, MII_BNX2_BAM_NXTPG_CTL, val);
1759
1760 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_CL73_USERB0);
1761
1762 val = MII_BNX2_CL73_BAM_EN | MII_BNX2_CL73_BAM_STA_MGR_EN |
1763 MII_BNX2_CL73_BAM_NP_AFT_BP_EN;
1764 bnx2_write_phy(bp, MII_BNX2_CL73_BAM_CTL1, val);
1765
1766 bnx2_write_phy(bp, MII_BNX2_BLK_ADDR, MII_BNX2_BLK_ADDR_COMBO_IEEEB0);
1767
1768 return 0;
1769}
1770
1771static int
Michael Chan5b0c76a2005-11-04 08:45:49 -08001772bnx2_init_5708s_phy(struct bnx2 *bp)
1773{
1774 u32 val;
1775
Michael Chan27a005b2007-05-03 13:23:41 -07001776 bnx2_reset_phy(bp);
1777
1778 bp->mii_up1 = BCM5708S_UP1;
1779
Michael Chan5b0c76a2005-11-04 08:45:49 -08001780 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG3);
1781 bnx2_write_phy(bp, BCM5708S_DIG_3_0, BCM5708S_DIG_3_0_USE_IEEE);
1782 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1783
1784 bnx2_read_phy(bp, BCM5708S_1000X_CTL1, &val);
1785 val |= BCM5708S_1000X_CTL1_FIBER_MODE | BCM5708S_1000X_CTL1_AUTODET_EN;
1786 bnx2_write_phy(bp, BCM5708S_1000X_CTL1, val);
1787
1788 bnx2_read_phy(bp, BCM5708S_1000X_CTL2, &val);
1789 val |= BCM5708S_1000X_CTL2_PLLEL_DET_EN;
1790 bnx2_write_phy(bp, BCM5708S_1000X_CTL2, val);
1791
1792 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) {
1793 bnx2_read_phy(bp, BCM5708S_UP1, &val);
1794 val |= BCM5708S_UP1_2G5;
1795 bnx2_write_phy(bp, BCM5708S_UP1, val);
1796 }
1797
1798 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
Michael Chandda1e392006-01-23 16:08:14 -08001799 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
1800 (CHIP_ID(bp) == CHIP_ID_5708_B1)) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001801 /* increase tx signal amplitude */
1802 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1803 BCM5708S_BLK_ADDR_TX_MISC);
1804 bnx2_read_phy(bp, BCM5708S_TX_ACTL1, &val);
1805 val &= ~BCM5708S_TX_ACTL1_DRIVER_VCM;
1806 bnx2_write_phy(bp, BCM5708S_TX_ACTL1, val);
1807 bnx2_write_phy(bp, BCM5708S_BLK_ADDR, BCM5708S_BLK_ADDR_DIG);
1808 }
1809
Michael Chane3648b32005-11-04 08:51:21 -08001810 val = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_CONFIG) &
Michael Chan5b0c76a2005-11-04 08:45:49 -08001811 BNX2_PORT_HW_CFG_CFG_TXCTL3_MASK;
1812
1813 if (val) {
1814 u32 is_backplane;
1815
Michael Chane3648b32005-11-04 08:51:21 -08001816 is_backplane = REG_RD_IND(bp, bp->shmem_base +
Michael Chan5b0c76a2005-11-04 08:45:49 -08001817 BNX2_SHARED_HW_CFG_CONFIG);
1818 if (is_backplane & BNX2_SHARED_HW_CFG_PHY_BACKPLANE) {
1819 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1820 BCM5708S_BLK_ADDR_TX_MISC);
1821 bnx2_write_phy(bp, BCM5708S_TX_ACTL3, val);
1822 bnx2_write_phy(bp, BCM5708S_BLK_ADDR,
1823 BCM5708S_BLK_ADDR_DIG);
1824 }
1825 }
1826 return 0;
1827}
1828
1829static int
1830bnx2_init_5706s_phy(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07001831{
Michael Chan27a005b2007-05-03 13:23:41 -07001832 bnx2_reset_phy(bp);
1833
Michael Chanb6016b72005-05-26 13:03:09 -07001834 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
1835
Michael Chan59b47d82006-11-19 14:10:45 -08001836 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1837 REG_WR(bp, BNX2_MISC_GP_HW_CTL0, 0x300);
Michael Chanb6016b72005-05-26 13:03:09 -07001838
1839 if (bp->dev->mtu > 1500) {
1840 u32 val;
1841
1842 /* Set extended packet length bit */
1843 bnx2_write_phy(bp, 0x18, 0x7);
1844 bnx2_read_phy(bp, 0x18, &val);
1845 bnx2_write_phy(bp, 0x18, (val & 0xfff8) | 0x4000);
1846
1847 bnx2_write_phy(bp, 0x1c, 0x6c00);
1848 bnx2_read_phy(bp, 0x1c, &val);
1849 bnx2_write_phy(bp, 0x1c, (val & 0x3ff) | 0xec02);
1850 }
1851 else {
1852 u32 val;
1853
1854 bnx2_write_phy(bp, 0x18, 0x7);
1855 bnx2_read_phy(bp, 0x18, &val);
1856 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1857
1858 bnx2_write_phy(bp, 0x1c, 0x6c00);
1859 bnx2_read_phy(bp, 0x1c, &val);
1860 bnx2_write_phy(bp, 0x1c, (val & 0x3fd) | 0xec00);
1861 }
1862
1863 return 0;
1864}
1865
1866static int
1867bnx2_init_copper_phy(struct bnx2 *bp)
1868{
Michael Chan5b0c76a2005-11-04 08:45:49 -08001869 u32 val;
1870
Michael Chan27a005b2007-05-03 13:23:41 -07001871 bnx2_reset_phy(bp);
1872
Michael Chanb6016b72005-05-26 13:03:09 -07001873 if (bp->phy_flags & PHY_CRC_FIX_FLAG) {
1874 bnx2_write_phy(bp, 0x18, 0x0c00);
1875 bnx2_write_phy(bp, 0x17, 0x000a);
1876 bnx2_write_phy(bp, 0x15, 0x310b);
1877 bnx2_write_phy(bp, 0x17, 0x201f);
1878 bnx2_write_phy(bp, 0x15, 0x9506);
1879 bnx2_write_phy(bp, 0x17, 0x401f);
1880 bnx2_write_phy(bp, 0x15, 0x14e2);
1881 bnx2_write_phy(bp, 0x18, 0x0400);
1882 }
1883
Michael Chanb659f442007-02-02 00:46:35 -08001884 if (bp->phy_flags & PHY_DIS_EARLY_DAC_FLAG) {
1885 bnx2_write_phy(bp, MII_BNX2_DSP_ADDRESS,
1886 MII_BNX2_DSP_EXPAND_REG | 0x8);
1887 bnx2_read_phy(bp, MII_BNX2_DSP_RW_PORT, &val);
1888 val &= ~(1 << 8);
1889 bnx2_write_phy(bp, MII_BNX2_DSP_RW_PORT, val);
1890 }
1891
Michael Chanb6016b72005-05-26 13:03:09 -07001892 if (bp->dev->mtu > 1500) {
Michael Chanb6016b72005-05-26 13:03:09 -07001893 /* Set extended packet length bit */
1894 bnx2_write_phy(bp, 0x18, 0x7);
1895 bnx2_read_phy(bp, 0x18, &val);
1896 bnx2_write_phy(bp, 0x18, val | 0x4000);
1897
1898 bnx2_read_phy(bp, 0x10, &val);
1899 bnx2_write_phy(bp, 0x10, val | 0x1);
1900 }
1901 else {
Michael Chanb6016b72005-05-26 13:03:09 -07001902 bnx2_write_phy(bp, 0x18, 0x7);
1903 bnx2_read_phy(bp, 0x18, &val);
1904 bnx2_write_phy(bp, 0x18, val & ~0x4007);
1905
1906 bnx2_read_phy(bp, 0x10, &val);
1907 bnx2_write_phy(bp, 0x10, val & ~0x1);
1908 }
1909
Michael Chan5b0c76a2005-11-04 08:45:49 -08001910 /* ethernet@wirespeed */
1911 bnx2_write_phy(bp, 0x18, 0x7007);
1912 bnx2_read_phy(bp, 0x18, &val);
1913 bnx2_write_phy(bp, 0x18, val | (1 << 15) | (1 << 4));
Michael Chanb6016b72005-05-26 13:03:09 -07001914 return 0;
1915}
1916
1917
1918static int
1919bnx2_init_phy(struct bnx2 *bp)
1920{
1921 u32 val;
1922 int rc = 0;
1923
1924 bp->phy_flags &= ~PHY_INT_MODE_MASK_FLAG;
1925 bp->phy_flags |= PHY_INT_MODE_LINK_READY_FLAG;
1926
Michael Chanca58c3a2007-05-03 13:22:52 -07001927 bp->mii_bmcr = MII_BMCR;
1928 bp->mii_bmsr = MII_BMSR;
Michael Chan27a005b2007-05-03 13:23:41 -07001929 bp->mii_bmsr1 = MII_BMSR;
Michael Chanca58c3a2007-05-03 13:22:52 -07001930 bp->mii_adv = MII_ADVERTISE;
1931 bp->mii_lpa = MII_LPA;
1932
Michael Chanb6016b72005-05-26 13:03:09 -07001933 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
1934
Michael Chan0d8a6572007-07-07 22:49:43 -07001935 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
1936 goto setup_phy;
1937
Michael Chanb6016b72005-05-26 13:03:09 -07001938 bnx2_read_phy(bp, MII_PHYSID1, &val);
1939 bp->phy_id = val << 16;
1940 bnx2_read_phy(bp, MII_PHYSID2, &val);
1941 bp->phy_id |= val & 0xffff;
1942
1943 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08001944 if (CHIP_NUM(bp) == CHIP_NUM_5706)
1945 rc = bnx2_init_5706s_phy(bp);
1946 else if (CHIP_NUM(bp) == CHIP_NUM_5708)
1947 rc = bnx2_init_5708s_phy(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07001948 else if (CHIP_NUM(bp) == CHIP_NUM_5709)
1949 rc = bnx2_init_5709s_phy(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07001950 }
1951 else {
1952 rc = bnx2_init_copper_phy(bp);
1953 }
1954
Michael Chan0d8a6572007-07-07 22:49:43 -07001955setup_phy:
1956 if (!rc)
1957 rc = bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07001958
1959 return rc;
1960}
1961
1962static int
1963bnx2_set_mac_loopback(struct bnx2 *bp)
1964{
1965 u32 mac_mode;
1966
1967 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
1968 mac_mode &= ~BNX2_EMAC_MODE_PORT;
1969 mac_mode |= BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK;
1970 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
1971 bp->link_up = 1;
1972 return 0;
1973}
1974
Michael Chanbc5a0692006-01-23 16:13:22 -08001975static int bnx2_test_link(struct bnx2 *);
1976
1977static int
1978bnx2_set_phy_loopback(struct bnx2 *bp)
1979{
1980 u32 mac_mode;
1981 int rc, i;
1982
1983 spin_lock_bh(&bp->phy_lock);
Michael Chanca58c3a2007-05-03 13:22:52 -07001984 rc = bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK | BMCR_FULLDPLX |
Michael Chanbc5a0692006-01-23 16:13:22 -08001985 BMCR_SPEED1000);
1986 spin_unlock_bh(&bp->phy_lock);
1987 if (rc)
1988 return rc;
1989
1990 for (i = 0; i < 10; i++) {
1991 if (bnx2_test_link(bp) == 0)
1992 break;
Michael Chan80be4432006-11-19 14:07:28 -08001993 msleep(100);
Michael Chanbc5a0692006-01-23 16:13:22 -08001994 }
1995
1996 mac_mode = REG_RD(bp, BNX2_EMAC_MODE);
1997 mac_mode &= ~(BNX2_EMAC_MODE_PORT | BNX2_EMAC_MODE_HALF_DUPLEX |
1998 BNX2_EMAC_MODE_MAC_LOOP | BNX2_EMAC_MODE_FORCE_LINK |
Michael Chan59b47d82006-11-19 14:10:45 -08001999 BNX2_EMAC_MODE_25G_MODE);
Michael Chanbc5a0692006-01-23 16:13:22 -08002000
2001 mac_mode |= BNX2_EMAC_MODE_PORT_GMII;
2002 REG_WR(bp, BNX2_EMAC_MODE, mac_mode);
2003 bp->link_up = 1;
2004 return 0;
2005}
2006
Michael Chanb6016b72005-05-26 13:03:09 -07002007static int
Michael Chanb090ae22006-01-23 16:07:10 -08002008bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int silent)
Michael Chanb6016b72005-05-26 13:03:09 -07002009{
2010 int i;
2011 u32 val;
2012
Michael Chanb6016b72005-05-26 13:03:09 -07002013 bp->fw_wr_seq++;
2014 msg_data |= bp->fw_wr_seq;
2015
Michael Chane3648b32005-11-04 08:51:21 -08002016 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002017
2018 /* wait for an acknowledgement. */
Michael Chanb090ae22006-01-23 16:07:10 -08002019 for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) {
2020 msleep(10);
Michael Chanb6016b72005-05-26 13:03:09 -07002021
Michael Chane3648b32005-11-04 08:51:21 -08002022 val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_MB);
Michael Chanb6016b72005-05-26 13:03:09 -07002023
2024 if ((val & BNX2_FW_MSG_ACK) == (msg_data & BNX2_DRV_MSG_SEQ))
2025 break;
2026 }
Michael Chanb090ae22006-01-23 16:07:10 -08002027 if ((msg_data & BNX2_DRV_MSG_DATA) == BNX2_DRV_MSG_DATA_WAIT0)
2028 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002029
2030 /* If we timed out, inform the firmware that this is the case. */
Michael Chanb090ae22006-01-23 16:07:10 -08002031 if ((val & BNX2_FW_MSG_ACK) != (msg_data & BNX2_DRV_MSG_SEQ)) {
2032 if (!silent)
2033 printk(KERN_ERR PFX "fw sync timeout, reset code = "
2034 "%x\n", msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002035
2036 msg_data &= ~BNX2_DRV_MSG_CODE;
2037 msg_data |= BNX2_DRV_MSG_CODE_FW_TIMEOUT;
2038
Michael Chane3648b32005-11-04 08:51:21 -08002039 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_MB, msg_data);
Michael Chanb6016b72005-05-26 13:03:09 -07002040
Michael Chanb6016b72005-05-26 13:03:09 -07002041 return -EBUSY;
2042 }
2043
Michael Chanb090ae22006-01-23 16:07:10 -08002044 if ((val & BNX2_FW_MSG_STATUS_MASK) != BNX2_FW_MSG_STATUS_OK)
2045 return -EIO;
2046
Michael Chanb6016b72005-05-26 13:03:09 -07002047 return 0;
2048}
2049
Michael Chan59b47d82006-11-19 14:10:45 -08002050static int
2051bnx2_init_5709_context(struct bnx2 *bp)
2052{
2053 int i, ret = 0;
2054 u32 val;
2055
2056 val = BNX2_CTX_COMMAND_ENABLED | BNX2_CTX_COMMAND_MEM_INIT | (1 << 12);
2057 val |= (BCM_PAGE_BITS - 8) << 16;
2058 REG_WR(bp, BNX2_CTX_COMMAND, val);
Michael Chan641bdcd2007-06-04 21:22:24 -07002059 for (i = 0; i < 10; i++) {
2060 val = REG_RD(bp, BNX2_CTX_COMMAND);
2061 if (!(val & BNX2_CTX_COMMAND_MEM_INIT))
2062 break;
2063 udelay(2);
2064 }
2065 if (val & BNX2_CTX_COMMAND_MEM_INIT)
2066 return -EBUSY;
2067
Michael Chan59b47d82006-11-19 14:10:45 -08002068 for (i = 0; i < bp->ctx_pages; i++) {
2069 int j;
2070
2071 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA0,
2072 (bp->ctx_blk_mapping[i] & 0xffffffff) |
2073 BNX2_CTX_HOST_PAGE_TBL_DATA0_VALID);
2074 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_DATA1,
2075 (u64) bp->ctx_blk_mapping[i] >> 32);
2076 REG_WR(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL, i |
2077 BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ);
2078 for (j = 0; j < 10; j++) {
2079
2080 val = REG_RD(bp, BNX2_CTX_HOST_PAGE_TBL_CTRL);
2081 if (!(val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ))
2082 break;
2083 udelay(5);
2084 }
2085 if (val & BNX2_CTX_HOST_PAGE_TBL_CTRL_WRITE_REQ) {
2086 ret = -EBUSY;
2087 break;
2088 }
2089 }
2090 return ret;
2091}
2092
Michael Chanb6016b72005-05-26 13:03:09 -07002093static void
2094bnx2_init_context(struct bnx2 *bp)
2095{
2096 u32 vcid;
2097
2098 vcid = 96;
2099 while (vcid) {
2100 u32 vcid_addr, pcid_addr, offset;
Michael Chan7947b202007-06-04 21:17:10 -07002101 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002102
2103 vcid--;
2104
2105 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
2106 u32 new_vcid;
2107
2108 vcid_addr = GET_PCID_ADDR(vcid);
2109 if (vcid & 0x8) {
2110 new_vcid = 0x60 + (vcid & 0xf0) + (vcid & 0x7);
2111 }
2112 else {
2113 new_vcid = vcid;
2114 }
2115 pcid_addr = GET_PCID_ADDR(new_vcid);
2116 }
2117 else {
2118 vcid_addr = GET_CID_ADDR(vcid);
2119 pcid_addr = vcid_addr;
2120 }
2121
Michael Chan7947b202007-06-04 21:17:10 -07002122 for (i = 0; i < (CTX_SIZE / PHY_CTX_SIZE); i++) {
2123 vcid_addr += (i << PHY_CTX_SHIFT);
2124 pcid_addr += (i << PHY_CTX_SHIFT);
Michael Chanb6016b72005-05-26 13:03:09 -07002125
Michael Chan7947b202007-06-04 21:17:10 -07002126 REG_WR(bp, BNX2_CTX_VIRT_ADDR, 0x00);
2127 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
2128
2129 /* Zero out the context. */
2130 for (offset = 0; offset < PHY_CTX_SIZE; offset += 4)
2131 CTX_WR(bp, 0x00, offset, 0);
2132
2133 REG_WR(bp, BNX2_CTX_VIRT_ADDR, vcid_addr);
2134 REG_WR(bp, BNX2_CTX_PAGE_TBL, pcid_addr);
Michael Chanb6016b72005-05-26 13:03:09 -07002135 }
Michael Chanb6016b72005-05-26 13:03:09 -07002136 }
2137}
2138
2139static int
2140bnx2_alloc_bad_rbuf(struct bnx2 *bp)
2141{
2142 u16 *good_mbuf;
2143 u32 good_mbuf_cnt;
2144 u32 val;
2145
2146 good_mbuf = kmalloc(512 * sizeof(u16), GFP_KERNEL);
2147 if (good_mbuf == NULL) {
2148 printk(KERN_ERR PFX "Failed to allocate memory in "
2149 "bnx2_alloc_bad_rbuf\n");
2150 return -ENOMEM;
2151 }
2152
2153 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
2154 BNX2_MISC_ENABLE_SET_BITS_RX_MBUF_ENABLE);
2155
2156 good_mbuf_cnt = 0;
2157
2158 /* Allocate a bunch of mbufs and save the good ones in an array. */
2159 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
2160 while (val & BNX2_RBUF_STATUS1_FREE_COUNT) {
2161 REG_WR_IND(bp, BNX2_RBUF_COMMAND, BNX2_RBUF_COMMAND_ALLOC_REQ);
2162
2163 val = REG_RD_IND(bp, BNX2_RBUF_FW_BUF_ALLOC);
2164
2165 val &= BNX2_RBUF_FW_BUF_ALLOC_VALUE;
2166
2167 /* The addresses with Bit 9 set are bad memory blocks. */
2168 if (!(val & (1 << 9))) {
2169 good_mbuf[good_mbuf_cnt] = (u16) val;
2170 good_mbuf_cnt++;
2171 }
2172
2173 val = REG_RD_IND(bp, BNX2_RBUF_STATUS1);
2174 }
2175
2176 /* Free the good ones back to the mbuf pool thus discarding
2177 * all the bad ones. */
2178 while (good_mbuf_cnt) {
2179 good_mbuf_cnt--;
2180
2181 val = good_mbuf[good_mbuf_cnt];
2182 val = (val << 9) | val | 1;
2183
2184 REG_WR_IND(bp, BNX2_RBUF_FW_BUF_FREE, val);
2185 }
2186 kfree(good_mbuf);
2187 return 0;
2188}
2189
2190static void
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002191bnx2_set_mac_addr(struct bnx2 *bp)
Michael Chanb6016b72005-05-26 13:03:09 -07002192{
2193 u32 val;
2194 u8 *mac_addr = bp->dev->dev_addr;
2195
2196 val = (mac_addr[0] << 8) | mac_addr[1];
2197
2198 REG_WR(bp, BNX2_EMAC_MAC_MATCH0, val);
2199
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002200 val = (mac_addr[2] << 24) | (mac_addr[3] << 16) |
Michael Chanb6016b72005-05-26 13:03:09 -07002201 (mac_addr[4] << 8) | mac_addr[5];
2202
2203 REG_WR(bp, BNX2_EMAC_MAC_MATCH1, val);
2204}
2205
2206static inline int
2207bnx2_alloc_rx_skb(struct bnx2 *bp, u16 index)
2208{
2209 struct sk_buff *skb;
2210 struct sw_bd *rx_buf = &bp->rx_buf_ring[index];
2211 dma_addr_t mapping;
Michael Chan13daffa2006-03-20 17:49:20 -08002212 struct rx_bd *rxbd = &bp->rx_desc_ring[RX_RING(index)][RX_IDX(index)];
Michael Chanb6016b72005-05-26 13:03:09 -07002213 unsigned long align;
2214
Michael Chan932f3772006-08-15 01:39:36 -07002215 skb = netdev_alloc_skb(bp->dev, bp->rx_buf_size);
Michael Chanb6016b72005-05-26 13:03:09 -07002216 if (skb == NULL) {
2217 return -ENOMEM;
2218 }
2219
Michael Chan59b47d82006-11-19 14:10:45 -08002220 if (unlikely((align = (unsigned long) skb->data & (BNX2_RX_ALIGN - 1))))
2221 skb_reserve(skb, BNX2_RX_ALIGN - align);
Michael Chanb6016b72005-05-26 13:03:09 -07002222
Michael Chanb6016b72005-05-26 13:03:09 -07002223 mapping = pci_map_single(bp->pdev, skb->data, bp->rx_buf_use_size,
2224 PCI_DMA_FROMDEVICE);
2225
2226 rx_buf->skb = skb;
2227 pci_unmap_addr_set(rx_buf, mapping, mapping);
2228
2229 rxbd->rx_bd_haddr_hi = (u64) mapping >> 32;
2230 rxbd->rx_bd_haddr_lo = (u64) mapping & 0xffffffff;
2231
2232 bp->rx_prod_bseq += bp->rx_buf_use_size;
2233
2234 return 0;
2235}
2236
Michael Chanda3e4fb2007-05-03 13:24:23 -07002237static int
2238bnx2_phy_event_is_set(struct bnx2 *bp, u32 event)
2239{
2240 struct status_block *sblk = bp->status_blk;
2241 u32 new_link_state, old_link_state;
2242 int is_set = 1;
2243
2244 new_link_state = sblk->status_attn_bits & event;
2245 old_link_state = sblk->status_attn_bits_ack & event;
2246 if (new_link_state != old_link_state) {
2247 if (new_link_state)
2248 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_SET_CMD, event);
2249 else
2250 REG_WR(bp, BNX2_PCICFG_STATUS_BIT_CLEAR_CMD, event);
2251 } else
2252 is_set = 0;
2253
2254 return is_set;
2255}
2256
Michael Chanb6016b72005-05-26 13:03:09 -07002257static void
2258bnx2_phy_int(struct bnx2 *bp)
2259{
Michael Chanda3e4fb2007-05-03 13:24:23 -07002260 if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_LINK_STATE)) {
2261 spin_lock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002262 bnx2_set_link(bp);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002263 spin_unlock(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002264 }
Michael Chan0d8a6572007-07-07 22:49:43 -07002265 if (bnx2_phy_event_is_set(bp, STATUS_ATTN_BITS_TIMER_ABORT))
2266 bnx2_set_remote_link(bp);
2267
Michael Chanb6016b72005-05-26 13:03:09 -07002268}
2269
2270static void
2271bnx2_tx_int(struct bnx2 *bp)
2272{
Michael Chanf4e418f2005-11-04 08:53:48 -08002273 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002274 u16 hw_cons, sw_cons, sw_ring_cons;
2275 int tx_free_bd = 0;
2276
Michael Chanf4e418f2005-11-04 08:53:48 -08002277 hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
Michael Chanb6016b72005-05-26 13:03:09 -07002278 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
2279 hw_cons++;
2280 }
2281 sw_cons = bp->tx_cons;
2282
2283 while (sw_cons != hw_cons) {
2284 struct sw_bd *tx_buf;
2285 struct sk_buff *skb;
2286 int i, last;
2287
2288 sw_ring_cons = TX_RING_IDX(sw_cons);
2289
2290 tx_buf = &bp->tx_buf_ring[sw_ring_cons];
2291 skb = tx_buf->skb;
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002292
Michael Chanb6016b72005-05-26 13:03:09 -07002293 /* partial BD completions possible with TSO packets */
Herbert Xu89114af2006-07-08 13:34:32 -07002294 if (skb_is_gso(skb)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002295 u16 last_idx, last_ring_idx;
2296
2297 last_idx = sw_cons +
2298 skb_shinfo(skb)->nr_frags + 1;
2299 last_ring_idx = sw_ring_cons +
2300 skb_shinfo(skb)->nr_frags + 1;
2301 if (unlikely(last_ring_idx >= MAX_TX_DESC_CNT)) {
2302 last_idx++;
2303 }
2304 if (((s16) ((s16) last_idx - (s16) hw_cons)) > 0) {
2305 break;
2306 }
2307 }
Arjan van de Ven1d39ed52006-12-12 14:06:23 +01002308
Michael Chanb6016b72005-05-26 13:03:09 -07002309 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
2310 skb_headlen(skb), PCI_DMA_TODEVICE);
2311
2312 tx_buf->skb = NULL;
2313 last = skb_shinfo(skb)->nr_frags;
2314
2315 for (i = 0; i < last; i++) {
2316 sw_cons = NEXT_TX_BD(sw_cons);
2317
2318 pci_unmap_page(bp->pdev,
2319 pci_unmap_addr(
2320 &bp->tx_buf_ring[TX_RING_IDX(sw_cons)],
2321 mapping),
2322 skb_shinfo(skb)->frags[i].size,
2323 PCI_DMA_TODEVICE);
2324 }
2325
2326 sw_cons = NEXT_TX_BD(sw_cons);
2327
2328 tx_free_bd += last + 1;
2329
Michael Chan745720e2006-06-29 12:37:41 -07002330 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002331
Michael Chanf4e418f2005-11-04 08:53:48 -08002332 hw_cons = bp->hw_tx_cons =
2333 sblk->status_tx_quick_consumer_index0;
2334
Michael Chanb6016b72005-05-26 13:03:09 -07002335 if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
2336 hw_cons++;
2337 }
2338 }
2339
Michael Chane89bbf12005-08-25 15:36:58 -07002340 bp->tx_cons = sw_cons;
Michael Chan2f8af122006-08-15 01:39:10 -07002341 /* Need to make the tx_cons update visible to bnx2_start_xmit()
2342 * before checking for netif_queue_stopped(). Without the
2343 * memory barrier, there is a small possibility that bnx2_start_xmit()
2344 * will miss it and cause the queue to be stopped forever.
2345 */
2346 smp_mb();
Michael Chanb6016b72005-05-26 13:03:09 -07002347
Michael Chan2f8af122006-08-15 01:39:10 -07002348 if (unlikely(netif_queue_stopped(bp->dev)) &&
2349 (bnx2_tx_avail(bp) > bp->tx_wake_thresh)) {
2350 netif_tx_lock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002351 if ((netif_queue_stopped(bp->dev)) &&
Michael Chan2f8af122006-08-15 01:39:10 -07002352 (bnx2_tx_avail(bp) > bp->tx_wake_thresh))
Michael Chanb6016b72005-05-26 13:03:09 -07002353 netif_wake_queue(bp->dev);
Michael Chan2f8af122006-08-15 01:39:10 -07002354 netif_tx_unlock(bp->dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002355 }
Michael Chanb6016b72005-05-26 13:03:09 -07002356}
2357
2358static inline void
2359bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
2360 u16 cons, u16 prod)
2361{
Michael Chan236b6392006-03-20 17:49:02 -08002362 struct sw_bd *cons_rx_buf, *prod_rx_buf;
2363 struct rx_bd *cons_bd, *prod_bd;
2364
2365 cons_rx_buf = &bp->rx_buf_ring[cons];
2366 prod_rx_buf = &bp->rx_buf_ring[prod];
Michael Chanb6016b72005-05-26 13:03:09 -07002367
2368 pci_dma_sync_single_for_device(bp->pdev,
2369 pci_unmap_addr(cons_rx_buf, mapping),
2370 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2371
Michael Chan236b6392006-03-20 17:49:02 -08002372 bp->rx_prod_bseq += bp->rx_buf_use_size;
2373
2374 prod_rx_buf->skb = skb;
2375
2376 if (cons == prod)
2377 return;
2378
Michael Chanb6016b72005-05-26 13:03:09 -07002379 pci_unmap_addr_set(prod_rx_buf, mapping,
2380 pci_unmap_addr(cons_rx_buf, mapping));
2381
Michael Chan3fdfcc22006-03-20 17:49:49 -08002382 cons_bd = &bp->rx_desc_ring[RX_RING(cons)][RX_IDX(cons)];
2383 prod_bd = &bp->rx_desc_ring[RX_RING(prod)][RX_IDX(prod)];
Michael Chan236b6392006-03-20 17:49:02 -08002384 prod_bd->rx_bd_haddr_hi = cons_bd->rx_bd_haddr_hi;
2385 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
Michael Chanb6016b72005-05-26 13:03:09 -07002386}
2387
2388static int
2389bnx2_rx_int(struct bnx2 *bp, int budget)
2390{
Michael Chanf4e418f2005-11-04 08:53:48 -08002391 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002392 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
2393 struct l2_fhdr *rx_hdr;
2394 int rx_pkt = 0;
2395
Michael Chanf4e418f2005-11-04 08:53:48 -08002396 hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
Michael Chanb6016b72005-05-26 13:03:09 -07002397 if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
2398 hw_cons++;
2399 }
2400 sw_cons = bp->rx_cons;
2401 sw_prod = bp->rx_prod;
2402
2403 /* Memory barrier necessary as speculative reads of the rx
2404 * buffer can be ahead of the index in the status block
2405 */
2406 rmb();
2407 while (sw_cons != hw_cons) {
2408 unsigned int len;
Michael Chanade2bfe2006-01-23 16:09:51 -08002409 u32 status;
Michael Chanb6016b72005-05-26 13:03:09 -07002410 struct sw_bd *rx_buf;
2411 struct sk_buff *skb;
Michael Chan236b6392006-03-20 17:49:02 -08002412 dma_addr_t dma_addr;
Michael Chanb6016b72005-05-26 13:03:09 -07002413
2414 sw_ring_cons = RX_RING_IDX(sw_cons);
2415 sw_ring_prod = RX_RING_IDX(sw_prod);
2416
2417 rx_buf = &bp->rx_buf_ring[sw_ring_cons];
2418 skb = rx_buf->skb;
Michael Chan236b6392006-03-20 17:49:02 -08002419
2420 rx_buf->skb = NULL;
2421
2422 dma_addr = pci_unmap_addr(rx_buf, mapping);
2423
2424 pci_dma_sync_single_for_cpu(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07002425 bp->rx_offset + RX_COPY_THRESH, PCI_DMA_FROMDEVICE);
2426
2427 rx_hdr = (struct l2_fhdr *) skb->data;
2428 len = rx_hdr->l2_fhdr_pkt_len - 4;
2429
Michael Chanade2bfe2006-01-23 16:09:51 -08002430 if ((status = rx_hdr->l2_fhdr_status) &
Michael Chanb6016b72005-05-26 13:03:09 -07002431 (L2_FHDR_ERRORS_BAD_CRC |
2432 L2_FHDR_ERRORS_PHY_DECODE |
2433 L2_FHDR_ERRORS_ALIGNMENT |
2434 L2_FHDR_ERRORS_TOO_SHORT |
2435 L2_FHDR_ERRORS_GIANT_FRAME)) {
2436
2437 goto reuse_rx;
2438 }
2439
2440 /* Since we don't have a jumbo ring, copy small packets
2441 * if mtu > 1500
2442 */
2443 if ((bp->dev->mtu > 1500) && (len <= RX_COPY_THRESH)) {
2444 struct sk_buff *new_skb;
2445
Michael Chan932f3772006-08-15 01:39:36 -07002446 new_skb = netdev_alloc_skb(bp->dev, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07002447 if (new_skb == NULL)
2448 goto reuse_rx;
2449
2450 /* aligned copy */
Arnaldo Carvalho de Melod626f622007-03-27 18:55:52 -03002451 skb_copy_from_linear_data_offset(skb, bp->rx_offset - 2,
2452 new_skb->data, len + 2);
Michael Chanb6016b72005-05-26 13:03:09 -07002453 skb_reserve(new_skb, 2);
2454 skb_put(new_skb, len);
Michael Chanb6016b72005-05-26 13:03:09 -07002455
2456 bnx2_reuse_rx_skb(bp, skb,
2457 sw_ring_cons, sw_ring_prod);
2458
2459 skb = new_skb;
2460 }
2461 else if (bnx2_alloc_rx_skb(bp, sw_ring_prod) == 0) {
Michael Chan236b6392006-03-20 17:49:02 -08002462 pci_unmap_single(bp->pdev, dma_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07002463 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
2464
2465 skb_reserve(skb, bp->rx_offset);
2466 skb_put(skb, len);
2467 }
2468 else {
2469reuse_rx:
2470 bnx2_reuse_rx_skb(bp, skb,
2471 sw_ring_cons, sw_ring_prod);
2472 goto next_rx;
2473 }
2474
2475 skb->protocol = eth_type_trans(skb, bp->dev);
2476
2477 if ((len > (bp->dev->mtu + ETH_HLEN)) &&
Alexey Dobriyand1e100b2006-06-11 20:57:17 -07002478 (ntohs(skb->protocol) != 0x8100)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002479
Michael Chan745720e2006-06-29 12:37:41 -07002480 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07002481 goto next_rx;
2482
2483 }
2484
Michael Chanb6016b72005-05-26 13:03:09 -07002485 skb->ip_summed = CHECKSUM_NONE;
2486 if (bp->rx_csum &&
2487 (status & (L2_FHDR_STATUS_TCP_SEGMENT |
2488 L2_FHDR_STATUS_UDP_DATAGRAM))) {
2489
Michael Chanade2bfe2006-01-23 16:09:51 -08002490 if (likely((status & (L2_FHDR_ERRORS_TCP_XSUM |
2491 L2_FHDR_ERRORS_UDP_XSUM)) == 0))
Michael Chanb6016b72005-05-26 13:03:09 -07002492 skb->ip_summed = CHECKSUM_UNNECESSARY;
2493 }
2494
2495#ifdef BCM_VLAN
2496 if ((status & L2_FHDR_STATUS_L2_VLAN_TAG) && (bp->vlgrp != 0)) {
2497 vlan_hwaccel_receive_skb(skb, bp->vlgrp,
2498 rx_hdr->l2_fhdr_vlan_tag);
2499 }
2500 else
2501#endif
2502 netif_receive_skb(skb);
2503
2504 bp->dev->last_rx = jiffies;
2505 rx_pkt++;
2506
2507next_rx:
Michael Chanb6016b72005-05-26 13:03:09 -07002508 sw_cons = NEXT_RX_BD(sw_cons);
2509 sw_prod = NEXT_RX_BD(sw_prod);
2510
2511 if ((rx_pkt == budget))
2512 break;
Michael Chanf4e418f2005-11-04 08:53:48 -08002513
2514 /* Refresh hw_cons to see if there is new work */
2515 if (sw_cons == hw_cons) {
2516 hw_cons = bp->hw_rx_cons =
2517 sblk->status_rx_quick_consumer_index0;
2518 if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)
2519 hw_cons++;
2520 rmb();
2521 }
Michael Chanb6016b72005-05-26 13:03:09 -07002522 }
2523 bp->rx_cons = sw_cons;
2524 bp->rx_prod = sw_prod;
2525
2526 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, sw_prod);
2527
2528 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
2529
2530 mmiowb();
2531
2532 return rx_pkt;
2533
2534}
2535
2536/* MSI ISR - The only difference between this and the INTx ISR
2537 * is that the MSI interrupt is always serviced.
2538 */
2539static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002540bnx2_msi(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002541{
2542 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002543 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002544
Michael Chanc921e4c2005-09-08 13:15:32 -07002545 prefetch(bp->status_blk);
Michael Chanb6016b72005-05-26 13:03:09 -07002546 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2547 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2548 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2549
2550 /* Return here if interrupt is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002551 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2552 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002553
Michael Chan73eef4c2005-08-25 15:39:15 -07002554 netif_rx_schedule(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002555
Michael Chan73eef4c2005-08-25 15:39:15 -07002556 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002557}
2558
2559static irqreturn_t
Michael Chan8e6a72c2007-05-03 13:24:48 -07002560bnx2_msi_1shot(int irq, void *dev_instance)
2561{
2562 struct net_device *dev = dev_instance;
2563 struct bnx2 *bp = netdev_priv(dev);
2564
2565 prefetch(bp->status_blk);
2566
2567 /* Return here if interrupt is disabled. */
2568 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2569 return IRQ_HANDLED;
2570
2571 netif_rx_schedule(dev);
2572
2573 return IRQ_HANDLED;
2574}
2575
2576static irqreturn_t
David Howells7d12e782006-10-05 14:55:46 +01002577bnx2_interrupt(int irq, void *dev_instance)
Michael Chanb6016b72005-05-26 13:03:09 -07002578{
2579 struct net_device *dev = dev_instance;
Michael Chan972ec0d2006-01-23 16:12:43 -08002580 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb8a7ce72007-07-07 22:51:03 -07002581 struct status_block *sblk = bp->status_blk;
Michael Chanb6016b72005-05-26 13:03:09 -07002582
2583 /* When using INTx, it is possible for the interrupt to arrive
2584 * at the CPU before the status block posted prior to the
2585 * interrupt. Reading a register will flush the status block.
2586 * When using MSI, the MSI message will always complete after
2587 * the status block write.
2588 */
Michael Chanb8a7ce72007-07-07 22:51:03 -07002589 if ((sblk->status_idx == bp->last_status_idx) &&
Michael Chanb6016b72005-05-26 13:03:09 -07002590 (REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
2591 BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
Michael Chan73eef4c2005-08-25 15:39:15 -07002592 return IRQ_NONE;
Michael Chanb6016b72005-05-26 13:03:09 -07002593
2594 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2595 BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
2596 BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
2597
Michael Chanb8a7ce72007-07-07 22:51:03 -07002598 /* Read back to deassert IRQ immediately to avoid too many
2599 * spurious interrupts.
2600 */
2601 REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);
2602
Michael Chanb6016b72005-05-26 13:03:09 -07002603 /* Return here if interrupt is shared and is disabled. */
Michael Chan73eef4c2005-08-25 15:39:15 -07002604 if (unlikely(atomic_read(&bp->intr_sem) != 0))
2605 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002606
Michael Chanb8a7ce72007-07-07 22:51:03 -07002607 if (netif_rx_schedule_prep(dev)) {
2608 bp->last_status_idx = sblk->status_idx;
2609 __netif_rx_schedule(dev);
2610 }
Michael Chanb6016b72005-05-26 13:03:09 -07002611
Michael Chan73eef4c2005-08-25 15:39:15 -07002612 return IRQ_HANDLED;
Michael Chanb6016b72005-05-26 13:03:09 -07002613}
2614
Michael Chan0d8a6572007-07-07 22:49:43 -07002615#define STATUS_ATTN_EVENTS (STATUS_ATTN_BITS_LINK_STATE | \
2616 STATUS_ATTN_BITS_TIMER_ABORT)
Michael Chanda3e4fb2007-05-03 13:24:23 -07002617
Michael Chanf4e418f2005-11-04 08:53:48 -08002618static inline int
2619bnx2_has_work(struct bnx2 *bp)
2620{
2621 struct status_block *sblk = bp->status_blk;
2622
2623 if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) ||
2624 (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
2625 return 1;
2626
Michael Chanda3e4fb2007-05-03 13:24:23 -07002627 if ((sblk->status_attn_bits & STATUS_ATTN_EVENTS) !=
2628 (sblk->status_attn_bits_ack & STATUS_ATTN_EVENTS))
Michael Chanf4e418f2005-11-04 08:53:48 -08002629 return 1;
2630
2631 return 0;
2632}
2633
Michael Chanb6016b72005-05-26 13:03:09 -07002634static int
2635bnx2_poll(struct net_device *dev, int *budget)
2636{
Michael Chan972ec0d2006-01-23 16:12:43 -08002637 struct bnx2 *bp = netdev_priv(dev);
Michael Chanda3e4fb2007-05-03 13:24:23 -07002638 struct status_block *sblk = bp->status_blk;
2639 u32 status_attn_bits = sblk->status_attn_bits;
2640 u32 status_attn_bits_ack = sblk->status_attn_bits_ack;
Michael Chanb6016b72005-05-26 13:03:09 -07002641
Michael Chanda3e4fb2007-05-03 13:24:23 -07002642 if ((status_attn_bits & STATUS_ATTN_EVENTS) !=
2643 (status_attn_bits_ack & STATUS_ATTN_EVENTS)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002644
Michael Chanb6016b72005-05-26 13:03:09 -07002645 bnx2_phy_int(bp);
Michael Chanbf5295b2006-03-23 01:11:56 -08002646
2647 /* This is needed to take care of transient status
2648 * during link changes.
2649 */
2650 REG_WR(bp, BNX2_HC_COMMAND,
2651 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
2652 REG_RD(bp, BNX2_HC_COMMAND);
Michael Chanb6016b72005-05-26 13:03:09 -07002653 }
2654
Michael Chanf4e418f2005-11-04 08:53:48 -08002655 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
Michael Chanb6016b72005-05-26 13:03:09 -07002656 bnx2_tx_int(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07002657
Michael Chanf4e418f2005-11-04 08:53:48 -08002658 if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) {
Michael Chanb6016b72005-05-26 13:03:09 -07002659 int orig_budget = *budget;
2660 int work_done;
2661
2662 if (orig_budget > dev->quota)
2663 orig_budget = dev->quota;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002664
Michael Chanb6016b72005-05-26 13:03:09 -07002665 work_done = bnx2_rx_int(bp, orig_budget);
2666 *budget -= work_done;
2667 dev->quota -= work_done;
Michael Chanb6016b72005-05-26 13:03:09 -07002668 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04002669
Michael Chanf4e418f2005-11-04 08:53:48 -08002670 bp->last_status_idx = bp->status_blk->status_idx;
2671 rmb();
2672
2673 if (!bnx2_has_work(bp)) {
Michael Chanb6016b72005-05-26 13:03:09 -07002674 netif_rx_complete(dev);
Michael Chan1269a8a2006-01-23 16:11:03 -08002675 if (likely(bp->flags & USING_MSI_FLAG)) {
2676 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2677 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2678 bp->last_status_idx);
2679 return 0;
2680 }
Michael Chanb6016b72005-05-26 13:03:09 -07002681 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
Michael Chan1269a8a2006-01-23 16:11:03 -08002682 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2683 BNX2_PCICFG_INT_ACK_CMD_MASK_INT |
2684 bp->last_status_idx);
2685
2686 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
2687 BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
2688 bp->last_status_idx);
Michael Chanb6016b72005-05-26 13:03:09 -07002689 return 0;
2690 }
2691
2692 return 1;
2693}
2694
Herbert Xu932ff272006-06-09 12:20:56 -07002695/* Called with rtnl_lock from vlan functions and also netif_tx_lock
Michael Chanb6016b72005-05-26 13:03:09 -07002696 * from set_multicast.
2697 */
2698static void
2699bnx2_set_rx_mode(struct net_device *dev)
2700{
Michael Chan972ec0d2006-01-23 16:12:43 -08002701 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07002702 u32 rx_mode, sort_mode;
2703 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07002704
Michael Chanc770a652005-08-25 15:38:39 -07002705 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002706
2707 rx_mode = bp->rx_mode & ~(BNX2_EMAC_RX_MODE_PROMISCUOUS |
2708 BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG);
2709 sort_mode = 1 | BNX2_RPM_SORT_USER0_BC_EN;
2710#ifdef BCM_VLAN
Michael Chane29054f2006-01-23 16:06:06 -08002711 if (!bp->vlgrp && !(bp->flags & ASF_ENABLE_FLAG))
Michael Chanb6016b72005-05-26 13:03:09 -07002712 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002713#else
Michael Chane29054f2006-01-23 16:06:06 -08002714 if (!(bp->flags & ASF_ENABLE_FLAG))
2715 rx_mode |= BNX2_EMAC_RX_MODE_KEEP_VLAN_TAG;
Michael Chanb6016b72005-05-26 13:03:09 -07002716#endif
2717 if (dev->flags & IFF_PROMISC) {
2718 /* Promiscuous mode. */
2719 rx_mode |= BNX2_EMAC_RX_MODE_PROMISCUOUS;
Michael Chan75108732006-11-19 14:06:40 -08002720 sort_mode |= BNX2_RPM_SORT_USER0_PROM_EN |
2721 BNX2_RPM_SORT_USER0_PROM_VLAN;
Michael Chanb6016b72005-05-26 13:03:09 -07002722 }
2723 else if (dev->flags & IFF_ALLMULTI) {
2724 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2725 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2726 0xffffffff);
2727 }
2728 sort_mode |= BNX2_RPM_SORT_USER0_MC_EN;
2729 }
2730 else {
2731 /* Accept one or more multicast(s). */
2732 struct dev_mc_list *mclist;
2733 u32 mc_filter[NUM_MC_HASH_REGISTERS];
2734 u32 regidx;
2735 u32 bit;
2736 u32 crc;
2737
2738 memset(mc_filter, 0, 4 * NUM_MC_HASH_REGISTERS);
2739
2740 for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
2741 i++, mclist = mclist->next) {
2742
2743 crc = ether_crc_le(ETH_ALEN, mclist->dmi_addr);
2744 bit = crc & 0xff;
2745 regidx = (bit & 0xe0) >> 5;
2746 bit &= 0x1f;
2747 mc_filter[regidx] |= (1 << bit);
2748 }
2749
2750 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
2751 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
2752 mc_filter[i]);
2753 }
2754
2755 sort_mode |= BNX2_RPM_SORT_USER0_MC_HSH_EN;
2756 }
2757
2758 if (rx_mode != bp->rx_mode) {
2759 bp->rx_mode = rx_mode;
2760 REG_WR(bp, BNX2_EMAC_RX_MODE, rx_mode);
2761 }
2762
2763 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
2764 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode);
2765 REG_WR(bp, BNX2_RPM_SORT_USER0, sort_mode | BNX2_RPM_SORT_USER0_ENA);
2766
Michael Chanc770a652005-08-25 15:38:39 -07002767 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07002768}
2769
Michael Chanfba9fe92006-06-12 22:21:25 -07002770#define FW_BUF_SIZE 0x8000
2771
2772static int
2773bnx2_gunzip_init(struct bnx2 *bp)
2774{
2775 if ((bp->gunzip_buf = vmalloc(FW_BUF_SIZE)) == NULL)
2776 goto gunzip_nomem1;
2777
2778 if ((bp->strm = kmalloc(sizeof(*bp->strm), GFP_KERNEL)) == NULL)
2779 goto gunzip_nomem2;
2780
2781 bp->strm->workspace = kmalloc(zlib_inflate_workspacesize(), GFP_KERNEL);
2782 if (bp->strm->workspace == NULL)
2783 goto gunzip_nomem3;
2784
2785 return 0;
2786
2787gunzip_nomem3:
2788 kfree(bp->strm);
2789 bp->strm = NULL;
2790
2791gunzip_nomem2:
2792 vfree(bp->gunzip_buf);
2793 bp->gunzip_buf = NULL;
2794
2795gunzip_nomem1:
2796 printk(KERN_ERR PFX "%s: Cannot allocate firmware buffer for "
2797 "uncompression.\n", bp->dev->name);
2798 return -ENOMEM;
2799}
2800
2801static void
2802bnx2_gunzip_end(struct bnx2 *bp)
2803{
2804 kfree(bp->strm->workspace);
2805
2806 kfree(bp->strm);
2807 bp->strm = NULL;
2808
2809 if (bp->gunzip_buf) {
2810 vfree(bp->gunzip_buf);
2811 bp->gunzip_buf = NULL;
2812 }
2813}
2814
2815static int
2816bnx2_gunzip(struct bnx2 *bp, u8 *zbuf, int len, void **outbuf, int *outlen)
2817{
2818 int n, rc;
2819
2820 /* check gzip header */
2821 if ((zbuf[0] != 0x1f) || (zbuf[1] != 0x8b) || (zbuf[2] != Z_DEFLATED))
2822 return -EINVAL;
2823
2824 n = 10;
2825
2826#define FNAME 0x8
2827 if (zbuf[3] & FNAME)
2828 while ((zbuf[n++] != 0) && (n < len));
2829
2830 bp->strm->next_in = zbuf + n;
2831 bp->strm->avail_in = len - n;
2832 bp->strm->next_out = bp->gunzip_buf;
2833 bp->strm->avail_out = FW_BUF_SIZE;
2834
2835 rc = zlib_inflateInit2(bp->strm, -MAX_WBITS);
2836 if (rc != Z_OK)
2837 return rc;
2838
2839 rc = zlib_inflate(bp->strm, Z_FINISH);
2840
2841 *outlen = FW_BUF_SIZE - bp->strm->avail_out;
2842 *outbuf = bp->gunzip_buf;
2843
2844 if ((rc != Z_OK) && (rc != Z_STREAM_END))
2845 printk(KERN_ERR PFX "%s: Firmware decompression error: %s\n",
2846 bp->dev->name, bp->strm->msg);
2847
2848 zlib_inflateEnd(bp->strm);
2849
2850 if (rc == Z_STREAM_END)
2851 return 0;
2852
2853 return rc;
2854}
2855
Michael Chanb6016b72005-05-26 13:03:09 -07002856static void
2857load_rv2p_fw(struct bnx2 *bp, u32 *rv2p_code, u32 rv2p_code_len,
2858 u32 rv2p_proc)
2859{
2860 int i;
2861 u32 val;
2862
2863
2864 for (i = 0; i < rv2p_code_len; i += 8) {
Michael Chanfba9fe92006-06-12 22:21:25 -07002865 REG_WR(bp, BNX2_RV2P_INSTR_HIGH, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07002866 rv2p_code++;
Michael Chanfba9fe92006-06-12 22:21:25 -07002867 REG_WR(bp, BNX2_RV2P_INSTR_LOW, cpu_to_le32(*rv2p_code));
Michael Chanb6016b72005-05-26 13:03:09 -07002868 rv2p_code++;
2869
2870 if (rv2p_proc == RV2P_PROC1) {
2871 val = (i / 8) | BNX2_RV2P_PROC1_ADDR_CMD_RDWR;
2872 REG_WR(bp, BNX2_RV2P_PROC1_ADDR_CMD, val);
2873 }
2874 else {
2875 val = (i / 8) | BNX2_RV2P_PROC2_ADDR_CMD_RDWR;
2876 REG_WR(bp, BNX2_RV2P_PROC2_ADDR_CMD, val);
2877 }
2878 }
2879
2880 /* Reset the processor, un-stall is done later. */
2881 if (rv2p_proc == RV2P_PROC1) {
2882 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC1_RESET);
2883 }
2884 else {
2885 REG_WR(bp, BNX2_RV2P_COMMAND, BNX2_RV2P_COMMAND_PROC2_RESET);
2886 }
2887}
2888
Michael Chanaf3ee512006-11-19 14:09:25 -08002889static int
Michael Chanb6016b72005-05-26 13:03:09 -07002890load_cpu_fw(struct bnx2 *bp, struct cpu_reg *cpu_reg, struct fw_info *fw)
2891{
2892 u32 offset;
2893 u32 val;
Michael Chanaf3ee512006-11-19 14:09:25 -08002894 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07002895
2896 /* Halt the CPU. */
2897 val = REG_RD_IND(bp, cpu_reg->mode);
2898 val |= cpu_reg->mode_value_halt;
2899 REG_WR_IND(bp, cpu_reg->mode, val);
2900 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
2901
2902 /* Load the Text area. */
2903 offset = cpu_reg->spad_base + (fw->text_addr - cpu_reg->mips_view_base);
Michael Chanaf3ee512006-11-19 14:09:25 -08002904 if (fw->gz_text) {
2905 u32 text_len;
2906 void *text;
2907
2908 rc = bnx2_gunzip(bp, fw->gz_text, fw->gz_text_len, &text,
2909 &text_len);
2910 if (rc)
2911 return rc;
2912
2913 fw->text = text;
2914 }
2915 if (fw->gz_text) {
Michael Chanb6016b72005-05-26 13:03:09 -07002916 int j;
2917
2918 for (j = 0; j < (fw->text_len / 4); j++, offset += 4) {
Michael Chanfba9fe92006-06-12 22:21:25 -07002919 REG_WR_IND(bp, offset, cpu_to_le32(fw->text[j]));
Michael Chanb6016b72005-05-26 13:03:09 -07002920 }
2921 }
2922
2923 /* Load the Data area. */
2924 offset = cpu_reg->spad_base + (fw->data_addr - cpu_reg->mips_view_base);
2925 if (fw->data) {
2926 int j;
2927
2928 for (j = 0; j < (fw->data_len / 4); j++, offset += 4) {
2929 REG_WR_IND(bp, offset, fw->data[j]);
2930 }
2931 }
2932
2933 /* Load the SBSS area. */
2934 offset = cpu_reg->spad_base + (fw->sbss_addr - cpu_reg->mips_view_base);
2935 if (fw->sbss) {
2936 int j;
2937
2938 for (j = 0; j < (fw->sbss_len / 4); j++, offset += 4) {
2939 REG_WR_IND(bp, offset, fw->sbss[j]);
2940 }
2941 }
2942
2943 /* Load the BSS area. */
2944 offset = cpu_reg->spad_base + (fw->bss_addr - cpu_reg->mips_view_base);
2945 if (fw->bss) {
2946 int j;
2947
2948 for (j = 0; j < (fw->bss_len/4); j++, offset += 4) {
2949 REG_WR_IND(bp, offset, fw->bss[j]);
2950 }
2951 }
2952
2953 /* Load the Read-Only area. */
2954 offset = cpu_reg->spad_base +
2955 (fw->rodata_addr - cpu_reg->mips_view_base);
2956 if (fw->rodata) {
2957 int j;
2958
2959 for (j = 0; j < (fw->rodata_len / 4); j++, offset += 4) {
2960 REG_WR_IND(bp, offset, fw->rodata[j]);
2961 }
2962 }
2963
2964 /* Clear the pre-fetch instruction. */
2965 REG_WR_IND(bp, cpu_reg->inst, 0);
2966 REG_WR_IND(bp, cpu_reg->pc, fw->start_addr);
2967
2968 /* Start the CPU. */
2969 val = REG_RD_IND(bp, cpu_reg->mode);
2970 val &= ~cpu_reg->mode_value_halt;
2971 REG_WR_IND(bp, cpu_reg->state, cpu_reg->state_value_clear);
2972 REG_WR_IND(bp, cpu_reg->mode, val);
Michael Chanaf3ee512006-11-19 14:09:25 -08002973
2974 return 0;
Michael Chanb6016b72005-05-26 13:03:09 -07002975}
2976
Michael Chanfba9fe92006-06-12 22:21:25 -07002977static int
Michael Chanb6016b72005-05-26 13:03:09 -07002978bnx2_init_cpus(struct bnx2 *bp)
2979{
2980 struct cpu_reg cpu_reg;
Michael Chanaf3ee512006-11-19 14:09:25 -08002981 struct fw_info *fw;
Michael Chanfba9fe92006-06-12 22:21:25 -07002982 int rc = 0;
2983 void *text;
2984 u32 text_len;
2985
2986 if ((rc = bnx2_gunzip_init(bp)) != 0)
2987 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07002988
2989 /* Initialize the RV2P processor. */
Michael Chanfba9fe92006-06-12 22:21:25 -07002990 rc = bnx2_gunzip(bp, bnx2_rv2p_proc1, sizeof(bnx2_rv2p_proc1), &text,
2991 &text_len);
2992 if (rc)
2993 goto init_cpu_err;
2994
2995 load_rv2p_fw(bp, text, text_len, RV2P_PROC1);
2996
2997 rc = bnx2_gunzip(bp, bnx2_rv2p_proc2, sizeof(bnx2_rv2p_proc2), &text,
2998 &text_len);
2999 if (rc)
3000 goto init_cpu_err;
3001
3002 load_rv2p_fw(bp, text, text_len, RV2P_PROC2);
Michael Chanb6016b72005-05-26 13:03:09 -07003003
3004 /* Initialize the RX Processor. */
3005 cpu_reg.mode = BNX2_RXP_CPU_MODE;
3006 cpu_reg.mode_value_halt = BNX2_RXP_CPU_MODE_SOFT_HALT;
3007 cpu_reg.mode_value_sstep = BNX2_RXP_CPU_MODE_STEP_ENA;
3008 cpu_reg.state = BNX2_RXP_CPU_STATE;
3009 cpu_reg.state_value_clear = 0xffffff;
3010 cpu_reg.gpr0 = BNX2_RXP_CPU_REG_FILE;
3011 cpu_reg.evmask = BNX2_RXP_CPU_EVENT_MASK;
3012 cpu_reg.pc = BNX2_RXP_CPU_PROGRAM_COUNTER;
3013 cpu_reg.inst = BNX2_RXP_CPU_INSTRUCTION;
3014 cpu_reg.bp = BNX2_RXP_CPU_HW_BREAKPOINT;
3015 cpu_reg.spad_base = BNX2_RXP_SCRATCH;
3016 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003017
Michael Chand43584c2006-11-19 14:14:35 -08003018 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3019 fw = &bnx2_rxp_fw_09;
3020 else
3021 fw = &bnx2_rxp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003022
Michael Chanaf3ee512006-11-19 14:09:25 -08003023 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003024 if (rc)
3025 goto init_cpu_err;
3026
Michael Chanb6016b72005-05-26 13:03:09 -07003027 /* Initialize the TX Processor. */
3028 cpu_reg.mode = BNX2_TXP_CPU_MODE;
3029 cpu_reg.mode_value_halt = BNX2_TXP_CPU_MODE_SOFT_HALT;
3030 cpu_reg.mode_value_sstep = BNX2_TXP_CPU_MODE_STEP_ENA;
3031 cpu_reg.state = BNX2_TXP_CPU_STATE;
3032 cpu_reg.state_value_clear = 0xffffff;
3033 cpu_reg.gpr0 = BNX2_TXP_CPU_REG_FILE;
3034 cpu_reg.evmask = BNX2_TXP_CPU_EVENT_MASK;
3035 cpu_reg.pc = BNX2_TXP_CPU_PROGRAM_COUNTER;
3036 cpu_reg.inst = BNX2_TXP_CPU_INSTRUCTION;
3037 cpu_reg.bp = BNX2_TXP_CPU_HW_BREAKPOINT;
3038 cpu_reg.spad_base = BNX2_TXP_SCRATCH;
3039 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003040
Michael Chand43584c2006-11-19 14:14:35 -08003041 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3042 fw = &bnx2_txp_fw_09;
3043 else
3044 fw = &bnx2_txp_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003045
Michael Chanaf3ee512006-11-19 14:09:25 -08003046 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003047 if (rc)
3048 goto init_cpu_err;
3049
Michael Chanb6016b72005-05-26 13:03:09 -07003050 /* Initialize the TX Patch-up Processor. */
3051 cpu_reg.mode = BNX2_TPAT_CPU_MODE;
3052 cpu_reg.mode_value_halt = BNX2_TPAT_CPU_MODE_SOFT_HALT;
3053 cpu_reg.mode_value_sstep = BNX2_TPAT_CPU_MODE_STEP_ENA;
3054 cpu_reg.state = BNX2_TPAT_CPU_STATE;
3055 cpu_reg.state_value_clear = 0xffffff;
3056 cpu_reg.gpr0 = BNX2_TPAT_CPU_REG_FILE;
3057 cpu_reg.evmask = BNX2_TPAT_CPU_EVENT_MASK;
3058 cpu_reg.pc = BNX2_TPAT_CPU_PROGRAM_COUNTER;
3059 cpu_reg.inst = BNX2_TPAT_CPU_INSTRUCTION;
3060 cpu_reg.bp = BNX2_TPAT_CPU_HW_BREAKPOINT;
3061 cpu_reg.spad_base = BNX2_TPAT_SCRATCH;
3062 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003063
Michael Chand43584c2006-11-19 14:14:35 -08003064 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3065 fw = &bnx2_tpat_fw_09;
3066 else
3067 fw = &bnx2_tpat_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003068
Michael Chanaf3ee512006-11-19 14:09:25 -08003069 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003070 if (rc)
3071 goto init_cpu_err;
3072
Michael Chanb6016b72005-05-26 13:03:09 -07003073 /* Initialize the Completion Processor. */
3074 cpu_reg.mode = BNX2_COM_CPU_MODE;
3075 cpu_reg.mode_value_halt = BNX2_COM_CPU_MODE_SOFT_HALT;
3076 cpu_reg.mode_value_sstep = BNX2_COM_CPU_MODE_STEP_ENA;
3077 cpu_reg.state = BNX2_COM_CPU_STATE;
3078 cpu_reg.state_value_clear = 0xffffff;
3079 cpu_reg.gpr0 = BNX2_COM_CPU_REG_FILE;
3080 cpu_reg.evmask = BNX2_COM_CPU_EVENT_MASK;
3081 cpu_reg.pc = BNX2_COM_CPU_PROGRAM_COUNTER;
3082 cpu_reg.inst = BNX2_COM_CPU_INSTRUCTION;
3083 cpu_reg.bp = BNX2_COM_CPU_HW_BREAKPOINT;
3084 cpu_reg.spad_base = BNX2_COM_SCRATCH;
3085 cpu_reg.mips_view_base = 0x8000000;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003086
Michael Chand43584c2006-11-19 14:14:35 -08003087 if (CHIP_NUM(bp) == CHIP_NUM_5709)
3088 fw = &bnx2_com_fw_09;
3089 else
3090 fw = &bnx2_com_fw_06;
Michael Chanb6016b72005-05-26 13:03:09 -07003091
Michael Chanaf3ee512006-11-19 14:09:25 -08003092 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chanfba9fe92006-06-12 22:21:25 -07003093 if (rc)
3094 goto init_cpu_err;
3095
Michael Chand43584c2006-11-19 14:14:35 -08003096 /* Initialize the Command Processor. */
3097 cpu_reg.mode = BNX2_CP_CPU_MODE;
3098 cpu_reg.mode_value_halt = BNX2_CP_CPU_MODE_SOFT_HALT;
3099 cpu_reg.mode_value_sstep = BNX2_CP_CPU_MODE_STEP_ENA;
3100 cpu_reg.state = BNX2_CP_CPU_STATE;
3101 cpu_reg.state_value_clear = 0xffffff;
3102 cpu_reg.gpr0 = BNX2_CP_CPU_REG_FILE;
3103 cpu_reg.evmask = BNX2_CP_CPU_EVENT_MASK;
3104 cpu_reg.pc = BNX2_CP_CPU_PROGRAM_COUNTER;
3105 cpu_reg.inst = BNX2_CP_CPU_INSTRUCTION;
3106 cpu_reg.bp = BNX2_CP_CPU_HW_BREAKPOINT;
3107 cpu_reg.spad_base = BNX2_CP_SCRATCH;
3108 cpu_reg.mips_view_base = 0x8000000;
Michael Chanb6016b72005-05-26 13:03:09 -07003109
Michael Chand43584c2006-11-19 14:14:35 -08003110 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3111 fw = &bnx2_cp_fw_09;
Michael Chanb6016b72005-05-26 13:03:09 -07003112
Adrian Bunk6c1bbcc2006-12-07 15:10:06 -08003113 rc = load_cpu_fw(bp, &cpu_reg, fw);
Michael Chand43584c2006-11-19 14:14:35 -08003114 if (rc)
3115 goto init_cpu_err;
3116 }
Michael Chanfba9fe92006-06-12 22:21:25 -07003117init_cpu_err:
3118 bnx2_gunzip_end(bp);
3119 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003120}
3121
3122static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07003123bnx2_set_power_state(struct bnx2 *bp, pci_power_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07003124{
3125 u16 pmcsr;
3126
3127 pci_read_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL, &pmcsr);
3128
3129 switch (state) {
Pavel Machek829ca9a2005-09-03 15:56:56 -07003130 case PCI_D0: {
Michael Chanb6016b72005-05-26 13:03:09 -07003131 u32 val;
3132
3133 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3134 (pmcsr & ~PCI_PM_CTRL_STATE_MASK) |
3135 PCI_PM_CTRL_PME_STATUS);
3136
3137 if (pmcsr & PCI_PM_CTRL_STATE_MASK)
3138 /* delay required during transition out of D3hot */
3139 msleep(20);
3140
3141 val = REG_RD(bp, BNX2_EMAC_MODE);
3142 val |= BNX2_EMAC_MODE_MPKT_RCVD | BNX2_EMAC_MODE_ACPI_RCVD;
3143 val &= ~BNX2_EMAC_MODE_MPKT;
3144 REG_WR(bp, BNX2_EMAC_MODE, val);
3145
3146 val = REG_RD(bp, BNX2_RPM_CONFIG);
3147 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3148 REG_WR(bp, BNX2_RPM_CONFIG, val);
3149 break;
3150 }
Pavel Machek829ca9a2005-09-03 15:56:56 -07003151 case PCI_D3hot: {
Michael Chanb6016b72005-05-26 13:03:09 -07003152 int i;
3153 u32 val, wol_msg;
3154
3155 if (bp->wol) {
3156 u32 advertising;
3157 u8 autoneg;
3158
3159 autoneg = bp->autoneg;
3160 advertising = bp->advertising;
3161
3162 bp->autoneg = AUTONEG_SPEED;
3163 bp->advertising = ADVERTISED_10baseT_Half |
3164 ADVERTISED_10baseT_Full |
3165 ADVERTISED_100baseT_Half |
3166 ADVERTISED_100baseT_Full |
3167 ADVERTISED_Autoneg;
3168
3169 bnx2_setup_copper_phy(bp);
3170
3171 bp->autoneg = autoneg;
3172 bp->advertising = advertising;
3173
3174 bnx2_set_mac_addr(bp);
3175
3176 val = REG_RD(bp, BNX2_EMAC_MODE);
3177
3178 /* Enable port mode. */
3179 val &= ~BNX2_EMAC_MODE_PORT;
3180 val |= BNX2_EMAC_MODE_PORT_MII |
3181 BNX2_EMAC_MODE_MPKT_RCVD |
3182 BNX2_EMAC_MODE_ACPI_RCVD |
Michael Chanb6016b72005-05-26 13:03:09 -07003183 BNX2_EMAC_MODE_MPKT;
3184
3185 REG_WR(bp, BNX2_EMAC_MODE, val);
3186
3187 /* receive all multicast */
3188 for (i = 0; i < NUM_MC_HASH_REGISTERS; i++) {
3189 REG_WR(bp, BNX2_EMAC_MULTICAST_HASH0 + (i * 4),
3190 0xffffffff);
3191 }
3192 REG_WR(bp, BNX2_EMAC_RX_MODE,
3193 BNX2_EMAC_RX_MODE_SORT_MODE);
3194
3195 val = 1 | BNX2_RPM_SORT_USER0_BC_EN |
3196 BNX2_RPM_SORT_USER0_MC_EN;
3197 REG_WR(bp, BNX2_RPM_SORT_USER0, 0x0);
3198 REG_WR(bp, BNX2_RPM_SORT_USER0, val);
3199 REG_WR(bp, BNX2_RPM_SORT_USER0, val |
3200 BNX2_RPM_SORT_USER0_ENA);
3201
3202 /* Need to enable EMAC and RPM for WOL. */
3203 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
3204 BNX2_MISC_ENABLE_SET_BITS_RX_PARSER_MAC_ENABLE |
3205 BNX2_MISC_ENABLE_SET_BITS_TX_HEADER_Q_ENABLE |
3206 BNX2_MISC_ENABLE_SET_BITS_EMAC_ENABLE);
3207
3208 val = REG_RD(bp, BNX2_RPM_CONFIG);
3209 val &= ~BNX2_RPM_CONFIG_ACPI_ENA;
3210 REG_WR(bp, BNX2_RPM_CONFIG, val);
3211
3212 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
3213 }
3214 else {
3215 wol_msg = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
3216 }
3217
Michael Chandda1e392006-01-23 16:08:14 -08003218 if (!(bp->flags & NO_WOL_FLAG))
3219 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT3 | wol_msg, 0);
Michael Chanb6016b72005-05-26 13:03:09 -07003220
3221 pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
3222 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3223 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3224
3225 if (bp->wol)
3226 pmcsr |= 3;
3227 }
3228 else {
3229 pmcsr |= 3;
3230 }
3231 if (bp->wol) {
3232 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
3233 }
3234 pci_write_config_word(bp->pdev, bp->pm_cap + PCI_PM_CTRL,
3235 pmcsr);
3236
3237 /* No more memory access after this point until
3238 * device is brought back to D0.
3239 */
3240 udelay(50);
3241 break;
3242 }
3243 default:
3244 return -EINVAL;
3245 }
3246 return 0;
3247}
3248
3249static int
3250bnx2_acquire_nvram_lock(struct bnx2 *bp)
3251{
3252 u32 val;
3253 int j;
3254
3255 /* Request access to the flash interface. */
3256 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_SET2);
3257 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3258 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3259 if (val & BNX2_NVM_SW_ARB_ARB_ARB2)
3260 break;
3261
3262 udelay(5);
3263 }
3264
3265 if (j >= NVRAM_TIMEOUT_COUNT)
3266 return -EBUSY;
3267
3268 return 0;
3269}
3270
3271static int
3272bnx2_release_nvram_lock(struct bnx2 *bp)
3273{
3274 int j;
3275 u32 val;
3276
3277 /* Relinquish nvram interface. */
3278 REG_WR(bp, BNX2_NVM_SW_ARB, BNX2_NVM_SW_ARB_ARB_REQ_CLR2);
3279
3280 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3281 val = REG_RD(bp, BNX2_NVM_SW_ARB);
3282 if (!(val & BNX2_NVM_SW_ARB_ARB_ARB2))
3283 break;
3284
3285 udelay(5);
3286 }
3287
3288 if (j >= NVRAM_TIMEOUT_COUNT)
3289 return -EBUSY;
3290
3291 return 0;
3292}
3293
3294
3295static int
3296bnx2_enable_nvram_write(struct bnx2 *bp)
3297{
3298 u32 val;
3299
3300 val = REG_RD(bp, BNX2_MISC_CFG);
3301 REG_WR(bp, BNX2_MISC_CFG, val | BNX2_MISC_CFG_NVM_WR_EN_PCI);
3302
Michael Chane30372c2007-07-16 18:26:23 -07003303 if (bp->flash_info->flags & BNX2_NV_WREN) {
Michael Chanb6016b72005-05-26 13:03:09 -07003304 int j;
3305
3306 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3307 REG_WR(bp, BNX2_NVM_COMMAND,
3308 BNX2_NVM_COMMAND_WREN | BNX2_NVM_COMMAND_DOIT);
3309
3310 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3311 udelay(5);
3312
3313 val = REG_RD(bp, BNX2_NVM_COMMAND);
3314 if (val & BNX2_NVM_COMMAND_DONE)
3315 break;
3316 }
3317
3318 if (j >= NVRAM_TIMEOUT_COUNT)
3319 return -EBUSY;
3320 }
3321 return 0;
3322}
3323
3324static void
3325bnx2_disable_nvram_write(struct bnx2 *bp)
3326{
3327 u32 val;
3328
3329 val = REG_RD(bp, BNX2_MISC_CFG);
3330 REG_WR(bp, BNX2_MISC_CFG, val & ~BNX2_MISC_CFG_NVM_WR_EN);
3331}
3332
3333
3334static void
3335bnx2_enable_nvram_access(struct bnx2 *bp)
3336{
3337 u32 val;
3338
3339 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3340 /* Enable both bits, even on read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003341 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003342 val | BNX2_NVM_ACCESS_ENABLE_EN | BNX2_NVM_ACCESS_ENABLE_WR_EN);
3343}
3344
3345static void
3346bnx2_disable_nvram_access(struct bnx2 *bp)
3347{
3348 u32 val;
3349
3350 val = REG_RD(bp, BNX2_NVM_ACCESS_ENABLE);
3351 /* Disable both bits, even after read. */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003352 REG_WR(bp, BNX2_NVM_ACCESS_ENABLE,
Michael Chanb6016b72005-05-26 13:03:09 -07003353 val & ~(BNX2_NVM_ACCESS_ENABLE_EN |
3354 BNX2_NVM_ACCESS_ENABLE_WR_EN));
3355}
3356
3357static int
3358bnx2_nvram_erase_page(struct bnx2 *bp, u32 offset)
3359{
3360 u32 cmd;
3361 int j;
3362
Michael Chane30372c2007-07-16 18:26:23 -07003363 if (bp->flash_info->flags & BNX2_NV_BUFFERED)
Michael Chanb6016b72005-05-26 13:03:09 -07003364 /* Buffered flash, no erase needed */
3365 return 0;
3366
3367 /* Build an erase command */
3368 cmd = BNX2_NVM_COMMAND_ERASE | BNX2_NVM_COMMAND_WR |
3369 BNX2_NVM_COMMAND_DOIT;
3370
3371 /* Need to clear DONE bit separately. */
3372 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3373
3374 /* Address of the NVRAM to read from. */
3375 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3376
3377 /* Issue an erase command. */
3378 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3379
3380 /* Wait for completion. */
3381 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3382 u32 val;
3383
3384 udelay(5);
3385
3386 val = REG_RD(bp, BNX2_NVM_COMMAND);
3387 if (val & BNX2_NVM_COMMAND_DONE)
3388 break;
3389 }
3390
3391 if (j >= NVRAM_TIMEOUT_COUNT)
3392 return -EBUSY;
3393
3394 return 0;
3395}
3396
3397static int
3398bnx2_nvram_read_dword(struct bnx2 *bp, u32 offset, u8 *ret_val, u32 cmd_flags)
3399{
3400 u32 cmd;
3401 int j;
3402
3403 /* Build the command word. */
3404 cmd = BNX2_NVM_COMMAND_DOIT | cmd_flags;
3405
Michael Chane30372c2007-07-16 18:26:23 -07003406 /* Calculate an offset of a buffered flash, not needed for 5709. */
3407 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003408 offset = ((offset / bp->flash_info->page_size) <<
3409 bp->flash_info->page_bits) +
3410 (offset % bp->flash_info->page_size);
3411 }
3412
3413 /* Need to clear DONE bit separately. */
3414 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3415
3416 /* Address of the NVRAM to read from. */
3417 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3418
3419 /* Issue a read command. */
3420 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3421
3422 /* Wait for completion. */
3423 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3424 u32 val;
3425
3426 udelay(5);
3427
3428 val = REG_RD(bp, BNX2_NVM_COMMAND);
3429 if (val & BNX2_NVM_COMMAND_DONE) {
3430 val = REG_RD(bp, BNX2_NVM_READ);
3431
3432 val = be32_to_cpu(val);
3433 memcpy(ret_val, &val, 4);
3434 break;
3435 }
3436 }
3437 if (j >= NVRAM_TIMEOUT_COUNT)
3438 return -EBUSY;
3439
3440 return 0;
3441}
3442
3443
3444static int
3445bnx2_nvram_write_dword(struct bnx2 *bp, u32 offset, u8 *val, u32 cmd_flags)
3446{
3447 u32 cmd, val32;
3448 int j;
3449
3450 /* Build the command word. */
3451 cmd = BNX2_NVM_COMMAND_DOIT | BNX2_NVM_COMMAND_WR | cmd_flags;
3452
Michael Chane30372c2007-07-16 18:26:23 -07003453 /* Calculate an offset of a buffered flash, not needed for 5709. */
3454 if (bp->flash_info->flags & BNX2_NV_TRANSLATE) {
Michael Chanb6016b72005-05-26 13:03:09 -07003455 offset = ((offset / bp->flash_info->page_size) <<
3456 bp->flash_info->page_bits) +
3457 (offset % bp->flash_info->page_size);
3458 }
3459
3460 /* Need to clear DONE bit separately. */
3461 REG_WR(bp, BNX2_NVM_COMMAND, BNX2_NVM_COMMAND_DONE);
3462
3463 memcpy(&val32, val, 4);
3464 val32 = cpu_to_be32(val32);
3465
3466 /* Write the data. */
3467 REG_WR(bp, BNX2_NVM_WRITE, val32);
3468
3469 /* Address of the NVRAM to write to. */
3470 REG_WR(bp, BNX2_NVM_ADDR, offset & BNX2_NVM_ADDR_NVM_ADDR_VALUE);
3471
3472 /* Issue the write command. */
3473 REG_WR(bp, BNX2_NVM_COMMAND, cmd);
3474
3475 /* Wait for completion. */
3476 for (j = 0; j < NVRAM_TIMEOUT_COUNT; j++) {
3477 udelay(5);
3478
3479 if (REG_RD(bp, BNX2_NVM_COMMAND) & BNX2_NVM_COMMAND_DONE)
3480 break;
3481 }
3482 if (j >= NVRAM_TIMEOUT_COUNT)
3483 return -EBUSY;
3484
3485 return 0;
3486}
3487
3488static int
3489bnx2_init_nvram(struct bnx2 *bp)
3490{
3491 u32 val;
Michael Chane30372c2007-07-16 18:26:23 -07003492 int j, entry_count, rc = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07003493 struct flash_spec *flash;
3494
Michael Chane30372c2007-07-16 18:26:23 -07003495 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3496 bp->flash_info = &flash_5709;
3497 goto get_flash_size;
3498 }
3499
Michael Chanb6016b72005-05-26 13:03:09 -07003500 /* Determine the selected interface. */
3501 val = REG_RD(bp, BNX2_NVM_CFG1);
3502
3503 entry_count = sizeof(flash_table) / sizeof(struct flash_spec);
3504
Michael Chanb6016b72005-05-26 13:03:09 -07003505 if (val & 0x40000000) {
3506
3507 /* Flash interface has been reconfigured */
3508 for (j = 0, flash = &flash_table[0]; j < entry_count;
Michael Chan37137702005-11-04 08:49:17 -08003509 j++, flash++) {
3510 if ((val & FLASH_BACKUP_STRAP_MASK) ==
3511 (flash->config1 & FLASH_BACKUP_STRAP_MASK)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003512 bp->flash_info = flash;
3513 break;
3514 }
3515 }
3516 }
3517 else {
Michael Chan37137702005-11-04 08:49:17 -08003518 u32 mask;
Michael Chanb6016b72005-05-26 13:03:09 -07003519 /* Not yet been reconfigured */
3520
Michael Chan37137702005-11-04 08:49:17 -08003521 if (val & (1 << 23))
3522 mask = FLASH_BACKUP_STRAP_MASK;
3523 else
3524 mask = FLASH_STRAP_MASK;
3525
Michael Chanb6016b72005-05-26 13:03:09 -07003526 for (j = 0, flash = &flash_table[0]; j < entry_count;
3527 j++, flash++) {
3528
Michael Chan37137702005-11-04 08:49:17 -08003529 if ((val & mask) == (flash->strapping & mask)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003530 bp->flash_info = flash;
3531
3532 /* Request access to the flash interface. */
3533 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3534 return rc;
3535
3536 /* Enable access to flash interface */
3537 bnx2_enable_nvram_access(bp);
3538
3539 /* Reconfigure the flash interface */
3540 REG_WR(bp, BNX2_NVM_CFG1, flash->config1);
3541 REG_WR(bp, BNX2_NVM_CFG2, flash->config2);
3542 REG_WR(bp, BNX2_NVM_CFG3, flash->config3);
3543 REG_WR(bp, BNX2_NVM_WRITE1, flash->write1);
3544
3545 /* Disable access to flash interface */
3546 bnx2_disable_nvram_access(bp);
3547 bnx2_release_nvram_lock(bp);
3548
3549 break;
3550 }
3551 }
3552 } /* if (val & 0x40000000) */
3553
3554 if (j == entry_count) {
3555 bp->flash_info = NULL;
John W. Linville2f23c522005-11-10 12:57:33 -08003556 printk(KERN_ALERT PFX "Unknown flash/EEPROM type.\n");
Michael Chan1122db72006-01-23 16:11:42 -08003557 return -ENODEV;
Michael Chanb6016b72005-05-26 13:03:09 -07003558 }
3559
Michael Chane30372c2007-07-16 18:26:23 -07003560get_flash_size:
Michael Chan1122db72006-01-23 16:11:42 -08003561 val = REG_RD_IND(bp, bp->shmem_base + BNX2_SHARED_HW_CFG_CONFIG2);
3562 val &= BNX2_SHARED_HW_CFG2_NVM_SIZE_MASK;
3563 if (val)
3564 bp->flash_size = val;
3565 else
3566 bp->flash_size = bp->flash_info->total_size;
3567
Michael Chanb6016b72005-05-26 13:03:09 -07003568 return rc;
3569}
3570
3571static int
3572bnx2_nvram_read(struct bnx2 *bp, u32 offset, u8 *ret_buf,
3573 int buf_size)
3574{
3575 int rc = 0;
3576 u32 cmd_flags, offset32, len32, extra;
3577
3578 if (buf_size == 0)
3579 return 0;
3580
3581 /* Request access to the flash interface. */
3582 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3583 return rc;
3584
3585 /* Enable access to flash interface */
3586 bnx2_enable_nvram_access(bp);
3587
3588 len32 = buf_size;
3589 offset32 = offset;
3590 extra = 0;
3591
3592 cmd_flags = 0;
3593
3594 if (offset32 & 3) {
3595 u8 buf[4];
3596 u32 pre_len;
3597
3598 offset32 &= ~3;
3599 pre_len = 4 - (offset & 3);
3600
3601 if (pre_len >= len32) {
3602 pre_len = len32;
3603 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3604 BNX2_NVM_COMMAND_LAST;
3605 }
3606 else {
3607 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3608 }
3609
3610 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3611
3612 if (rc)
3613 return rc;
3614
3615 memcpy(ret_buf, buf + (offset & 3), pre_len);
3616
3617 offset32 += 4;
3618 ret_buf += pre_len;
3619 len32 -= pre_len;
3620 }
3621 if (len32 & 3) {
3622 extra = 4 - (len32 & 3);
3623 len32 = (len32 + 4) & ~3;
3624 }
3625
3626 if (len32 == 4) {
3627 u8 buf[4];
3628
3629 if (cmd_flags)
3630 cmd_flags = BNX2_NVM_COMMAND_LAST;
3631 else
3632 cmd_flags = BNX2_NVM_COMMAND_FIRST |
3633 BNX2_NVM_COMMAND_LAST;
3634
3635 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3636
3637 memcpy(ret_buf, buf, 4 - extra);
3638 }
3639 else if (len32 > 0) {
3640 u8 buf[4];
3641
3642 /* Read the first word. */
3643 if (cmd_flags)
3644 cmd_flags = 0;
3645 else
3646 cmd_flags = BNX2_NVM_COMMAND_FIRST;
3647
3648 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, cmd_flags);
3649
3650 /* Advance to the next dword. */
3651 offset32 += 4;
3652 ret_buf += 4;
3653 len32 -= 4;
3654
3655 while (len32 > 4 && rc == 0) {
3656 rc = bnx2_nvram_read_dword(bp, offset32, ret_buf, 0);
3657
3658 /* Advance to the next dword. */
3659 offset32 += 4;
3660 ret_buf += 4;
3661 len32 -= 4;
3662 }
3663
3664 if (rc)
3665 return rc;
3666
3667 cmd_flags = BNX2_NVM_COMMAND_LAST;
3668 rc = bnx2_nvram_read_dword(bp, offset32, buf, cmd_flags);
3669
3670 memcpy(ret_buf, buf, 4 - extra);
3671 }
3672
3673 /* Disable access to flash interface */
3674 bnx2_disable_nvram_access(bp);
3675
3676 bnx2_release_nvram_lock(bp);
3677
3678 return rc;
3679}
3680
3681static int
3682bnx2_nvram_write(struct bnx2 *bp, u32 offset, u8 *data_buf,
3683 int buf_size)
3684{
3685 u32 written, offset32, len32;
Michael Chane6be7632007-01-08 19:56:13 -08003686 u8 *buf, start[4], end[4], *align_buf = NULL, *flash_buffer = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07003687 int rc = 0;
3688 int align_start, align_end;
3689
3690 buf = data_buf;
3691 offset32 = offset;
3692 len32 = buf_size;
3693 align_start = align_end = 0;
3694
3695 if ((align_start = (offset32 & 3))) {
3696 offset32 &= ~3;
Michael Chanc8738792007-03-30 14:53:06 -07003697 len32 += align_start;
3698 if (len32 < 4)
3699 len32 = 4;
Michael Chanb6016b72005-05-26 13:03:09 -07003700 if ((rc = bnx2_nvram_read(bp, offset32, start, 4)))
3701 return rc;
3702 }
3703
3704 if (len32 & 3) {
Michael Chanc8738792007-03-30 14:53:06 -07003705 align_end = 4 - (len32 & 3);
3706 len32 += align_end;
3707 if ((rc = bnx2_nvram_read(bp, offset32 + len32 - 4, end, 4)))
3708 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003709 }
3710
3711 if (align_start || align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08003712 align_buf = kmalloc(len32, GFP_KERNEL);
3713 if (align_buf == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07003714 return -ENOMEM;
3715 if (align_start) {
Michael Chane6be7632007-01-08 19:56:13 -08003716 memcpy(align_buf, start, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003717 }
3718 if (align_end) {
Michael Chane6be7632007-01-08 19:56:13 -08003719 memcpy(align_buf + len32 - 4, end, 4);
Michael Chanb6016b72005-05-26 13:03:09 -07003720 }
Michael Chane6be7632007-01-08 19:56:13 -08003721 memcpy(align_buf + align_start, data_buf, buf_size);
3722 buf = align_buf;
Michael Chanb6016b72005-05-26 13:03:09 -07003723 }
3724
Michael Chane30372c2007-07-16 18:26:23 -07003725 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanae181bc2006-05-22 16:39:20 -07003726 flash_buffer = kmalloc(264, GFP_KERNEL);
3727 if (flash_buffer == NULL) {
3728 rc = -ENOMEM;
3729 goto nvram_write_end;
3730 }
3731 }
3732
Michael Chanb6016b72005-05-26 13:03:09 -07003733 written = 0;
3734 while ((written < len32) && (rc == 0)) {
3735 u32 page_start, page_end, data_start, data_end;
3736 u32 addr, cmd_flags;
3737 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07003738
3739 /* Find the page_start addr */
3740 page_start = offset32 + written;
3741 page_start -= (page_start % bp->flash_info->page_size);
3742 /* Find the page_end addr */
3743 page_end = page_start + bp->flash_info->page_size;
3744 /* Find the data_start addr */
3745 data_start = (written == 0) ? offset32 : page_start;
3746 /* Find the data_end addr */
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003747 data_end = (page_end > offset32 + len32) ?
Michael Chanb6016b72005-05-26 13:03:09 -07003748 (offset32 + len32) : page_end;
3749
3750 /* Request access to the flash interface. */
3751 if ((rc = bnx2_acquire_nvram_lock(bp)) != 0)
3752 goto nvram_write_end;
3753
3754 /* Enable access to flash interface */
3755 bnx2_enable_nvram_access(bp);
3756
3757 cmd_flags = BNX2_NVM_COMMAND_FIRST;
Michael Chane30372c2007-07-16 18:26:23 -07003758 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003759 int j;
3760
3761 /* Read the whole page into the buffer
3762 * (non-buffer flash only) */
3763 for (j = 0; j < bp->flash_info->page_size; j += 4) {
3764 if (j == (bp->flash_info->page_size - 4)) {
3765 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3766 }
3767 rc = bnx2_nvram_read_dword(bp,
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003768 page_start + j,
3769 &flash_buffer[j],
Michael Chanb6016b72005-05-26 13:03:09 -07003770 cmd_flags);
3771
3772 if (rc)
3773 goto nvram_write_end;
3774
3775 cmd_flags = 0;
3776 }
3777 }
3778
3779 /* Enable writes to flash interface (unlock write-protect) */
3780 if ((rc = bnx2_enable_nvram_write(bp)) != 0)
3781 goto nvram_write_end;
3782
Michael Chanb6016b72005-05-26 13:03:09 -07003783 /* Loop to write back the buffer data from page_start to
3784 * data_start */
3785 i = 0;
Michael Chane30372c2007-07-16 18:26:23 -07003786 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanc8738792007-03-30 14:53:06 -07003787 /* Erase the page */
3788 if ((rc = bnx2_nvram_erase_page(bp, page_start)) != 0)
3789 goto nvram_write_end;
3790
3791 /* Re-enable the write again for the actual write */
3792 bnx2_enable_nvram_write(bp);
3793
Michael Chanb6016b72005-05-26 13:03:09 -07003794 for (addr = page_start; addr < data_start;
3795 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003796
Michael Chanb6016b72005-05-26 13:03:09 -07003797 rc = bnx2_nvram_write_dword(bp, addr,
3798 &flash_buffer[i], cmd_flags);
3799
3800 if (rc != 0)
3801 goto nvram_write_end;
3802
3803 cmd_flags = 0;
3804 }
3805 }
3806
3807 /* Loop to write the new data from data_start to data_end */
Michael Chanbae25762006-05-22 16:38:38 -07003808 for (addr = data_start; addr < data_end; addr += 4, i += 4) {
Michael Chanb6016b72005-05-26 13:03:09 -07003809 if ((addr == page_end - 4) ||
Michael Chane30372c2007-07-16 18:26:23 -07003810 ((bp->flash_info->flags & BNX2_NV_BUFFERED) &&
Michael Chanb6016b72005-05-26 13:03:09 -07003811 (addr == data_end - 4))) {
3812
3813 cmd_flags |= BNX2_NVM_COMMAND_LAST;
3814 }
3815 rc = bnx2_nvram_write_dword(bp, addr, buf,
3816 cmd_flags);
3817
3818 if (rc != 0)
3819 goto nvram_write_end;
3820
3821 cmd_flags = 0;
3822 buf += 4;
3823 }
3824
3825 /* Loop to write back the buffer data from data_end
3826 * to page_end */
Michael Chane30372c2007-07-16 18:26:23 -07003827 if (!(bp->flash_info->flags & BNX2_NV_BUFFERED)) {
Michael Chanb6016b72005-05-26 13:03:09 -07003828 for (addr = data_end; addr < page_end;
3829 addr += 4, i += 4) {
Jeff Garzik6aa20a22006-09-13 13:24:59 -04003830
Michael Chanb6016b72005-05-26 13:03:09 -07003831 if (addr == page_end-4) {
3832 cmd_flags = BNX2_NVM_COMMAND_LAST;
3833 }
3834 rc = bnx2_nvram_write_dword(bp, addr,
3835 &flash_buffer[i], cmd_flags);
3836
3837 if (rc != 0)
3838 goto nvram_write_end;
3839
3840 cmd_flags = 0;
3841 }
3842 }
3843
3844 /* Disable writes to flash interface (lock write-protect) */
3845 bnx2_disable_nvram_write(bp);
3846
3847 /* Disable access to flash interface */
3848 bnx2_disable_nvram_access(bp);
3849 bnx2_release_nvram_lock(bp);
3850
3851 /* Increment written */
3852 written += data_end - data_start;
3853 }
3854
3855nvram_write_end:
Michael Chane6be7632007-01-08 19:56:13 -08003856 kfree(flash_buffer);
3857 kfree(align_buf);
Michael Chanb6016b72005-05-26 13:03:09 -07003858 return rc;
3859}
3860
Michael Chan0d8a6572007-07-07 22:49:43 -07003861static void
3862bnx2_init_remote_phy(struct bnx2 *bp)
3863{
3864 u32 val;
3865
3866 bp->phy_flags &= ~REMOTE_PHY_CAP_FLAG;
3867 if (!(bp->phy_flags & PHY_SERDES_FLAG))
3868 return;
3869
3870 val = REG_RD_IND(bp, bp->shmem_base + BNX2_FW_CAP_MB);
3871 if ((val & BNX2_FW_CAP_SIGNATURE_MASK) != BNX2_FW_CAP_SIGNATURE)
3872 return;
3873
3874 if (val & BNX2_FW_CAP_REMOTE_PHY_CAPABLE) {
3875 if (netif_running(bp->dev)) {
3876 val = BNX2_DRV_ACK_CAP_SIGNATURE |
3877 BNX2_FW_CAP_REMOTE_PHY_CAPABLE;
3878 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_ACK_CAP_MB,
3879 val);
3880 }
3881 bp->phy_flags |= REMOTE_PHY_CAP_FLAG;
3882
3883 val = REG_RD_IND(bp, bp->shmem_base + BNX2_LINK_STATUS);
3884 if (val & BNX2_LINK_STATUS_SERDES_LINK)
3885 bp->phy_port = PORT_FIBRE;
3886 else
3887 bp->phy_port = PORT_TP;
3888 }
3889}
3890
Michael Chanb6016b72005-05-26 13:03:09 -07003891static int
3892bnx2_reset_chip(struct bnx2 *bp, u32 reset_code)
3893{
3894 u32 val;
3895 int i, rc = 0;
3896
3897 /* Wait for the current PCI transaction to complete before
3898 * issuing a reset. */
3899 REG_WR(bp, BNX2_MISC_ENABLE_CLR_BITS,
3900 BNX2_MISC_ENABLE_CLR_BITS_TX_DMA_ENABLE |
3901 BNX2_MISC_ENABLE_CLR_BITS_DMA_ENGINE_ENABLE |
3902 BNX2_MISC_ENABLE_CLR_BITS_RX_DMA_ENABLE |
3903 BNX2_MISC_ENABLE_CLR_BITS_HOST_COALESCE_ENABLE);
3904 val = REG_RD(bp, BNX2_MISC_ENABLE_CLR_BITS);
3905 udelay(5);
3906
Michael Chanb090ae22006-01-23 16:07:10 -08003907 /* Wait for the firmware to tell us it is ok to issue a reset. */
3908 bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT0 | reset_code, 1);
3909
Michael Chanb6016b72005-05-26 13:03:09 -07003910 /* Deposit a driver reset signature so the firmware knows that
3911 * this is a soft reset. */
Michael Chane3648b32005-11-04 08:51:21 -08003912 REG_WR_IND(bp, bp->shmem_base + BNX2_DRV_RESET_SIGNATURE,
Michael Chanb6016b72005-05-26 13:03:09 -07003913 BNX2_DRV_RESET_SIGNATURE_MAGIC);
3914
Michael Chanb6016b72005-05-26 13:03:09 -07003915 /* Do a dummy read to force the chip to complete all current transaction
3916 * before we issue a reset. */
3917 val = REG_RD(bp, BNX2_MISC_ID);
3918
Michael Chan234754d2006-11-19 14:11:41 -08003919 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
3920 REG_WR(bp, BNX2_MISC_COMMAND, BNX2_MISC_COMMAND_SW_RESET);
3921 REG_RD(bp, BNX2_MISC_COMMAND);
3922 udelay(5);
Michael Chanb6016b72005-05-26 13:03:09 -07003923
Michael Chan234754d2006-11-19 14:11:41 -08003924 val = BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
3925 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
Michael Chanb6016b72005-05-26 13:03:09 -07003926
Michael Chan234754d2006-11-19 14:11:41 -08003927 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG, val);
Michael Chanb6016b72005-05-26 13:03:09 -07003928
Michael Chan234754d2006-11-19 14:11:41 -08003929 } else {
3930 val = BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3931 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
3932 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP;
3933
3934 /* Chip reset. */
3935 REG_WR(bp, BNX2_PCICFG_MISC_CONFIG, val);
3936
3937 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
3938 (CHIP_ID(bp) == CHIP_ID_5706_A1)) {
3939 current->state = TASK_UNINTERRUPTIBLE;
3940 schedule_timeout(HZ / 50);
Michael Chanb6016b72005-05-26 13:03:09 -07003941 }
Michael Chanb6016b72005-05-26 13:03:09 -07003942
Michael Chan234754d2006-11-19 14:11:41 -08003943 /* Reset takes approximate 30 usec */
3944 for (i = 0; i < 10; i++) {
3945 val = REG_RD(bp, BNX2_PCICFG_MISC_CONFIG);
3946 if ((val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3947 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) == 0)
3948 break;
3949 udelay(10);
3950 }
3951
3952 if (val & (BNX2_PCICFG_MISC_CONFIG_CORE_RST_REQ |
3953 BNX2_PCICFG_MISC_CONFIG_CORE_RST_BSY)) {
3954 printk(KERN_ERR PFX "Chip reset did not complete\n");
3955 return -EBUSY;
3956 }
Michael Chanb6016b72005-05-26 13:03:09 -07003957 }
3958
3959 /* Make sure byte swapping is properly configured. */
3960 val = REG_RD(bp, BNX2_PCI_SWAP_DIAG0);
3961 if (val != 0x01020304) {
3962 printk(KERN_ERR PFX "Chip not in correct endian mode\n");
3963 return -ENODEV;
3964 }
3965
Michael Chanb6016b72005-05-26 13:03:09 -07003966 /* Wait for the firmware to finish its initialization. */
Michael Chanb090ae22006-01-23 16:07:10 -08003967 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT1 | reset_code, 0);
3968 if (rc)
3969 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003970
Michael Chan0d8a6572007-07-07 22:49:43 -07003971 spin_lock_bh(&bp->phy_lock);
3972 bnx2_init_remote_phy(bp);
3973 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
3974 bnx2_set_default_remote_link(bp);
3975 spin_unlock_bh(&bp->phy_lock);
3976
Michael Chanb6016b72005-05-26 13:03:09 -07003977 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
3978 /* Adjust the voltage regular to two steps lower. The default
3979 * of this register is 0x0000000e. */
3980 REG_WR(bp, BNX2_MISC_VREG_CONTROL, 0x000000fa);
3981
3982 /* Remove bad rbuf memory from the free pool. */
3983 rc = bnx2_alloc_bad_rbuf(bp);
3984 }
3985
3986 return rc;
3987}
3988
3989static int
3990bnx2_init_chip(struct bnx2 *bp)
3991{
3992 u32 val;
Michael Chanb090ae22006-01-23 16:07:10 -08003993 int rc;
Michael Chanb6016b72005-05-26 13:03:09 -07003994
3995 /* Make sure the interrupt is not active. */
3996 REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_MASK_INT);
3997
3998 val = BNX2_DMA_CONFIG_DATA_BYTE_SWAP |
3999 BNX2_DMA_CONFIG_DATA_WORD_SWAP |
4000#ifdef __BIG_ENDIAN
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004001 BNX2_DMA_CONFIG_CNTL_BYTE_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004002#endif
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004003 BNX2_DMA_CONFIG_CNTL_WORD_SWAP |
Michael Chanb6016b72005-05-26 13:03:09 -07004004 DMA_READ_CHANS << 12 |
4005 DMA_WRITE_CHANS << 16;
4006
4007 val |= (0x2 << 20) | (1 << 11);
4008
Michael Chandda1e392006-01-23 16:08:14 -08004009 if ((bp->flags & PCIX_FLAG) && (bp->bus_speed_mhz == 133))
Michael Chanb6016b72005-05-26 13:03:09 -07004010 val |= (1 << 23);
4011
4012 if ((CHIP_NUM(bp) == CHIP_NUM_5706) &&
4013 (CHIP_ID(bp) != CHIP_ID_5706_A0) && !(bp->flags & PCIX_FLAG))
4014 val |= BNX2_DMA_CONFIG_CNTL_PING_PONG_DMA;
4015
4016 REG_WR(bp, BNX2_DMA_CONFIG, val);
4017
4018 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
4019 val = REG_RD(bp, BNX2_TDMA_CONFIG);
4020 val |= BNX2_TDMA_CONFIG_ONE_DMA;
4021 REG_WR(bp, BNX2_TDMA_CONFIG, val);
4022 }
4023
4024 if (bp->flags & PCIX_FLAG) {
4025 u16 val16;
4026
4027 pci_read_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4028 &val16);
4029 pci_write_config_word(bp->pdev, bp->pcix_cap + PCI_X_CMD,
4030 val16 & ~PCI_X_CMD_ERO);
4031 }
4032
4033 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS,
4034 BNX2_MISC_ENABLE_SET_BITS_HOST_COALESCE_ENABLE |
4035 BNX2_MISC_ENABLE_STATUS_BITS_RX_V2P_ENABLE |
4036 BNX2_MISC_ENABLE_STATUS_BITS_CONTEXT_ENABLE);
4037
4038 /* Initialize context mapping and zero out the quick contexts. The
4039 * context block must have already been enabled. */
Michael Chan641bdcd2007-06-04 21:22:24 -07004040 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4041 rc = bnx2_init_5709_context(bp);
4042 if (rc)
4043 return rc;
4044 } else
Michael Chan59b47d82006-11-19 14:10:45 -08004045 bnx2_init_context(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004046
Michael Chanfba9fe92006-06-12 22:21:25 -07004047 if ((rc = bnx2_init_cpus(bp)) != 0)
4048 return rc;
4049
Michael Chanb6016b72005-05-26 13:03:09 -07004050 bnx2_init_nvram(bp);
4051
4052 bnx2_set_mac_addr(bp);
4053
4054 val = REG_RD(bp, BNX2_MQ_CONFIG);
4055 val &= ~BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE;
4056 val |= BNX2_MQ_CONFIG_KNL_BYP_BLK_SIZE_256;
Michael Chan68c9f752007-04-24 15:35:53 -07004057 if (CHIP_ID(bp) == CHIP_ID_5709_A0 || CHIP_ID(bp) == CHIP_ID_5709_A1)
4058 val |= BNX2_MQ_CONFIG_HALT_DIS;
4059
Michael Chanb6016b72005-05-26 13:03:09 -07004060 REG_WR(bp, BNX2_MQ_CONFIG, val);
4061
4062 val = 0x10000 + (MAX_CID_CNT * MB_KERNEL_CTX_SIZE);
4063 REG_WR(bp, BNX2_MQ_KNL_BYP_WIND_START, val);
4064 REG_WR(bp, BNX2_MQ_KNL_WIND_END, val);
4065
4066 val = (BCM_PAGE_BITS - 8) << 24;
4067 REG_WR(bp, BNX2_RV2P_CONFIG, val);
4068
4069 /* Configure page size. */
4070 val = REG_RD(bp, BNX2_TBDR_CONFIG);
4071 val &= ~BNX2_TBDR_CONFIG_PAGE_SIZE;
4072 val |= (BCM_PAGE_BITS - 8) << 24 | 0x40;
4073 REG_WR(bp, BNX2_TBDR_CONFIG, val);
4074
4075 val = bp->mac_addr[0] +
4076 (bp->mac_addr[1] << 8) +
4077 (bp->mac_addr[2] << 16) +
4078 bp->mac_addr[3] +
4079 (bp->mac_addr[4] << 8) +
4080 (bp->mac_addr[5] << 16);
4081 REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val);
4082
4083 /* Program the MTU. Also include 4 bytes for CRC32. */
4084 val = bp->dev->mtu + ETH_HLEN + 4;
4085 if (val > (MAX_ETHERNET_PACKET_SIZE + 4))
4086 val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA;
4087 REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val);
4088
4089 bp->last_status_idx = 0;
4090 bp->rx_mode = BNX2_EMAC_RX_MODE_SORT_MODE;
4091
4092 /* Set up how to generate a link change interrupt. */
4093 REG_WR(bp, BNX2_EMAC_ATTENTION_ENA, BNX2_EMAC_ATTENTION_ENA_LINK);
4094
4095 REG_WR(bp, BNX2_HC_STATUS_ADDR_L,
4096 (u64) bp->status_blk_mapping & 0xffffffff);
4097 REG_WR(bp, BNX2_HC_STATUS_ADDR_H, (u64) bp->status_blk_mapping >> 32);
4098
4099 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_L,
4100 (u64) bp->stats_blk_mapping & 0xffffffff);
4101 REG_WR(bp, BNX2_HC_STATISTICS_ADDR_H,
4102 (u64) bp->stats_blk_mapping >> 32);
4103
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004104 REG_WR(bp, BNX2_HC_TX_QUICK_CONS_TRIP,
Michael Chanb6016b72005-05-26 13:03:09 -07004105 (bp->tx_quick_cons_trip_int << 16) | bp->tx_quick_cons_trip);
4106
4107 REG_WR(bp, BNX2_HC_RX_QUICK_CONS_TRIP,
4108 (bp->rx_quick_cons_trip_int << 16) | bp->rx_quick_cons_trip);
4109
4110 REG_WR(bp, BNX2_HC_COMP_PROD_TRIP,
4111 (bp->comp_prod_trip_int << 16) | bp->comp_prod_trip);
4112
4113 REG_WR(bp, BNX2_HC_TX_TICKS, (bp->tx_ticks_int << 16) | bp->tx_ticks);
4114
4115 REG_WR(bp, BNX2_HC_RX_TICKS, (bp->rx_ticks_int << 16) | bp->rx_ticks);
4116
4117 REG_WR(bp, BNX2_HC_COM_TICKS,
4118 (bp->com_ticks_int << 16) | bp->com_ticks);
4119
4120 REG_WR(bp, BNX2_HC_CMD_TICKS,
4121 (bp->cmd_ticks_int << 16) | bp->cmd_ticks);
4122
Michael Chan02537b062007-06-04 21:24:07 -07004123 if (CHIP_NUM(bp) == CHIP_NUM_5708)
4124 REG_WR(bp, BNX2_HC_STATS_TICKS, 0);
4125 else
4126 REG_WR(bp, BNX2_HC_STATS_TICKS, bp->stats_ticks & 0xffff00);
Michael Chanb6016b72005-05-26 13:03:09 -07004127 REG_WR(bp, BNX2_HC_STAT_COLLECT_TICKS, 0xbb8); /* 3ms */
4128
4129 if (CHIP_ID(bp) == CHIP_ID_5706_A1)
Michael Chan8e6a72c2007-05-03 13:24:48 -07004130 val = BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004131 else {
Michael Chan8e6a72c2007-05-03 13:24:48 -07004132 val = BNX2_HC_CONFIG_RX_TMR_MODE | BNX2_HC_CONFIG_TX_TMR_MODE |
4133 BNX2_HC_CONFIG_COLLECT_STATS;
Michael Chanb6016b72005-05-26 13:03:09 -07004134 }
4135
Michael Chan8e6a72c2007-05-03 13:24:48 -07004136 if (bp->flags & ONE_SHOT_MSI_FLAG)
4137 val |= BNX2_HC_CONFIG_ONE_SHOT;
4138
4139 REG_WR(bp, BNX2_HC_CONFIG, val);
4140
Michael Chanb6016b72005-05-26 13:03:09 -07004141 /* Clear internal stats counters. */
4142 REG_WR(bp, BNX2_HC_COMMAND, BNX2_HC_COMMAND_CLR_STAT_NOW);
4143
Michael Chanda3e4fb2007-05-03 13:24:23 -07004144 REG_WR(bp, BNX2_HC_ATTN_BITS_ENABLE, STATUS_ATTN_EVENTS);
Michael Chanb6016b72005-05-26 13:03:09 -07004145
Michael Chane29054f2006-01-23 16:06:06 -08004146 if (REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_FEATURE) &
4147 BNX2_PORT_FEATURE_ASF_ENABLED)
4148 bp->flags |= ASF_ENABLE_FLAG;
4149
Michael Chanb6016b72005-05-26 13:03:09 -07004150 /* Initialize the receive filter. */
4151 bnx2_set_rx_mode(bp->dev);
4152
Michael Chan0aa38df2007-06-04 21:23:06 -07004153 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4154 val = REG_RD(bp, BNX2_MISC_NEW_CORE_CTL);
4155 val |= BNX2_MISC_NEW_CORE_CTL_DMA_ENABLE;
4156 REG_WR(bp, BNX2_MISC_NEW_CORE_CTL, val);
4157 }
Michael Chanb090ae22006-01-23 16:07:10 -08004158 rc = bnx2_fw_sync(bp, BNX2_DRV_MSG_DATA_WAIT2 | BNX2_DRV_MSG_CODE_RESET,
4159 0);
Michael Chanb6016b72005-05-26 13:03:09 -07004160
Michael Chandf149d72007-07-07 22:51:36 -07004161 REG_WR(bp, BNX2_MISC_ENABLE_SET_BITS, BNX2_MISC_ENABLE_DEFAULT);
Michael Chanb6016b72005-05-26 13:03:09 -07004162 REG_RD(bp, BNX2_MISC_ENABLE_SET_BITS);
4163
4164 udelay(20);
4165
Michael Chanbf5295b2006-03-23 01:11:56 -08004166 bp->hc_cmd = REG_RD(bp, BNX2_HC_COMMAND);
4167
Michael Chanb090ae22006-01-23 16:07:10 -08004168 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07004169}
4170
Michael Chan59b47d82006-11-19 14:10:45 -08004171static void
4172bnx2_init_tx_context(struct bnx2 *bp, u32 cid)
4173{
4174 u32 val, offset0, offset1, offset2, offset3;
4175
4176 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
4177 offset0 = BNX2_L2CTX_TYPE_XI;
4178 offset1 = BNX2_L2CTX_CMD_TYPE_XI;
4179 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI_XI;
4180 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO_XI;
4181 } else {
4182 offset0 = BNX2_L2CTX_TYPE;
4183 offset1 = BNX2_L2CTX_CMD_TYPE;
4184 offset2 = BNX2_L2CTX_TBDR_BHADDR_HI;
4185 offset3 = BNX2_L2CTX_TBDR_BHADDR_LO;
4186 }
4187 val = BNX2_L2CTX_TYPE_TYPE_L2 | BNX2_L2CTX_TYPE_SIZE_L2;
4188 CTX_WR(bp, GET_CID_ADDR(cid), offset0, val);
4189
4190 val = BNX2_L2CTX_CMD_TYPE_TYPE_L2 | (8 << 16);
4191 CTX_WR(bp, GET_CID_ADDR(cid), offset1, val);
4192
4193 val = (u64) bp->tx_desc_mapping >> 32;
4194 CTX_WR(bp, GET_CID_ADDR(cid), offset2, val);
4195
4196 val = (u64) bp->tx_desc_mapping & 0xffffffff;
4197 CTX_WR(bp, GET_CID_ADDR(cid), offset3, val);
4198}
Michael Chanb6016b72005-05-26 13:03:09 -07004199
4200static void
4201bnx2_init_tx_ring(struct bnx2 *bp)
4202{
4203 struct tx_bd *txbd;
Michael Chan59b47d82006-11-19 14:10:45 -08004204 u32 cid;
Michael Chanb6016b72005-05-26 13:03:09 -07004205
Michael Chan2f8af122006-08-15 01:39:10 -07004206 bp->tx_wake_thresh = bp->tx_ring_size / 2;
4207
Michael Chanb6016b72005-05-26 13:03:09 -07004208 txbd = &bp->tx_desc_ring[MAX_TX_DESC_CNT];
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004209
Michael Chanb6016b72005-05-26 13:03:09 -07004210 txbd->tx_bd_haddr_hi = (u64) bp->tx_desc_mapping >> 32;
4211 txbd->tx_bd_haddr_lo = (u64) bp->tx_desc_mapping & 0xffffffff;
4212
4213 bp->tx_prod = 0;
4214 bp->tx_cons = 0;
Michael Chanf4e418f2005-11-04 08:53:48 -08004215 bp->hw_tx_cons = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004216 bp->tx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004217
Michael Chan59b47d82006-11-19 14:10:45 -08004218 cid = TX_CID;
4219 bp->tx_bidx_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BIDX;
4220 bp->tx_bseq_addr = MB_GET_CID_ADDR(cid) + BNX2_L2CTX_TX_HOST_BSEQ;
Michael Chanb6016b72005-05-26 13:03:09 -07004221
Michael Chan59b47d82006-11-19 14:10:45 -08004222 bnx2_init_tx_context(bp, cid);
Michael Chanb6016b72005-05-26 13:03:09 -07004223}
4224
4225static void
4226bnx2_init_rx_ring(struct bnx2 *bp)
4227{
4228 struct rx_bd *rxbd;
4229 int i;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004230 u16 prod, ring_prod;
Michael Chanb6016b72005-05-26 13:03:09 -07004231 u32 val;
4232
4233 /* 8 for CRC and VLAN */
4234 bp->rx_buf_use_size = bp->dev->mtu + ETH_HLEN + bp->rx_offset + 8;
Michael Chan59b47d82006-11-19 14:10:45 -08004235 /* hw alignment */
4236 bp->rx_buf_size = bp->rx_buf_use_size + BNX2_RX_ALIGN;
Michael Chanb6016b72005-05-26 13:03:09 -07004237
4238 ring_prod = prod = bp->rx_prod = 0;
4239 bp->rx_cons = 0;
Michael Chanf4e418f2005-11-04 08:53:48 -08004240 bp->hw_rx_cons = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07004241 bp->rx_prod_bseq = 0;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004242
Michael Chan13daffa2006-03-20 17:49:20 -08004243 for (i = 0; i < bp->rx_max_ring; i++) {
4244 int j;
Michael Chanb6016b72005-05-26 13:03:09 -07004245
Michael Chan13daffa2006-03-20 17:49:20 -08004246 rxbd = &bp->rx_desc_ring[i][0];
4247 for (j = 0; j < MAX_RX_DESC_CNT; j++, rxbd++) {
4248 rxbd->rx_bd_len = bp->rx_buf_use_size;
4249 rxbd->rx_bd_flags = RX_BD_FLAGS_START | RX_BD_FLAGS_END;
4250 }
4251 if (i == (bp->rx_max_ring - 1))
4252 j = 0;
4253 else
4254 j = i + 1;
4255 rxbd->rx_bd_haddr_hi = (u64) bp->rx_desc_mapping[j] >> 32;
4256 rxbd->rx_bd_haddr_lo = (u64) bp->rx_desc_mapping[j] &
4257 0xffffffff;
4258 }
Michael Chanb6016b72005-05-26 13:03:09 -07004259
4260 val = BNX2_L2CTX_CTX_TYPE_CTX_BD_CHN_TYPE_VALUE;
4261 val |= BNX2_L2CTX_CTX_TYPE_SIZE_L2;
4262 val |= 0x02 << 8;
4263 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_CTX_TYPE, val);
4264
Michael Chan13daffa2006-03-20 17:49:20 -08004265 val = (u64) bp->rx_desc_mapping[0] >> 32;
Michael Chanb6016b72005-05-26 13:03:09 -07004266 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_HI, val);
4267
Michael Chan13daffa2006-03-20 17:49:20 -08004268 val = (u64) bp->rx_desc_mapping[0] & 0xffffffff;
Michael Chanb6016b72005-05-26 13:03:09 -07004269 CTX_WR(bp, GET_CID_ADDR(RX_CID), BNX2_L2CTX_NX_BDHADDR_LO, val);
4270
Michael Chan236b6392006-03-20 17:49:02 -08004271 for (i = 0; i < bp->rx_ring_size; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07004272 if (bnx2_alloc_rx_skb(bp, ring_prod) < 0) {
4273 break;
4274 }
4275 prod = NEXT_RX_BD(prod);
4276 ring_prod = RX_RING_IDX(prod);
4277 }
4278 bp->rx_prod = prod;
4279
4280 REG_WR16(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BDIDX, prod);
4281
4282 REG_WR(bp, MB_RX_CID_ADDR + BNX2_L2CTX_HOST_BSEQ, bp->rx_prod_bseq);
4283}
4284
4285static void
Michael Chan13daffa2006-03-20 17:49:20 -08004286bnx2_set_rx_ring_size(struct bnx2 *bp, u32 size)
4287{
4288 u32 num_rings, max;
4289
4290 bp->rx_ring_size = size;
4291 num_rings = 1;
4292 while (size > MAX_RX_DESC_CNT) {
4293 size -= MAX_RX_DESC_CNT;
4294 num_rings++;
4295 }
4296 /* round to next power of 2 */
4297 max = MAX_RX_RINGS;
4298 while ((max & num_rings) == 0)
4299 max >>= 1;
4300
4301 if (num_rings != max)
4302 max <<= 1;
4303
4304 bp->rx_max_ring = max;
4305 bp->rx_max_ring_idx = (bp->rx_max_ring * RX_DESC_CNT) - 1;
4306}
4307
4308static void
Michael Chanb6016b72005-05-26 13:03:09 -07004309bnx2_free_tx_skbs(struct bnx2 *bp)
4310{
4311 int i;
4312
4313 if (bp->tx_buf_ring == NULL)
4314 return;
4315
4316 for (i = 0; i < TX_DESC_CNT; ) {
4317 struct sw_bd *tx_buf = &bp->tx_buf_ring[i];
4318 struct sk_buff *skb = tx_buf->skb;
4319 int j, last;
4320
4321 if (skb == NULL) {
4322 i++;
4323 continue;
4324 }
4325
4326 pci_unmap_single(bp->pdev, pci_unmap_addr(tx_buf, mapping),
4327 skb_headlen(skb), PCI_DMA_TODEVICE);
4328
4329 tx_buf->skb = NULL;
4330
4331 last = skb_shinfo(skb)->nr_frags;
4332 for (j = 0; j < last; j++) {
4333 tx_buf = &bp->tx_buf_ring[i + j + 1];
4334 pci_unmap_page(bp->pdev,
4335 pci_unmap_addr(tx_buf, mapping),
4336 skb_shinfo(skb)->frags[j].size,
4337 PCI_DMA_TODEVICE);
4338 }
Michael Chan745720e2006-06-29 12:37:41 -07004339 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004340 i += j + 1;
4341 }
4342
4343}
4344
4345static void
4346bnx2_free_rx_skbs(struct bnx2 *bp)
4347{
4348 int i;
4349
4350 if (bp->rx_buf_ring == NULL)
4351 return;
4352
Michael Chan13daffa2006-03-20 17:49:20 -08004353 for (i = 0; i < bp->rx_max_ring_idx; i++) {
Michael Chanb6016b72005-05-26 13:03:09 -07004354 struct sw_bd *rx_buf = &bp->rx_buf_ring[i];
4355 struct sk_buff *skb = rx_buf->skb;
4356
Michael Chan05d0f1c2005-11-04 08:53:48 -08004357 if (skb == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07004358 continue;
4359
4360 pci_unmap_single(bp->pdev, pci_unmap_addr(rx_buf, mapping),
4361 bp->rx_buf_use_size, PCI_DMA_FROMDEVICE);
4362
4363 rx_buf->skb = NULL;
4364
Michael Chan745720e2006-06-29 12:37:41 -07004365 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004366 }
4367}
4368
4369static void
4370bnx2_free_skbs(struct bnx2 *bp)
4371{
4372 bnx2_free_tx_skbs(bp);
4373 bnx2_free_rx_skbs(bp);
4374}
4375
4376static int
4377bnx2_reset_nic(struct bnx2 *bp, u32 reset_code)
4378{
4379 int rc;
4380
4381 rc = bnx2_reset_chip(bp, reset_code);
4382 bnx2_free_skbs(bp);
4383 if (rc)
4384 return rc;
4385
Michael Chanfba9fe92006-06-12 22:21:25 -07004386 if ((rc = bnx2_init_chip(bp)) != 0)
4387 return rc;
4388
Michael Chanb6016b72005-05-26 13:03:09 -07004389 bnx2_init_tx_ring(bp);
4390 bnx2_init_rx_ring(bp);
4391 return 0;
4392}
4393
4394static int
4395bnx2_init_nic(struct bnx2 *bp)
4396{
4397 int rc;
4398
4399 if ((rc = bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET)) != 0)
4400 return rc;
4401
Michael Chan80be4432006-11-19 14:07:28 -08004402 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004403 bnx2_init_phy(bp);
4404 bnx2_set_link(bp);
Michael Chan0d8a6572007-07-07 22:49:43 -07004405 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07004406 return 0;
4407}
4408
4409static int
4410bnx2_test_registers(struct bnx2 *bp)
4411{
4412 int ret;
Michael Chan5bae30c2007-05-03 13:18:46 -07004413 int i, is_5709;
Arjan van de Venf71e1302006-03-03 21:33:57 -05004414 static const struct {
Michael Chanb6016b72005-05-26 13:03:09 -07004415 u16 offset;
4416 u16 flags;
Michael Chan5bae30c2007-05-03 13:18:46 -07004417#define BNX2_FL_NOT_5709 1
Michael Chanb6016b72005-05-26 13:03:09 -07004418 u32 rw_mask;
4419 u32 ro_mask;
4420 } reg_tbl[] = {
4421 { 0x006c, 0, 0x00000000, 0x0000003f },
4422 { 0x0090, 0, 0xffffffff, 0x00000000 },
4423 { 0x0094, 0, 0x00000000, 0x00000000 },
4424
Michael Chan5bae30c2007-05-03 13:18:46 -07004425 { 0x0404, BNX2_FL_NOT_5709, 0x00003f00, 0x00000000 },
4426 { 0x0418, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4427 { 0x041c, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4428 { 0x0420, BNX2_FL_NOT_5709, 0x00000000, 0x80ffffff },
4429 { 0x0424, BNX2_FL_NOT_5709, 0x00000000, 0x00000000 },
4430 { 0x0428, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4431 { 0x0450, BNX2_FL_NOT_5709, 0x00000000, 0x0000ffff },
4432 { 0x0454, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4433 { 0x0458, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
Michael Chanb6016b72005-05-26 13:03:09 -07004434
Michael Chan5bae30c2007-05-03 13:18:46 -07004435 { 0x0808, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4436 { 0x0854, BNX2_FL_NOT_5709, 0x00000000, 0xffffffff },
4437 { 0x0868, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4438 { 0x086c, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4439 { 0x0870, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
4440 { 0x0874, BNX2_FL_NOT_5709, 0x00000000, 0x77777777 },
Michael Chanb6016b72005-05-26 13:03:09 -07004441
Michael Chan5bae30c2007-05-03 13:18:46 -07004442 { 0x0c00, BNX2_FL_NOT_5709, 0x00000000, 0x00000001 },
4443 { 0x0c04, BNX2_FL_NOT_5709, 0x00000000, 0x03ff0001 },
4444 { 0x0c08, BNX2_FL_NOT_5709, 0x0f0ff073, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004445
4446 { 0x1000, 0, 0x00000000, 0x00000001 },
4447 { 0x1004, 0, 0x00000000, 0x000f0001 },
Michael Chanb6016b72005-05-26 13:03:09 -07004448
4449 { 0x1408, 0, 0x01c00800, 0x00000000 },
4450 { 0x149c, 0, 0x8000ffff, 0x00000000 },
4451 { 0x14a8, 0, 0x00000000, 0x000001ff },
Michael Chan5b0c76a2005-11-04 08:45:49 -08004452 { 0x14ac, 0, 0x0fffffff, 0x10000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004453 { 0x14b0, 0, 0x00000002, 0x00000001 },
4454 { 0x14b8, 0, 0x00000000, 0x00000000 },
4455 { 0x14c0, 0, 0x00000000, 0x00000009 },
4456 { 0x14c4, 0, 0x00003fff, 0x00000000 },
4457 { 0x14cc, 0, 0x00000000, 0x00000001 },
4458 { 0x14d0, 0, 0xffffffff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004459
4460 { 0x1800, 0, 0x00000000, 0x00000001 },
4461 { 0x1804, 0, 0x00000000, 0x00000003 },
Michael Chanb6016b72005-05-26 13:03:09 -07004462
4463 { 0x2800, 0, 0x00000000, 0x00000001 },
4464 { 0x2804, 0, 0x00000000, 0x00003f01 },
4465 { 0x2808, 0, 0x0f3f3f03, 0x00000000 },
4466 { 0x2810, 0, 0xffff0000, 0x00000000 },
4467 { 0x2814, 0, 0xffff0000, 0x00000000 },
4468 { 0x2818, 0, 0xffff0000, 0x00000000 },
4469 { 0x281c, 0, 0xffff0000, 0x00000000 },
4470 { 0x2834, 0, 0xffffffff, 0x00000000 },
4471 { 0x2840, 0, 0x00000000, 0xffffffff },
4472 { 0x2844, 0, 0x00000000, 0xffffffff },
4473 { 0x2848, 0, 0xffffffff, 0x00000000 },
4474 { 0x284c, 0, 0xf800f800, 0x07ff07ff },
4475
4476 { 0x2c00, 0, 0x00000000, 0x00000011 },
4477 { 0x2c04, 0, 0x00000000, 0x00030007 },
4478
Michael Chanb6016b72005-05-26 13:03:09 -07004479 { 0x3c00, 0, 0x00000000, 0x00000001 },
4480 { 0x3c04, 0, 0x00000000, 0x00070000 },
4481 { 0x3c08, 0, 0x00007f71, 0x07f00000 },
4482 { 0x3c0c, 0, 0x1f3ffffc, 0x00000000 },
4483 { 0x3c10, 0, 0xffffffff, 0x00000000 },
4484 { 0x3c14, 0, 0x00000000, 0xffffffff },
4485 { 0x3c18, 0, 0x00000000, 0xffffffff },
4486 { 0x3c1c, 0, 0xfffff000, 0x00000000 },
4487 { 0x3c20, 0, 0xffffff00, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004488
4489 { 0x5004, 0, 0x00000000, 0x0000007f },
4490 { 0x5008, 0, 0x0f0007ff, 0x00000000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004491
Michael Chanb6016b72005-05-26 13:03:09 -07004492 { 0x5c00, 0, 0x00000000, 0x00000001 },
4493 { 0x5c04, 0, 0x00000000, 0x0003000f },
4494 { 0x5c08, 0, 0x00000003, 0x00000000 },
4495 { 0x5c0c, 0, 0x0000fff8, 0x00000000 },
4496 { 0x5c10, 0, 0x00000000, 0xffffffff },
4497 { 0x5c80, 0, 0x00000000, 0x0f7113f1 },
4498 { 0x5c84, 0, 0x00000000, 0x0000f333 },
4499 { 0x5c88, 0, 0x00000000, 0x00077373 },
4500 { 0x5c8c, 0, 0x00000000, 0x0007f737 },
4501
4502 { 0x6808, 0, 0x0000ff7f, 0x00000000 },
4503 { 0x680c, 0, 0xffffffff, 0x00000000 },
4504 { 0x6810, 0, 0xffffffff, 0x00000000 },
4505 { 0x6814, 0, 0xffffffff, 0x00000000 },
4506 { 0x6818, 0, 0xffffffff, 0x00000000 },
4507 { 0x681c, 0, 0xffffffff, 0x00000000 },
4508 { 0x6820, 0, 0x00ff00ff, 0x00000000 },
4509 { 0x6824, 0, 0x00ff00ff, 0x00000000 },
4510 { 0x6828, 0, 0x00ff00ff, 0x00000000 },
4511 { 0x682c, 0, 0x03ff03ff, 0x00000000 },
4512 { 0x6830, 0, 0x03ff03ff, 0x00000000 },
4513 { 0x6834, 0, 0x03ff03ff, 0x00000000 },
4514 { 0x6838, 0, 0x03ff03ff, 0x00000000 },
4515 { 0x683c, 0, 0x0000ffff, 0x00000000 },
4516 { 0x6840, 0, 0x00000ff0, 0x00000000 },
4517 { 0x6844, 0, 0x00ffff00, 0x00000000 },
4518 { 0x684c, 0, 0xffffffff, 0x00000000 },
4519 { 0x6850, 0, 0x7f7f7f7f, 0x00000000 },
4520 { 0x6854, 0, 0x7f7f7f7f, 0x00000000 },
4521 { 0x6858, 0, 0x7f7f7f7f, 0x00000000 },
4522 { 0x685c, 0, 0x7f7f7f7f, 0x00000000 },
4523 { 0x6908, 0, 0x00000000, 0x0001ff0f },
4524 { 0x690c, 0, 0x00000000, 0x0ffe00f0 },
4525
4526 { 0xffff, 0, 0x00000000, 0x00000000 },
4527 };
4528
4529 ret = 0;
Michael Chan5bae30c2007-05-03 13:18:46 -07004530 is_5709 = 0;
4531 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4532 is_5709 = 1;
4533
Michael Chanb6016b72005-05-26 13:03:09 -07004534 for (i = 0; reg_tbl[i].offset != 0xffff; i++) {
4535 u32 offset, rw_mask, ro_mask, save_val, val;
Michael Chan5bae30c2007-05-03 13:18:46 -07004536 u16 flags = reg_tbl[i].flags;
4537
4538 if (is_5709 && (flags & BNX2_FL_NOT_5709))
4539 continue;
Michael Chanb6016b72005-05-26 13:03:09 -07004540
4541 offset = (u32) reg_tbl[i].offset;
4542 rw_mask = reg_tbl[i].rw_mask;
4543 ro_mask = reg_tbl[i].ro_mask;
4544
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004545 save_val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004546
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004547 writel(0, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004548
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004549 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004550 if ((val & rw_mask) != 0) {
4551 goto reg_test_err;
4552 }
4553
4554 if ((val & ro_mask) != (save_val & ro_mask)) {
4555 goto reg_test_err;
4556 }
4557
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004558 writel(0xffffffff, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004559
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004560 val = readl(bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004561 if ((val & rw_mask) != rw_mask) {
4562 goto reg_test_err;
4563 }
4564
4565 if ((val & ro_mask) != (save_val & ro_mask)) {
4566 goto reg_test_err;
4567 }
4568
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004569 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004570 continue;
4571
4572reg_test_err:
Peter Hagervall14ab9b82005-08-10 14:18:16 -07004573 writel(save_val, bp->regview + offset);
Michael Chanb6016b72005-05-26 13:03:09 -07004574 ret = -ENODEV;
4575 break;
4576 }
4577 return ret;
4578}
4579
4580static int
4581bnx2_do_mem_test(struct bnx2 *bp, u32 start, u32 size)
4582{
Arjan van de Venf71e1302006-03-03 21:33:57 -05004583 static const u32 test_pattern[] = { 0x00000000, 0xffffffff, 0x55555555,
Michael Chanb6016b72005-05-26 13:03:09 -07004584 0xaaaaaaaa , 0xaa55aa55, 0x55aa55aa };
4585 int i;
4586
4587 for (i = 0; i < sizeof(test_pattern) / 4; i++) {
4588 u32 offset;
4589
4590 for (offset = 0; offset < size; offset += 4) {
4591
4592 REG_WR_IND(bp, start + offset, test_pattern[i]);
4593
4594 if (REG_RD_IND(bp, start + offset) !=
4595 test_pattern[i]) {
4596 return -ENODEV;
4597 }
4598 }
4599 }
4600 return 0;
4601}
4602
4603static int
4604bnx2_test_memory(struct bnx2 *bp)
4605{
4606 int ret = 0;
4607 int i;
Michael Chan5bae30c2007-05-03 13:18:46 -07004608 static struct mem_entry {
Michael Chanb6016b72005-05-26 13:03:09 -07004609 u32 offset;
4610 u32 len;
Michael Chan5bae30c2007-05-03 13:18:46 -07004611 } mem_tbl_5706[] = {
Michael Chanb6016b72005-05-26 13:03:09 -07004612 { 0x60000, 0x4000 },
Michael Chan5b0c76a2005-11-04 08:45:49 -08004613 { 0xa0000, 0x3000 },
Michael Chanb6016b72005-05-26 13:03:09 -07004614 { 0xe0000, 0x4000 },
4615 { 0x120000, 0x4000 },
4616 { 0x1a0000, 0x4000 },
4617 { 0x160000, 0x4000 },
4618 { 0xffffffff, 0 },
Michael Chan5bae30c2007-05-03 13:18:46 -07004619 },
4620 mem_tbl_5709[] = {
4621 { 0x60000, 0x4000 },
4622 { 0xa0000, 0x3000 },
4623 { 0xe0000, 0x4000 },
4624 { 0x120000, 0x4000 },
4625 { 0x1a0000, 0x4000 },
4626 { 0xffffffff, 0 },
Michael Chanb6016b72005-05-26 13:03:09 -07004627 };
Michael Chan5bae30c2007-05-03 13:18:46 -07004628 struct mem_entry *mem_tbl;
4629
4630 if (CHIP_NUM(bp) == CHIP_NUM_5709)
4631 mem_tbl = mem_tbl_5709;
4632 else
4633 mem_tbl = mem_tbl_5706;
Michael Chanb6016b72005-05-26 13:03:09 -07004634
4635 for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) {
4636 if ((ret = bnx2_do_mem_test(bp, mem_tbl[i].offset,
4637 mem_tbl[i].len)) != 0) {
4638 return ret;
4639 }
4640 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004641
Michael Chanb6016b72005-05-26 13:03:09 -07004642 return ret;
4643}
4644
Michael Chanbc5a0692006-01-23 16:13:22 -08004645#define BNX2_MAC_LOOPBACK 0
4646#define BNX2_PHY_LOOPBACK 1
4647
Michael Chanb6016b72005-05-26 13:03:09 -07004648static int
Michael Chanbc5a0692006-01-23 16:13:22 -08004649bnx2_run_loopback(struct bnx2 *bp, int loopback_mode)
Michael Chanb6016b72005-05-26 13:03:09 -07004650{
4651 unsigned int pkt_size, num_pkts, i;
4652 struct sk_buff *skb, *rx_skb;
4653 unsigned char *packet;
Michael Chanbc5a0692006-01-23 16:13:22 -08004654 u16 rx_start_idx, rx_idx;
Michael Chanb6016b72005-05-26 13:03:09 -07004655 dma_addr_t map;
4656 struct tx_bd *txbd;
4657 struct sw_bd *rx_buf;
4658 struct l2_fhdr *rx_hdr;
4659 int ret = -ENODEV;
4660
Michael Chanbc5a0692006-01-23 16:13:22 -08004661 if (loopback_mode == BNX2_MAC_LOOPBACK) {
4662 bp->loopback = MAC_LOOPBACK;
4663 bnx2_set_mac_loopback(bp);
4664 }
4665 else if (loopback_mode == BNX2_PHY_LOOPBACK) {
Michael Chan80be4432006-11-19 14:07:28 -08004666 bp->loopback = PHY_LOOPBACK;
Michael Chanbc5a0692006-01-23 16:13:22 -08004667 bnx2_set_phy_loopback(bp);
4668 }
4669 else
4670 return -EINVAL;
Michael Chanb6016b72005-05-26 13:03:09 -07004671
4672 pkt_size = 1514;
Michael Chan932f3772006-08-15 01:39:36 -07004673 skb = netdev_alloc_skb(bp->dev, pkt_size);
John W. Linvilleb6cbc3b62005-11-10 12:58:00 -08004674 if (!skb)
4675 return -ENOMEM;
Michael Chanb6016b72005-05-26 13:03:09 -07004676 packet = skb_put(skb, pkt_size);
Michael Chan66342922006-12-14 15:57:04 -08004677 memcpy(packet, bp->dev->dev_addr, 6);
Michael Chanb6016b72005-05-26 13:03:09 -07004678 memset(packet + 6, 0x0, 8);
4679 for (i = 14; i < pkt_size; i++)
4680 packet[i] = (unsigned char) (i & 0xff);
4681
4682 map = pci_map_single(bp->pdev, skb->data, pkt_size,
4683 PCI_DMA_TODEVICE);
4684
Michael Chanbf5295b2006-03-23 01:11:56 -08004685 REG_WR(bp, BNX2_HC_COMMAND,
4686 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
4687
Michael Chanb6016b72005-05-26 13:03:09 -07004688 REG_RD(bp, BNX2_HC_COMMAND);
4689
4690 udelay(5);
4691 rx_start_idx = bp->status_blk->status_rx_quick_consumer_index0;
4692
Michael Chanb6016b72005-05-26 13:03:09 -07004693 num_pkts = 0;
4694
Michael Chanbc5a0692006-01-23 16:13:22 -08004695 txbd = &bp->tx_desc_ring[TX_RING_IDX(bp->tx_prod)];
Michael Chanb6016b72005-05-26 13:03:09 -07004696
4697 txbd->tx_bd_haddr_hi = (u64) map >> 32;
4698 txbd->tx_bd_haddr_lo = (u64) map & 0xffffffff;
4699 txbd->tx_bd_mss_nbytes = pkt_size;
4700 txbd->tx_bd_vlan_tag_flags = TX_BD_FLAGS_START | TX_BD_FLAGS_END;
4701
4702 num_pkts++;
Michael Chanbc5a0692006-01-23 16:13:22 -08004703 bp->tx_prod = NEXT_TX_BD(bp->tx_prod);
4704 bp->tx_prod_bseq += pkt_size;
Michael Chanb6016b72005-05-26 13:03:09 -07004705
Michael Chan234754d2006-11-19 14:11:41 -08004706 REG_WR16(bp, bp->tx_bidx_addr, bp->tx_prod);
4707 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07004708
4709 udelay(100);
4710
Michael Chanbf5295b2006-03-23 01:11:56 -08004711 REG_WR(bp, BNX2_HC_COMMAND,
4712 bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW_WO_INT);
4713
Michael Chanb6016b72005-05-26 13:03:09 -07004714 REG_RD(bp, BNX2_HC_COMMAND);
4715
4716 udelay(5);
4717
4718 pci_unmap_single(bp->pdev, map, pkt_size, PCI_DMA_TODEVICE);
Michael Chan745720e2006-06-29 12:37:41 -07004719 dev_kfree_skb(skb);
Michael Chanb6016b72005-05-26 13:03:09 -07004720
Michael Chanbc5a0692006-01-23 16:13:22 -08004721 if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_prod) {
Michael Chanb6016b72005-05-26 13:03:09 -07004722 goto loopback_test_done;
4723 }
4724
4725 rx_idx = bp->status_blk->status_rx_quick_consumer_index0;
4726 if (rx_idx != rx_start_idx + num_pkts) {
4727 goto loopback_test_done;
4728 }
4729
4730 rx_buf = &bp->rx_buf_ring[rx_start_idx];
4731 rx_skb = rx_buf->skb;
4732
4733 rx_hdr = (struct l2_fhdr *) rx_skb->data;
4734 skb_reserve(rx_skb, bp->rx_offset);
4735
4736 pci_dma_sync_single_for_cpu(bp->pdev,
4737 pci_unmap_addr(rx_buf, mapping),
4738 bp->rx_buf_size, PCI_DMA_FROMDEVICE);
4739
Michael Chanade2bfe2006-01-23 16:09:51 -08004740 if (rx_hdr->l2_fhdr_status &
Michael Chanb6016b72005-05-26 13:03:09 -07004741 (L2_FHDR_ERRORS_BAD_CRC |
4742 L2_FHDR_ERRORS_PHY_DECODE |
4743 L2_FHDR_ERRORS_ALIGNMENT |
4744 L2_FHDR_ERRORS_TOO_SHORT |
4745 L2_FHDR_ERRORS_GIANT_FRAME)) {
4746
4747 goto loopback_test_done;
4748 }
4749
4750 if ((rx_hdr->l2_fhdr_pkt_len - 4) != pkt_size) {
4751 goto loopback_test_done;
4752 }
4753
4754 for (i = 14; i < pkt_size; i++) {
4755 if (*(rx_skb->data + i) != (unsigned char) (i & 0xff)) {
4756 goto loopback_test_done;
4757 }
4758 }
4759
4760 ret = 0;
4761
4762loopback_test_done:
4763 bp->loopback = 0;
4764 return ret;
4765}
4766
Michael Chanbc5a0692006-01-23 16:13:22 -08004767#define BNX2_MAC_LOOPBACK_FAILED 1
4768#define BNX2_PHY_LOOPBACK_FAILED 2
4769#define BNX2_LOOPBACK_FAILED (BNX2_MAC_LOOPBACK_FAILED | \
4770 BNX2_PHY_LOOPBACK_FAILED)
4771
4772static int
4773bnx2_test_loopback(struct bnx2 *bp)
4774{
4775 int rc = 0;
4776
4777 if (!netif_running(bp->dev))
4778 return BNX2_LOOPBACK_FAILED;
4779
4780 bnx2_reset_nic(bp, BNX2_DRV_MSG_CODE_RESET);
4781 spin_lock_bh(&bp->phy_lock);
4782 bnx2_init_phy(bp);
4783 spin_unlock_bh(&bp->phy_lock);
4784 if (bnx2_run_loopback(bp, BNX2_MAC_LOOPBACK))
4785 rc |= BNX2_MAC_LOOPBACK_FAILED;
4786 if (bnx2_run_loopback(bp, BNX2_PHY_LOOPBACK))
4787 rc |= BNX2_PHY_LOOPBACK_FAILED;
4788 return rc;
4789}
4790
Michael Chanb6016b72005-05-26 13:03:09 -07004791#define NVRAM_SIZE 0x200
4792#define CRC32_RESIDUAL 0xdebb20e3
4793
4794static int
4795bnx2_test_nvram(struct bnx2 *bp)
4796{
4797 u32 buf[NVRAM_SIZE / 4];
4798 u8 *data = (u8 *) buf;
4799 int rc = 0;
4800 u32 magic, csum;
4801
4802 if ((rc = bnx2_nvram_read(bp, 0, data, 4)) != 0)
4803 goto test_nvram_done;
4804
4805 magic = be32_to_cpu(buf[0]);
4806 if (magic != 0x669955aa) {
4807 rc = -ENODEV;
4808 goto test_nvram_done;
4809 }
4810
4811 if ((rc = bnx2_nvram_read(bp, 0x100, data, NVRAM_SIZE)) != 0)
4812 goto test_nvram_done;
4813
4814 csum = ether_crc_le(0x100, data);
4815 if (csum != CRC32_RESIDUAL) {
4816 rc = -ENODEV;
4817 goto test_nvram_done;
4818 }
4819
4820 csum = ether_crc_le(0x100, data + 0x100);
4821 if (csum != CRC32_RESIDUAL) {
4822 rc = -ENODEV;
4823 }
4824
4825test_nvram_done:
4826 return rc;
4827}
4828
4829static int
4830bnx2_test_link(struct bnx2 *bp)
4831{
4832 u32 bmsr;
4833
Michael Chanc770a652005-08-25 15:38:39 -07004834 spin_lock_bh(&bp->phy_lock);
Michael Chan27a005b2007-05-03 13:23:41 -07004835 bnx2_enable_bmsr1(bp);
4836 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
4837 bnx2_read_phy(bp, bp->mii_bmsr1, &bmsr);
4838 bnx2_disable_bmsr1(bp);
Michael Chanc770a652005-08-25 15:38:39 -07004839 spin_unlock_bh(&bp->phy_lock);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04004840
Michael Chanb6016b72005-05-26 13:03:09 -07004841 if (bmsr & BMSR_LSTATUS) {
4842 return 0;
4843 }
4844 return -ENODEV;
4845}
4846
4847static int
4848bnx2_test_intr(struct bnx2 *bp)
4849{
4850 int i;
Michael Chanb6016b72005-05-26 13:03:09 -07004851 u16 status_idx;
4852
4853 if (!netif_running(bp->dev))
4854 return -ENODEV;
4855
4856 status_idx = REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff;
4857
4858 /* This register is not touched during run-time. */
Michael Chanbf5295b2006-03-23 01:11:56 -08004859 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd | BNX2_HC_COMMAND_COAL_NOW);
Michael Chanb6016b72005-05-26 13:03:09 -07004860 REG_RD(bp, BNX2_HC_COMMAND);
4861
4862 for (i = 0; i < 10; i++) {
4863 if ((REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD) & 0xffff) !=
4864 status_idx) {
4865
4866 break;
4867 }
4868
4869 msleep_interruptible(10);
4870 }
4871 if (i < 10)
4872 return 0;
4873
4874 return -ENODEV;
4875}
4876
4877static void
Michael Chan48b01e22006-11-19 14:08:00 -08004878bnx2_5706_serdes_timer(struct bnx2 *bp)
4879{
4880 spin_lock(&bp->phy_lock);
4881 if (bp->serdes_an_pending)
4882 bp->serdes_an_pending--;
4883 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
4884 u32 bmcr;
4885
4886 bp->current_interval = bp->timer_interval;
4887
Michael Chanca58c3a2007-05-03 13:22:52 -07004888 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004889
4890 if (bmcr & BMCR_ANENABLE) {
4891 u32 phy1, phy2;
4892
4893 bnx2_write_phy(bp, 0x1c, 0x7c00);
4894 bnx2_read_phy(bp, 0x1c, &phy1);
4895
4896 bnx2_write_phy(bp, 0x17, 0x0f01);
4897 bnx2_read_phy(bp, 0x15, &phy2);
4898 bnx2_write_phy(bp, 0x17, 0x0f01);
4899 bnx2_read_phy(bp, 0x15, &phy2);
4900
4901 if ((phy1 & 0x10) && /* SIGNAL DETECT */
4902 !(phy2 & 0x20)) { /* no CONFIG */
4903
4904 bmcr &= ~BMCR_ANENABLE;
4905 bmcr |= BMCR_SPEED1000 | BMCR_FULLDPLX;
Michael Chanca58c3a2007-05-03 13:22:52 -07004906 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004907 bp->phy_flags |= PHY_PARALLEL_DETECT_FLAG;
4908 }
4909 }
4910 }
4911 else if ((bp->link_up) && (bp->autoneg & AUTONEG_SPEED) &&
4912 (bp->phy_flags & PHY_PARALLEL_DETECT_FLAG)) {
4913 u32 phy2;
4914
4915 bnx2_write_phy(bp, 0x17, 0x0f01);
4916 bnx2_read_phy(bp, 0x15, &phy2);
4917 if (phy2 & 0x20) {
4918 u32 bmcr;
4919
Michael Chanca58c3a2007-05-03 13:22:52 -07004920 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004921 bmcr |= BMCR_ANENABLE;
Michael Chanca58c3a2007-05-03 13:22:52 -07004922 bnx2_write_phy(bp, bp->mii_bmcr, bmcr);
Michael Chan48b01e22006-11-19 14:08:00 -08004923
4924 bp->phy_flags &= ~PHY_PARALLEL_DETECT_FLAG;
4925 }
4926 } else
4927 bp->current_interval = bp->timer_interval;
4928
4929 spin_unlock(&bp->phy_lock);
4930}
4931
4932static void
Michael Chanf8dd0642006-11-19 14:08:29 -08004933bnx2_5708_serdes_timer(struct bnx2 *bp)
4934{
Michael Chan0d8a6572007-07-07 22:49:43 -07004935 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
4936 return;
4937
Michael Chanf8dd0642006-11-19 14:08:29 -08004938 if ((bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) == 0) {
4939 bp->serdes_an_pending = 0;
4940 return;
4941 }
4942
4943 spin_lock(&bp->phy_lock);
4944 if (bp->serdes_an_pending)
4945 bp->serdes_an_pending--;
4946 else if ((bp->link_up == 0) && (bp->autoneg & AUTONEG_SPEED)) {
4947 u32 bmcr;
4948
Michael Chanca58c3a2007-05-03 13:22:52 -07004949 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanf8dd0642006-11-19 14:08:29 -08004950 if (bmcr & BMCR_ANENABLE) {
Michael Chan605a9e22007-05-03 13:23:13 -07004951 bnx2_enable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08004952 bp->current_interval = SERDES_FORCED_TIMEOUT;
4953 } else {
Michael Chan605a9e22007-05-03 13:23:13 -07004954 bnx2_disable_forced_2g5(bp);
Michael Chanf8dd0642006-11-19 14:08:29 -08004955 bp->serdes_an_pending = 2;
4956 bp->current_interval = bp->timer_interval;
4957 }
4958
4959 } else
4960 bp->current_interval = bp->timer_interval;
4961
4962 spin_unlock(&bp->phy_lock);
4963}
4964
4965static void
Michael Chanb6016b72005-05-26 13:03:09 -07004966bnx2_timer(unsigned long data)
4967{
4968 struct bnx2 *bp = (struct bnx2 *) data;
Michael Chanb6016b72005-05-26 13:03:09 -07004969
Michael Chancd339a02005-08-25 15:35:24 -07004970 if (!netif_running(bp->dev))
4971 return;
4972
Michael Chanb6016b72005-05-26 13:03:09 -07004973 if (atomic_read(&bp->intr_sem) != 0)
4974 goto bnx2_restart_timer;
4975
Michael Chandf149d72007-07-07 22:51:36 -07004976 bnx2_send_heart_beat(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004977
Michael Chancea94db2006-06-12 22:16:13 -07004978 bp->stats_blk->stat_FwRxDrop = REG_RD_IND(bp, BNX2_FW_RX_DROP_COUNT);
4979
Michael Chan02537b062007-06-04 21:24:07 -07004980 /* workaround occasional corrupted counters */
4981 if (CHIP_NUM(bp) == CHIP_NUM_5708 && bp->stats_ticks)
4982 REG_WR(bp, BNX2_HC_COMMAND, bp->hc_cmd |
4983 BNX2_HC_COMMAND_STATS_NOW);
4984
Michael Chanf8dd0642006-11-19 14:08:29 -08004985 if (bp->phy_flags & PHY_SERDES_FLAG) {
4986 if (CHIP_NUM(bp) == CHIP_NUM_5706)
4987 bnx2_5706_serdes_timer(bp);
Michael Chan27a005b2007-05-03 13:23:41 -07004988 else
Michael Chanf8dd0642006-11-19 14:08:29 -08004989 bnx2_5708_serdes_timer(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07004990 }
4991
4992bnx2_restart_timer:
Michael Chancd339a02005-08-25 15:35:24 -07004993 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07004994}
4995
Michael Chan8e6a72c2007-05-03 13:24:48 -07004996static int
4997bnx2_request_irq(struct bnx2 *bp)
4998{
4999 struct net_device *dev = bp->dev;
5000 int rc = 0;
5001
5002 if (bp->flags & USING_MSI_FLAG) {
5003 irq_handler_t fn = bnx2_msi;
5004
5005 if (bp->flags & ONE_SHOT_MSI_FLAG)
5006 fn = bnx2_msi_1shot;
5007
5008 rc = request_irq(bp->pdev->irq, fn, 0, dev->name, dev);
5009 } else
5010 rc = request_irq(bp->pdev->irq, bnx2_interrupt,
5011 IRQF_SHARED, dev->name, dev);
5012 return rc;
5013}
5014
5015static void
5016bnx2_free_irq(struct bnx2 *bp)
5017{
5018 struct net_device *dev = bp->dev;
5019
5020 if (bp->flags & USING_MSI_FLAG) {
5021 free_irq(bp->pdev->irq, dev);
5022 pci_disable_msi(bp->pdev);
5023 bp->flags &= ~(USING_MSI_FLAG | ONE_SHOT_MSI_FLAG);
5024 } else
5025 free_irq(bp->pdev->irq, dev);
5026}
5027
Michael Chanb6016b72005-05-26 13:03:09 -07005028/* Called with rtnl_lock */
5029static int
5030bnx2_open(struct net_device *dev)
5031{
Michael Chan972ec0d2006-01-23 16:12:43 -08005032 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005033 int rc;
5034
Michael Chan1b2f9222007-05-03 13:20:19 -07005035 netif_carrier_off(dev);
5036
Pavel Machek829ca9a2005-09-03 15:56:56 -07005037 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07005038 bnx2_disable_int(bp);
5039
5040 rc = bnx2_alloc_mem(bp);
5041 if (rc)
5042 return rc;
5043
Michael Chan8e6a72c2007-05-03 13:24:48 -07005044 if ((bp->flags & MSI_CAP_FLAG) && !disable_msi) {
Michael Chanb6016b72005-05-26 13:03:09 -07005045 if (pci_enable_msi(bp->pdev) == 0) {
5046 bp->flags |= USING_MSI_FLAG;
Michael Chan8e6a72c2007-05-03 13:24:48 -07005047 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5048 bp->flags |= ONE_SHOT_MSI_FLAG;
Michael Chanb6016b72005-05-26 13:03:09 -07005049 }
5050 }
Michael Chan8e6a72c2007-05-03 13:24:48 -07005051 rc = bnx2_request_irq(bp);
5052
Michael Chanb6016b72005-05-26 13:03:09 -07005053 if (rc) {
5054 bnx2_free_mem(bp);
5055 return rc;
5056 }
5057
5058 rc = bnx2_init_nic(bp);
5059
5060 if (rc) {
Michael Chan8e6a72c2007-05-03 13:24:48 -07005061 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005062 bnx2_free_skbs(bp);
5063 bnx2_free_mem(bp);
5064 return rc;
5065 }
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005066
Michael Chancd339a02005-08-25 15:35:24 -07005067 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005068
5069 atomic_set(&bp->intr_sem, 0);
5070
5071 bnx2_enable_int(bp);
5072
5073 if (bp->flags & USING_MSI_FLAG) {
5074 /* Test MSI to make sure it is working
5075 * If MSI test fails, go back to INTx mode
5076 */
5077 if (bnx2_test_intr(bp) != 0) {
5078 printk(KERN_WARNING PFX "%s: No interrupt was generated"
5079 " using MSI, switching to INTx mode. Please"
5080 " report this failure to the PCI maintainer"
5081 " and include system chipset information.\n",
5082 bp->dev->name);
5083
5084 bnx2_disable_int(bp);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005085 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005086
5087 rc = bnx2_init_nic(bp);
5088
Michael Chan8e6a72c2007-05-03 13:24:48 -07005089 if (!rc)
5090 rc = bnx2_request_irq(bp);
5091
Michael Chanb6016b72005-05-26 13:03:09 -07005092 if (rc) {
5093 bnx2_free_skbs(bp);
5094 bnx2_free_mem(bp);
5095 del_timer_sync(&bp->timer);
5096 return rc;
5097 }
5098 bnx2_enable_int(bp);
5099 }
5100 }
5101 if (bp->flags & USING_MSI_FLAG) {
5102 printk(KERN_INFO PFX "%s: using MSI\n", dev->name);
5103 }
5104
5105 netif_start_queue(dev);
5106
5107 return 0;
5108}
5109
5110static void
David Howellsc4028952006-11-22 14:57:56 +00005111bnx2_reset_task(struct work_struct *work)
Michael Chanb6016b72005-05-26 13:03:09 -07005112{
David Howellsc4028952006-11-22 14:57:56 +00005113 struct bnx2 *bp = container_of(work, struct bnx2, reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07005114
Michael Chanafdc08b2005-08-25 15:34:29 -07005115 if (!netif_running(bp->dev))
5116 return;
5117
5118 bp->in_reset_task = 1;
Michael Chanb6016b72005-05-26 13:03:09 -07005119 bnx2_netif_stop(bp);
5120
5121 bnx2_init_nic(bp);
5122
5123 atomic_set(&bp->intr_sem, 1);
5124 bnx2_netif_start(bp);
Michael Chanafdc08b2005-08-25 15:34:29 -07005125 bp->in_reset_task = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005126}
5127
5128static void
5129bnx2_tx_timeout(struct net_device *dev)
5130{
Michael Chan972ec0d2006-01-23 16:12:43 -08005131 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005132
5133 /* This allows the netif to be shutdown gracefully before resetting */
5134 schedule_work(&bp->reset_task);
5135}
5136
5137#ifdef BCM_VLAN
5138/* Called with rtnl_lock */
5139static void
5140bnx2_vlan_rx_register(struct net_device *dev, struct vlan_group *vlgrp)
5141{
Michael Chan972ec0d2006-01-23 16:12:43 -08005142 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005143
5144 bnx2_netif_stop(bp);
5145
5146 bp->vlgrp = vlgrp;
5147 bnx2_set_rx_mode(dev);
5148
5149 bnx2_netif_start(bp);
5150}
Michael Chanb6016b72005-05-26 13:03:09 -07005151#endif
5152
Herbert Xu932ff272006-06-09 12:20:56 -07005153/* Called with netif_tx_lock.
Michael Chan2f8af122006-08-15 01:39:10 -07005154 * bnx2_tx_int() runs without netif_tx_lock unless it needs to call
5155 * netif_wake_queue().
Michael Chanb6016b72005-05-26 13:03:09 -07005156 */
5157static int
5158bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
5159{
Michael Chan972ec0d2006-01-23 16:12:43 -08005160 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005161 dma_addr_t mapping;
5162 struct tx_bd *txbd;
5163 struct sw_bd *tx_buf;
5164 u32 len, vlan_tag_flags, last_frag, mss;
5165 u16 prod, ring_prod;
5166 int i;
5167
Michael Chane89bbf12005-08-25 15:36:58 -07005168 if (unlikely(bnx2_tx_avail(bp) < (skb_shinfo(skb)->nr_frags + 1))) {
Michael Chanb6016b72005-05-26 13:03:09 -07005169 netif_stop_queue(dev);
5170 printk(KERN_ERR PFX "%s: BUG! Tx ring full when queue awake!\n",
5171 dev->name);
5172
5173 return NETDEV_TX_BUSY;
5174 }
5175 len = skb_headlen(skb);
5176 prod = bp->tx_prod;
5177 ring_prod = TX_RING_IDX(prod);
5178
5179 vlan_tag_flags = 0;
Patrick McHardy84fa7932006-08-29 16:44:56 -07005180 if (skb->ip_summed == CHECKSUM_PARTIAL) {
Michael Chanb6016b72005-05-26 13:03:09 -07005181 vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
5182 }
5183
5184 if (bp->vlgrp != 0 && vlan_tx_tag_present(skb)) {
5185 vlan_tag_flags |=
5186 (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
5187 }
Michael Chanfde82052007-05-03 17:23:35 -07005188 if ((mss = skb_shinfo(skb)->gso_size)) {
Michael Chanb6016b72005-05-26 13:03:09 -07005189 u32 tcp_opt_len, ip_tcp_len;
Arnaldo Carvalho de Meloeddc9ec2007-04-20 22:47:35 -07005190 struct iphdr *iph;
Michael Chanb6016b72005-05-26 13:03:09 -07005191
Michael Chanb6016b72005-05-26 13:03:09 -07005192 vlan_tag_flags |= TX_BD_FLAGS_SW_LSO;
5193
Michael Chan4666f872007-05-03 13:22:28 -07005194 tcp_opt_len = tcp_optlen(skb);
Arnaldo Carvalho de Meloab6a5bb2007-03-18 17:43:48 -07005195
Michael Chan4666f872007-05-03 13:22:28 -07005196 if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6) {
5197 u32 tcp_off = skb_transport_offset(skb) -
5198 sizeof(struct ipv6hdr) - ETH_HLEN;
Michael Chanb6016b72005-05-26 13:03:09 -07005199
Michael Chan4666f872007-05-03 13:22:28 -07005200 vlan_tag_flags |= ((tcp_opt_len >> 2) << 8) |
5201 TX_BD_FLAGS_SW_FLAGS;
5202 if (likely(tcp_off == 0))
5203 vlan_tag_flags &= ~TX_BD_FLAGS_TCP6_OFF0_MSK;
5204 else {
5205 tcp_off >>= 3;
5206 vlan_tag_flags |= ((tcp_off & 0x3) <<
5207 TX_BD_FLAGS_TCP6_OFF0_SHL) |
5208 ((tcp_off & 0x10) <<
5209 TX_BD_FLAGS_TCP6_OFF4_SHL);
5210 mss |= (tcp_off & 0xc) << TX_BD_TCP6_OFF2_SHL;
5211 }
5212 } else {
5213 if (skb_header_cloned(skb) &&
5214 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)) {
5215 dev_kfree_skb(skb);
5216 return NETDEV_TX_OK;
5217 }
5218
5219 ip_tcp_len = ip_hdrlen(skb) + sizeof(struct tcphdr);
5220
5221 iph = ip_hdr(skb);
5222 iph->check = 0;
5223 iph->tot_len = htons(mss + ip_tcp_len + tcp_opt_len);
5224 tcp_hdr(skb)->check = ~csum_tcpudp_magic(iph->saddr,
5225 iph->daddr, 0,
5226 IPPROTO_TCP,
5227 0);
5228 if (tcp_opt_len || (iph->ihl > 5)) {
5229 vlan_tag_flags |= ((iph->ihl - 5) +
5230 (tcp_opt_len >> 2)) << 8;
5231 }
Michael Chanb6016b72005-05-26 13:03:09 -07005232 }
Michael Chan4666f872007-05-03 13:22:28 -07005233 } else
Michael Chanb6016b72005-05-26 13:03:09 -07005234 mss = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005235
5236 mapping = pci_map_single(bp->pdev, skb->data, len, PCI_DMA_TODEVICE);
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005237
Michael Chanb6016b72005-05-26 13:03:09 -07005238 tx_buf = &bp->tx_buf_ring[ring_prod];
5239 tx_buf->skb = skb;
5240 pci_unmap_addr_set(tx_buf, mapping, mapping);
5241
5242 txbd = &bp->tx_desc_ring[ring_prod];
5243
5244 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5245 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5246 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5247 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags | TX_BD_FLAGS_START;
5248
5249 last_frag = skb_shinfo(skb)->nr_frags;
5250
5251 for (i = 0; i < last_frag; i++) {
5252 skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
5253
5254 prod = NEXT_TX_BD(prod);
5255 ring_prod = TX_RING_IDX(prod);
5256 txbd = &bp->tx_desc_ring[ring_prod];
5257
5258 len = frag->size;
5259 mapping = pci_map_page(bp->pdev, frag->page, frag->page_offset,
5260 len, PCI_DMA_TODEVICE);
5261 pci_unmap_addr_set(&bp->tx_buf_ring[ring_prod],
5262 mapping, mapping);
5263
5264 txbd->tx_bd_haddr_hi = (u64) mapping >> 32;
5265 txbd->tx_bd_haddr_lo = (u64) mapping & 0xffffffff;
5266 txbd->tx_bd_mss_nbytes = len | (mss << 16);
5267 txbd->tx_bd_vlan_tag_flags = vlan_tag_flags;
5268
5269 }
5270 txbd->tx_bd_vlan_tag_flags |= TX_BD_FLAGS_END;
5271
5272 prod = NEXT_TX_BD(prod);
5273 bp->tx_prod_bseq += skb->len;
5274
Michael Chan234754d2006-11-19 14:11:41 -08005275 REG_WR16(bp, bp->tx_bidx_addr, prod);
5276 REG_WR(bp, bp->tx_bseq_addr, bp->tx_prod_bseq);
Michael Chanb6016b72005-05-26 13:03:09 -07005277
5278 mmiowb();
5279
5280 bp->tx_prod = prod;
5281 dev->trans_start = jiffies;
5282
Michael Chane89bbf12005-08-25 15:36:58 -07005283 if (unlikely(bnx2_tx_avail(bp) <= MAX_SKB_FRAGS)) {
Michael Chane89bbf12005-08-25 15:36:58 -07005284 netif_stop_queue(dev);
Michael Chan2f8af122006-08-15 01:39:10 -07005285 if (bnx2_tx_avail(bp) > bp->tx_wake_thresh)
Michael Chane89bbf12005-08-25 15:36:58 -07005286 netif_wake_queue(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005287 }
5288
5289 return NETDEV_TX_OK;
5290}
5291
5292/* Called with rtnl_lock */
5293static int
5294bnx2_close(struct net_device *dev)
5295{
Michael Chan972ec0d2006-01-23 16:12:43 -08005296 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005297 u32 reset_code;
5298
Michael Chanafdc08b2005-08-25 15:34:29 -07005299 /* Calling flush_scheduled_work() may deadlock because
5300 * linkwatch_event() may be on the workqueue and it will try to get
5301 * the rtnl_lock which we are holding.
5302 */
5303 while (bp->in_reset_task)
5304 msleep(1);
5305
Michael Chanb6016b72005-05-26 13:03:09 -07005306 bnx2_netif_stop(bp);
5307 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08005308 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07005309 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08005310 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07005311 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
5312 else
5313 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
5314 bnx2_reset_chip(bp, reset_code);
Michael Chan8e6a72c2007-05-03 13:24:48 -07005315 bnx2_free_irq(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07005316 bnx2_free_skbs(bp);
5317 bnx2_free_mem(bp);
5318 bp->link_up = 0;
5319 netif_carrier_off(bp->dev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07005320 bnx2_set_power_state(bp, PCI_D3hot);
Michael Chanb6016b72005-05-26 13:03:09 -07005321 return 0;
5322}
5323
5324#define GET_NET_STATS64(ctr) \
5325 (unsigned long) ((unsigned long) (ctr##_hi) << 32) + \
5326 (unsigned long) (ctr##_lo)
5327
5328#define GET_NET_STATS32(ctr) \
5329 (ctr##_lo)
5330
5331#if (BITS_PER_LONG == 64)
5332#define GET_NET_STATS GET_NET_STATS64
5333#else
5334#define GET_NET_STATS GET_NET_STATS32
5335#endif
5336
5337static struct net_device_stats *
5338bnx2_get_stats(struct net_device *dev)
5339{
Michael Chan972ec0d2006-01-23 16:12:43 -08005340 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005341 struct statistics_block *stats_blk = bp->stats_blk;
5342 struct net_device_stats *net_stats = &bp->net_stats;
5343
5344 if (bp->stats_blk == NULL) {
5345 return net_stats;
5346 }
5347 net_stats->rx_packets =
5348 GET_NET_STATS(stats_blk->stat_IfHCInUcastPkts) +
5349 GET_NET_STATS(stats_blk->stat_IfHCInMulticastPkts) +
5350 GET_NET_STATS(stats_blk->stat_IfHCInBroadcastPkts);
5351
5352 net_stats->tx_packets =
5353 GET_NET_STATS(stats_blk->stat_IfHCOutUcastPkts) +
5354 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts) +
5355 GET_NET_STATS(stats_blk->stat_IfHCOutBroadcastPkts);
5356
5357 net_stats->rx_bytes =
5358 GET_NET_STATS(stats_blk->stat_IfHCInOctets);
5359
5360 net_stats->tx_bytes =
5361 GET_NET_STATS(stats_blk->stat_IfHCOutOctets);
5362
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005363 net_stats->multicast =
Michael Chanb6016b72005-05-26 13:03:09 -07005364 GET_NET_STATS(stats_blk->stat_IfHCOutMulticastPkts);
5365
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005366 net_stats->collisions =
Michael Chanb6016b72005-05-26 13:03:09 -07005367 (unsigned long) stats_blk->stat_EtherStatsCollisions;
5368
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005369 net_stats->rx_length_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005370 (unsigned long) (stats_blk->stat_EtherStatsUndersizePkts +
5371 stats_blk->stat_EtherStatsOverrsizePkts);
5372
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005373 net_stats->rx_over_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005374 (unsigned long) stats_blk->stat_IfInMBUFDiscards;
5375
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005376 net_stats->rx_frame_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005377 (unsigned long) stats_blk->stat_Dot3StatsAlignmentErrors;
5378
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005379 net_stats->rx_crc_errors =
Michael Chanb6016b72005-05-26 13:03:09 -07005380 (unsigned long) stats_blk->stat_Dot3StatsFCSErrors;
5381
5382 net_stats->rx_errors = net_stats->rx_length_errors +
5383 net_stats->rx_over_errors + net_stats->rx_frame_errors +
5384 net_stats->rx_crc_errors;
5385
5386 net_stats->tx_aborted_errors =
5387 (unsigned long) (stats_blk->stat_Dot3StatsExcessiveCollisions +
5388 stats_blk->stat_Dot3StatsLateCollisions);
5389
Michael Chan5b0c76a2005-11-04 08:45:49 -08005390 if ((CHIP_NUM(bp) == CHIP_NUM_5706) ||
5391 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07005392 net_stats->tx_carrier_errors = 0;
5393 else {
5394 net_stats->tx_carrier_errors =
5395 (unsigned long)
5396 stats_blk->stat_Dot3StatsCarrierSenseErrors;
5397 }
5398
5399 net_stats->tx_errors =
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005400 (unsigned long)
Michael Chanb6016b72005-05-26 13:03:09 -07005401 stats_blk->stat_emac_tx_stat_dot3statsinternalmactransmiterrors
5402 +
5403 net_stats->tx_aborted_errors +
5404 net_stats->tx_carrier_errors;
5405
Michael Chancea94db2006-06-12 22:16:13 -07005406 net_stats->rx_missed_errors =
5407 (unsigned long) (stats_blk->stat_IfInMBUFDiscards +
5408 stats_blk->stat_FwRxDrop);
5409
Michael Chanb6016b72005-05-26 13:03:09 -07005410 return net_stats;
5411}
5412
5413/* All ethtool functions called with rtnl_lock */
5414
5415static int
5416bnx2_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
5417{
Michael Chan972ec0d2006-01-23 16:12:43 -08005418 struct bnx2 *bp = netdev_priv(dev);
Michael Chan7b6b8342007-07-07 22:50:15 -07005419 int support_serdes = 0, support_copper = 0;
Michael Chanb6016b72005-05-26 13:03:09 -07005420
5421 cmd->supported = SUPPORTED_Autoneg;
Michael Chan7b6b8342007-07-07 22:50:15 -07005422 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
5423 support_serdes = 1;
5424 support_copper = 1;
5425 } else if (bp->phy_port == PORT_FIBRE)
5426 support_serdes = 1;
5427 else
5428 support_copper = 1;
5429
5430 if (support_serdes) {
Michael Chanb6016b72005-05-26 13:03:09 -07005431 cmd->supported |= SUPPORTED_1000baseT_Full |
5432 SUPPORTED_FIBRE;
Michael Chan605a9e22007-05-03 13:23:13 -07005433 if (bp->phy_flags & PHY_2_5G_CAPABLE_FLAG)
5434 cmd->supported |= SUPPORTED_2500baseX_Full;
Michael Chanb6016b72005-05-26 13:03:09 -07005435
Michael Chanb6016b72005-05-26 13:03:09 -07005436 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005437 if (support_copper) {
Michael Chanb6016b72005-05-26 13:03:09 -07005438 cmd->supported |= SUPPORTED_10baseT_Half |
5439 SUPPORTED_10baseT_Full |
5440 SUPPORTED_100baseT_Half |
5441 SUPPORTED_100baseT_Full |
5442 SUPPORTED_1000baseT_Full |
5443 SUPPORTED_TP;
5444
Michael Chanb6016b72005-05-26 13:03:09 -07005445 }
5446
Michael Chan7b6b8342007-07-07 22:50:15 -07005447 spin_lock_bh(&bp->phy_lock);
5448 cmd->port = bp->phy_port;
Michael Chanb6016b72005-05-26 13:03:09 -07005449 cmd->advertising = bp->advertising;
5450
5451 if (bp->autoneg & AUTONEG_SPEED) {
5452 cmd->autoneg = AUTONEG_ENABLE;
5453 }
5454 else {
5455 cmd->autoneg = AUTONEG_DISABLE;
5456 }
5457
5458 if (netif_carrier_ok(dev)) {
5459 cmd->speed = bp->line_speed;
5460 cmd->duplex = bp->duplex;
5461 }
5462 else {
5463 cmd->speed = -1;
5464 cmd->duplex = -1;
5465 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005466 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005467
5468 cmd->transceiver = XCVR_INTERNAL;
5469 cmd->phy_address = bp->phy_addr;
5470
5471 return 0;
5472}
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005473
Michael Chanb6016b72005-05-26 13:03:09 -07005474static int
5475bnx2_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
5476{
Michael Chan972ec0d2006-01-23 16:12:43 -08005477 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005478 u8 autoneg = bp->autoneg;
5479 u8 req_duplex = bp->req_duplex;
5480 u16 req_line_speed = bp->req_line_speed;
5481 u32 advertising = bp->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07005482 int err = -EINVAL;
5483
5484 spin_lock_bh(&bp->phy_lock);
5485
5486 if (cmd->port != PORT_TP && cmd->port != PORT_FIBRE)
5487 goto err_out_unlock;
5488
5489 if (cmd->port != bp->phy_port && !(bp->phy_flags & REMOTE_PHY_CAP_FLAG))
5490 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005491
5492 if (cmd->autoneg == AUTONEG_ENABLE) {
5493 autoneg |= AUTONEG_SPEED;
5494
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005495 cmd->advertising &= ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07005496
5497 /* allow advertising 1 speed */
5498 if ((cmd->advertising == ADVERTISED_10baseT_Half) ||
5499 (cmd->advertising == ADVERTISED_10baseT_Full) ||
5500 (cmd->advertising == ADVERTISED_100baseT_Half) ||
5501 (cmd->advertising == ADVERTISED_100baseT_Full)) {
5502
Michael Chan7b6b8342007-07-07 22:50:15 -07005503 if (cmd->port == PORT_FIBRE)
5504 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005505
5506 advertising = cmd->advertising;
5507
Michael Chan27a005b2007-05-03 13:23:41 -07005508 } else if (cmd->advertising == ADVERTISED_2500baseX_Full) {
Michael Chan7b6b8342007-07-07 22:50:15 -07005509 if (!(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG) ||
5510 (cmd->port == PORT_TP))
5511 goto err_out_unlock;
5512 } else if (cmd->advertising == ADVERTISED_1000baseT_Full)
Michael Chanb6016b72005-05-26 13:03:09 -07005513 advertising = cmd->advertising;
Michael Chan7b6b8342007-07-07 22:50:15 -07005514 else if (cmd->advertising == ADVERTISED_1000baseT_Half)
5515 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005516 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07005517 if (cmd->port == PORT_FIBRE)
Michael Chanb6016b72005-05-26 13:03:09 -07005518 advertising = ETHTOOL_ALL_FIBRE_SPEED;
Michael Chan7b6b8342007-07-07 22:50:15 -07005519 else
Michael Chanb6016b72005-05-26 13:03:09 -07005520 advertising = ETHTOOL_ALL_COPPER_SPEED;
Michael Chanb6016b72005-05-26 13:03:09 -07005521 }
5522 advertising |= ADVERTISED_Autoneg;
5523 }
5524 else {
Michael Chan7b6b8342007-07-07 22:50:15 -07005525 if (cmd->port == PORT_FIBRE) {
Michael Chan80be4432006-11-19 14:07:28 -08005526 if ((cmd->speed != SPEED_1000 &&
5527 cmd->speed != SPEED_2500) ||
5528 (cmd->duplex != DUPLEX_FULL))
Michael Chan7b6b8342007-07-07 22:50:15 -07005529 goto err_out_unlock;
Michael Chan80be4432006-11-19 14:07:28 -08005530
5531 if (cmd->speed == SPEED_2500 &&
5532 !(bp->phy_flags & PHY_2_5G_CAPABLE_FLAG))
Michael Chan7b6b8342007-07-07 22:50:15 -07005533 goto err_out_unlock;
Michael Chanb6016b72005-05-26 13:03:09 -07005534 }
Michael Chan7b6b8342007-07-07 22:50:15 -07005535 else if (cmd->speed == SPEED_1000 || cmd->speed == SPEED_2500)
5536 goto err_out_unlock;
5537
Michael Chanb6016b72005-05-26 13:03:09 -07005538 autoneg &= ~AUTONEG_SPEED;
5539 req_line_speed = cmd->speed;
5540 req_duplex = cmd->duplex;
5541 advertising = 0;
5542 }
5543
5544 bp->autoneg = autoneg;
5545 bp->advertising = advertising;
5546 bp->req_line_speed = req_line_speed;
5547 bp->req_duplex = req_duplex;
5548
Michael Chan7b6b8342007-07-07 22:50:15 -07005549 err = bnx2_setup_phy(bp, cmd->port);
Michael Chanb6016b72005-05-26 13:03:09 -07005550
Michael Chan7b6b8342007-07-07 22:50:15 -07005551err_out_unlock:
Michael Chanc770a652005-08-25 15:38:39 -07005552 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005553
Michael Chan7b6b8342007-07-07 22:50:15 -07005554 return err;
Michael Chanb6016b72005-05-26 13:03:09 -07005555}
5556
5557static void
5558bnx2_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
5559{
Michael Chan972ec0d2006-01-23 16:12:43 -08005560 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005561
5562 strcpy(info->driver, DRV_MODULE_NAME);
5563 strcpy(info->version, DRV_MODULE_VERSION);
5564 strcpy(info->bus_info, pci_name(bp->pdev));
Michael Chan58fc2ea2007-07-07 22:52:02 -07005565 strcpy(info->fw_version, bp->fw_version);
Michael Chanb6016b72005-05-26 13:03:09 -07005566}
5567
Michael Chan244ac4f2006-03-20 17:48:46 -08005568#define BNX2_REGDUMP_LEN (32 * 1024)
5569
5570static int
5571bnx2_get_regs_len(struct net_device *dev)
5572{
5573 return BNX2_REGDUMP_LEN;
5574}
5575
5576static void
5577bnx2_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *_p)
5578{
5579 u32 *p = _p, i, offset;
5580 u8 *orig_p = _p;
5581 struct bnx2 *bp = netdev_priv(dev);
5582 u32 reg_boundaries[] = { 0x0000, 0x0098, 0x0400, 0x045c,
5583 0x0800, 0x0880, 0x0c00, 0x0c10,
5584 0x0c30, 0x0d08, 0x1000, 0x101c,
5585 0x1040, 0x1048, 0x1080, 0x10a4,
5586 0x1400, 0x1490, 0x1498, 0x14f0,
5587 0x1500, 0x155c, 0x1580, 0x15dc,
5588 0x1600, 0x1658, 0x1680, 0x16d8,
5589 0x1800, 0x1820, 0x1840, 0x1854,
5590 0x1880, 0x1894, 0x1900, 0x1984,
5591 0x1c00, 0x1c0c, 0x1c40, 0x1c54,
5592 0x1c80, 0x1c94, 0x1d00, 0x1d84,
5593 0x2000, 0x2030, 0x23c0, 0x2400,
5594 0x2800, 0x2820, 0x2830, 0x2850,
5595 0x2b40, 0x2c10, 0x2fc0, 0x3058,
5596 0x3c00, 0x3c94, 0x4000, 0x4010,
5597 0x4080, 0x4090, 0x43c0, 0x4458,
5598 0x4c00, 0x4c18, 0x4c40, 0x4c54,
5599 0x4fc0, 0x5010, 0x53c0, 0x5444,
5600 0x5c00, 0x5c18, 0x5c80, 0x5c90,
5601 0x5fc0, 0x6000, 0x6400, 0x6428,
5602 0x6800, 0x6848, 0x684c, 0x6860,
5603 0x6888, 0x6910, 0x8000 };
5604
5605 regs->version = 0;
5606
5607 memset(p, 0, BNX2_REGDUMP_LEN);
5608
5609 if (!netif_running(bp->dev))
5610 return;
5611
5612 i = 0;
5613 offset = reg_boundaries[0];
5614 p += offset;
5615 while (offset < BNX2_REGDUMP_LEN) {
5616 *p++ = REG_RD(bp, offset);
5617 offset += 4;
5618 if (offset == reg_boundaries[i + 1]) {
5619 offset = reg_boundaries[i + 2];
5620 p = (u32 *) (orig_p + offset);
5621 i += 2;
5622 }
5623 }
5624}
5625
Michael Chanb6016b72005-05-26 13:03:09 -07005626static void
5627bnx2_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
5628{
Michael Chan972ec0d2006-01-23 16:12:43 -08005629 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005630
5631 if (bp->flags & NO_WOL_FLAG) {
5632 wol->supported = 0;
5633 wol->wolopts = 0;
5634 }
5635 else {
5636 wol->supported = WAKE_MAGIC;
5637 if (bp->wol)
5638 wol->wolopts = WAKE_MAGIC;
5639 else
5640 wol->wolopts = 0;
5641 }
5642 memset(&wol->sopass, 0, sizeof(wol->sopass));
5643}
5644
5645static int
5646bnx2_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
5647{
Michael Chan972ec0d2006-01-23 16:12:43 -08005648 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005649
5650 if (wol->wolopts & ~WAKE_MAGIC)
5651 return -EINVAL;
5652
5653 if (wol->wolopts & WAKE_MAGIC) {
5654 if (bp->flags & NO_WOL_FLAG)
5655 return -EINVAL;
5656
5657 bp->wol = 1;
5658 }
5659 else {
5660 bp->wol = 0;
5661 }
5662 return 0;
5663}
5664
5665static int
5666bnx2_nway_reset(struct net_device *dev)
5667{
Michael Chan972ec0d2006-01-23 16:12:43 -08005668 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005669 u32 bmcr;
5670
5671 if (!(bp->autoneg & AUTONEG_SPEED)) {
5672 return -EINVAL;
5673 }
5674
Michael Chanc770a652005-08-25 15:38:39 -07005675 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005676
Michael Chan7b6b8342007-07-07 22:50:15 -07005677 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG) {
5678 int rc;
5679
5680 rc = bnx2_setup_remote_phy(bp, bp->phy_port);
5681 spin_unlock_bh(&bp->phy_lock);
5682 return rc;
5683 }
5684
Michael Chanb6016b72005-05-26 13:03:09 -07005685 /* Force a link down visible on the other side */
5686 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chanca58c3a2007-05-03 13:22:52 -07005687 bnx2_write_phy(bp, bp->mii_bmcr, BMCR_LOOPBACK);
Michael Chanc770a652005-08-25 15:38:39 -07005688 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005689
5690 msleep(20);
5691
Michael Chanc770a652005-08-25 15:38:39 -07005692 spin_lock_bh(&bp->phy_lock);
Michael Chanf8dd0642006-11-19 14:08:29 -08005693
5694 bp->current_interval = SERDES_AN_TIMEOUT;
5695 bp->serdes_an_pending = 1;
5696 mod_timer(&bp->timer, jiffies + bp->current_interval);
Michael Chanb6016b72005-05-26 13:03:09 -07005697 }
5698
Michael Chanca58c3a2007-05-03 13:22:52 -07005699 bnx2_read_phy(bp, bp->mii_bmcr, &bmcr);
Michael Chanb6016b72005-05-26 13:03:09 -07005700 bmcr &= ~BMCR_LOOPBACK;
Michael Chanca58c3a2007-05-03 13:22:52 -07005701 bnx2_write_phy(bp, bp->mii_bmcr, bmcr | BMCR_ANRESTART | BMCR_ANENABLE);
Michael Chanb6016b72005-05-26 13:03:09 -07005702
Michael Chanc770a652005-08-25 15:38:39 -07005703 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005704
5705 return 0;
5706}
5707
5708static int
5709bnx2_get_eeprom_len(struct net_device *dev)
5710{
Michael Chan972ec0d2006-01-23 16:12:43 -08005711 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005712
Michael Chan1122db72006-01-23 16:11:42 -08005713 if (bp->flash_info == NULL)
Michael Chanb6016b72005-05-26 13:03:09 -07005714 return 0;
5715
Michael Chan1122db72006-01-23 16:11:42 -08005716 return (int) bp->flash_size;
Michael Chanb6016b72005-05-26 13:03:09 -07005717}
5718
5719static int
5720bnx2_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
5721 u8 *eebuf)
5722{
Michael Chan972ec0d2006-01-23 16:12:43 -08005723 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005724 int rc;
5725
John W. Linville1064e942005-11-10 12:58:24 -08005726 /* parameters already validated in ethtool_get_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07005727
5728 rc = bnx2_nvram_read(bp, eeprom->offset, eebuf, eeprom->len);
5729
5730 return rc;
5731}
5732
5733static int
5734bnx2_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
5735 u8 *eebuf)
5736{
Michael Chan972ec0d2006-01-23 16:12:43 -08005737 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005738 int rc;
5739
John W. Linville1064e942005-11-10 12:58:24 -08005740 /* parameters already validated in ethtool_set_eeprom */
Michael Chanb6016b72005-05-26 13:03:09 -07005741
5742 rc = bnx2_nvram_write(bp, eeprom->offset, eebuf, eeprom->len);
5743
5744 return rc;
5745}
5746
5747static int
5748bnx2_get_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
5749{
Michael Chan972ec0d2006-01-23 16:12:43 -08005750 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005751
5752 memset(coal, 0, sizeof(struct ethtool_coalesce));
5753
5754 coal->rx_coalesce_usecs = bp->rx_ticks;
5755 coal->rx_max_coalesced_frames = bp->rx_quick_cons_trip;
5756 coal->rx_coalesce_usecs_irq = bp->rx_ticks_int;
5757 coal->rx_max_coalesced_frames_irq = bp->rx_quick_cons_trip_int;
5758
5759 coal->tx_coalesce_usecs = bp->tx_ticks;
5760 coal->tx_max_coalesced_frames = bp->tx_quick_cons_trip;
5761 coal->tx_coalesce_usecs_irq = bp->tx_ticks_int;
5762 coal->tx_max_coalesced_frames_irq = bp->tx_quick_cons_trip_int;
5763
5764 coal->stats_block_coalesce_usecs = bp->stats_ticks;
5765
5766 return 0;
5767}
5768
5769static int
5770bnx2_set_coalesce(struct net_device *dev, struct ethtool_coalesce *coal)
5771{
Michael Chan972ec0d2006-01-23 16:12:43 -08005772 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005773
5774 bp->rx_ticks = (u16) coal->rx_coalesce_usecs;
5775 if (bp->rx_ticks > 0x3ff) bp->rx_ticks = 0x3ff;
5776
Jeff Garzik6aa20a22006-09-13 13:24:59 -04005777 bp->rx_quick_cons_trip = (u16) coal->rx_max_coalesced_frames;
Michael Chanb6016b72005-05-26 13:03:09 -07005778 if (bp->rx_quick_cons_trip > 0xff) bp->rx_quick_cons_trip = 0xff;
5779
5780 bp->rx_ticks_int = (u16) coal->rx_coalesce_usecs_irq;
5781 if (bp->rx_ticks_int > 0x3ff) bp->rx_ticks_int = 0x3ff;
5782
5783 bp->rx_quick_cons_trip_int = (u16) coal->rx_max_coalesced_frames_irq;
5784 if (bp->rx_quick_cons_trip_int > 0xff)
5785 bp->rx_quick_cons_trip_int = 0xff;
5786
5787 bp->tx_ticks = (u16) coal->tx_coalesce_usecs;
5788 if (bp->tx_ticks > 0x3ff) bp->tx_ticks = 0x3ff;
5789
5790 bp->tx_quick_cons_trip = (u16) coal->tx_max_coalesced_frames;
5791 if (bp->tx_quick_cons_trip > 0xff) bp->tx_quick_cons_trip = 0xff;
5792
5793 bp->tx_ticks_int = (u16) coal->tx_coalesce_usecs_irq;
5794 if (bp->tx_ticks_int > 0x3ff) bp->tx_ticks_int = 0x3ff;
5795
5796 bp->tx_quick_cons_trip_int = (u16) coal->tx_max_coalesced_frames_irq;
5797 if (bp->tx_quick_cons_trip_int > 0xff) bp->tx_quick_cons_trip_int =
5798 0xff;
5799
5800 bp->stats_ticks = coal->stats_block_coalesce_usecs;
Michael Chan02537b062007-06-04 21:24:07 -07005801 if (CHIP_NUM(bp) == CHIP_NUM_5708) {
5802 if (bp->stats_ticks != 0 && bp->stats_ticks != USEC_PER_SEC)
5803 bp->stats_ticks = USEC_PER_SEC;
5804 }
Michael Chanb6016b72005-05-26 13:03:09 -07005805 if (bp->stats_ticks > 0xffff00) bp->stats_ticks = 0xffff00;
5806 bp->stats_ticks &= 0xffff00;
5807
5808 if (netif_running(bp->dev)) {
5809 bnx2_netif_stop(bp);
5810 bnx2_init_nic(bp);
5811 bnx2_netif_start(bp);
5812 }
5813
5814 return 0;
5815}
5816
5817static void
5818bnx2_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
5819{
Michael Chan972ec0d2006-01-23 16:12:43 -08005820 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005821
Michael Chan13daffa2006-03-20 17:49:20 -08005822 ering->rx_max_pending = MAX_TOTAL_RX_DESC_CNT;
Michael Chanb6016b72005-05-26 13:03:09 -07005823 ering->rx_mini_max_pending = 0;
5824 ering->rx_jumbo_max_pending = 0;
5825
5826 ering->rx_pending = bp->rx_ring_size;
5827 ering->rx_mini_pending = 0;
5828 ering->rx_jumbo_pending = 0;
5829
5830 ering->tx_max_pending = MAX_TX_DESC_CNT;
5831 ering->tx_pending = bp->tx_ring_size;
5832}
5833
5834static int
5835bnx2_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ering)
5836{
Michael Chan972ec0d2006-01-23 16:12:43 -08005837 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005838
Michael Chan13daffa2006-03-20 17:49:20 -08005839 if ((ering->rx_pending > MAX_TOTAL_RX_DESC_CNT) ||
Michael Chanb6016b72005-05-26 13:03:09 -07005840 (ering->tx_pending > MAX_TX_DESC_CNT) ||
5841 (ering->tx_pending <= MAX_SKB_FRAGS)) {
5842
5843 return -EINVAL;
5844 }
Michael Chan13daffa2006-03-20 17:49:20 -08005845 if (netif_running(bp->dev)) {
5846 bnx2_netif_stop(bp);
5847 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
5848 bnx2_free_skbs(bp);
5849 bnx2_free_mem(bp);
5850 }
5851
5852 bnx2_set_rx_ring_size(bp, ering->rx_pending);
Michael Chanb6016b72005-05-26 13:03:09 -07005853 bp->tx_ring_size = ering->tx_pending;
5854
5855 if (netif_running(bp->dev)) {
Michael Chan13daffa2006-03-20 17:49:20 -08005856 int rc;
5857
5858 rc = bnx2_alloc_mem(bp);
5859 if (rc)
5860 return rc;
Michael Chanb6016b72005-05-26 13:03:09 -07005861 bnx2_init_nic(bp);
5862 bnx2_netif_start(bp);
5863 }
5864
5865 return 0;
5866}
5867
5868static void
5869bnx2_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
5870{
Michael Chan972ec0d2006-01-23 16:12:43 -08005871 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005872
5873 epause->autoneg = ((bp->autoneg & AUTONEG_FLOW_CTRL) != 0);
5874 epause->rx_pause = ((bp->flow_ctrl & FLOW_CTRL_RX) != 0);
5875 epause->tx_pause = ((bp->flow_ctrl & FLOW_CTRL_TX) != 0);
5876}
5877
5878static int
5879bnx2_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause)
5880{
Michael Chan972ec0d2006-01-23 16:12:43 -08005881 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005882
5883 bp->req_flow_ctrl = 0;
5884 if (epause->rx_pause)
5885 bp->req_flow_ctrl |= FLOW_CTRL_RX;
5886 if (epause->tx_pause)
5887 bp->req_flow_ctrl |= FLOW_CTRL_TX;
5888
5889 if (epause->autoneg) {
5890 bp->autoneg |= AUTONEG_FLOW_CTRL;
5891 }
5892 else {
5893 bp->autoneg &= ~AUTONEG_FLOW_CTRL;
5894 }
5895
Michael Chanc770a652005-08-25 15:38:39 -07005896 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005897
Michael Chan0d8a6572007-07-07 22:49:43 -07005898 bnx2_setup_phy(bp, bp->phy_port);
Michael Chanb6016b72005-05-26 13:03:09 -07005899
Michael Chanc770a652005-08-25 15:38:39 -07005900 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07005901
5902 return 0;
5903}
5904
5905static u32
5906bnx2_get_rx_csum(struct net_device *dev)
5907{
Michael Chan972ec0d2006-01-23 16:12:43 -08005908 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005909
5910 return bp->rx_csum;
5911}
5912
5913static int
5914bnx2_set_rx_csum(struct net_device *dev, u32 data)
5915{
Michael Chan972ec0d2006-01-23 16:12:43 -08005916 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07005917
5918 bp->rx_csum = data;
5919 return 0;
5920}
5921
Michael Chanb11d6212006-06-29 12:31:21 -07005922static int
5923bnx2_set_tso(struct net_device *dev, u32 data)
5924{
Michael Chan4666f872007-05-03 13:22:28 -07005925 struct bnx2 *bp = netdev_priv(dev);
5926
5927 if (data) {
Michael Chanb11d6212006-06-29 12:31:21 -07005928 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07005929 if (CHIP_NUM(bp) == CHIP_NUM_5709)
5930 dev->features |= NETIF_F_TSO6;
5931 } else
5932 dev->features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
5933 NETIF_F_TSO_ECN);
Michael Chanb11d6212006-06-29 12:31:21 -07005934 return 0;
5935}
5936
Michael Chancea94db2006-06-12 22:16:13 -07005937#define BNX2_NUM_STATS 46
Michael Chanb6016b72005-05-26 13:03:09 -07005938
Peter Hagervall14ab9b82005-08-10 14:18:16 -07005939static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07005940 char string[ETH_GSTRING_LEN];
5941} bnx2_stats_str_arr[BNX2_NUM_STATS] = {
5942 { "rx_bytes" },
5943 { "rx_error_bytes" },
5944 { "tx_bytes" },
5945 { "tx_error_bytes" },
5946 { "rx_ucast_packets" },
5947 { "rx_mcast_packets" },
5948 { "rx_bcast_packets" },
5949 { "tx_ucast_packets" },
5950 { "tx_mcast_packets" },
5951 { "tx_bcast_packets" },
5952 { "tx_mac_errors" },
5953 { "tx_carrier_errors" },
5954 { "rx_crc_errors" },
5955 { "rx_align_errors" },
5956 { "tx_single_collisions" },
5957 { "tx_multi_collisions" },
5958 { "tx_deferred" },
5959 { "tx_excess_collisions" },
5960 { "tx_late_collisions" },
5961 { "tx_total_collisions" },
5962 { "rx_fragments" },
5963 { "rx_jabbers" },
5964 { "rx_undersize_packets" },
5965 { "rx_oversize_packets" },
5966 { "rx_64_byte_packets" },
5967 { "rx_65_to_127_byte_packets" },
5968 { "rx_128_to_255_byte_packets" },
5969 { "rx_256_to_511_byte_packets" },
5970 { "rx_512_to_1023_byte_packets" },
5971 { "rx_1024_to_1522_byte_packets" },
5972 { "rx_1523_to_9022_byte_packets" },
5973 { "tx_64_byte_packets" },
5974 { "tx_65_to_127_byte_packets" },
5975 { "tx_128_to_255_byte_packets" },
5976 { "tx_256_to_511_byte_packets" },
5977 { "tx_512_to_1023_byte_packets" },
5978 { "tx_1024_to_1522_byte_packets" },
5979 { "tx_1523_to_9022_byte_packets" },
5980 { "rx_xon_frames" },
5981 { "rx_xoff_frames" },
5982 { "tx_xon_frames" },
5983 { "tx_xoff_frames" },
5984 { "rx_mac_ctrl_frames" },
5985 { "rx_filtered_packets" },
5986 { "rx_discards" },
Michael Chancea94db2006-06-12 22:16:13 -07005987 { "rx_fw_discards" },
Michael Chanb6016b72005-05-26 13:03:09 -07005988};
5989
5990#define STATS_OFFSET32(offset_name) (offsetof(struct statistics_block, offset_name) / 4)
5991
Arjan van de Venf71e1302006-03-03 21:33:57 -05005992static const unsigned long bnx2_stats_offset_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07005993 STATS_OFFSET32(stat_IfHCInOctets_hi),
5994 STATS_OFFSET32(stat_IfHCInBadOctets_hi),
5995 STATS_OFFSET32(stat_IfHCOutOctets_hi),
5996 STATS_OFFSET32(stat_IfHCOutBadOctets_hi),
5997 STATS_OFFSET32(stat_IfHCInUcastPkts_hi),
5998 STATS_OFFSET32(stat_IfHCInMulticastPkts_hi),
5999 STATS_OFFSET32(stat_IfHCInBroadcastPkts_hi),
6000 STATS_OFFSET32(stat_IfHCOutUcastPkts_hi),
6001 STATS_OFFSET32(stat_IfHCOutMulticastPkts_hi),
6002 STATS_OFFSET32(stat_IfHCOutBroadcastPkts_hi),
6003 STATS_OFFSET32(stat_emac_tx_stat_dot3statsinternalmactransmiterrors),
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006004 STATS_OFFSET32(stat_Dot3StatsCarrierSenseErrors),
6005 STATS_OFFSET32(stat_Dot3StatsFCSErrors),
6006 STATS_OFFSET32(stat_Dot3StatsAlignmentErrors),
6007 STATS_OFFSET32(stat_Dot3StatsSingleCollisionFrames),
6008 STATS_OFFSET32(stat_Dot3StatsMultipleCollisionFrames),
6009 STATS_OFFSET32(stat_Dot3StatsDeferredTransmissions),
6010 STATS_OFFSET32(stat_Dot3StatsExcessiveCollisions),
6011 STATS_OFFSET32(stat_Dot3StatsLateCollisions),
6012 STATS_OFFSET32(stat_EtherStatsCollisions),
6013 STATS_OFFSET32(stat_EtherStatsFragments),
6014 STATS_OFFSET32(stat_EtherStatsJabbers),
6015 STATS_OFFSET32(stat_EtherStatsUndersizePkts),
6016 STATS_OFFSET32(stat_EtherStatsOverrsizePkts),
6017 STATS_OFFSET32(stat_EtherStatsPktsRx64Octets),
6018 STATS_OFFSET32(stat_EtherStatsPktsRx65Octetsto127Octets),
6019 STATS_OFFSET32(stat_EtherStatsPktsRx128Octetsto255Octets),
6020 STATS_OFFSET32(stat_EtherStatsPktsRx256Octetsto511Octets),
6021 STATS_OFFSET32(stat_EtherStatsPktsRx512Octetsto1023Octets),
6022 STATS_OFFSET32(stat_EtherStatsPktsRx1024Octetsto1522Octets),
6023 STATS_OFFSET32(stat_EtherStatsPktsRx1523Octetsto9022Octets),
6024 STATS_OFFSET32(stat_EtherStatsPktsTx64Octets),
6025 STATS_OFFSET32(stat_EtherStatsPktsTx65Octetsto127Octets),
6026 STATS_OFFSET32(stat_EtherStatsPktsTx128Octetsto255Octets),
6027 STATS_OFFSET32(stat_EtherStatsPktsTx256Octetsto511Octets),
6028 STATS_OFFSET32(stat_EtherStatsPktsTx512Octetsto1023Octets),
6029 STATS_OFFSET32(stat_EtherStatsPktsTx1024Octetsto1522Octets),
6030 STATS_OFFSET32(stat_EtherStatsPktsTx1523Octetsto9022Octets),
6031 STATS_OFFSET32(stat_XonPauseFramesReceived),
6032 STATS_OFFSET32(stat_XoffPauseFramesReceived),
6033 STATS_OFFSET32(stat_OutXonSent),
6034 STATS_OFFSET32(stat_OutXoffSent),
6035 STATS_OFFSET32(stat_MacControlFramesReceived),
6036 STATS_OFFSET32(stat_IfInFramesL2FilterDiscards),
6037 STATS_OFFSET32(stat_IfInMBUFDiscards),
Michael Chancea94db2006-06-12 22:16:13 -07006038 STATS_OFFSET32(stat_FwRxDrop),
Michael Chanb6016b72005-05-26 13:03:09 -07006039};
6040
6041/* stat_IfHCInBadOctets and stat_Dot3StatsCarrierSenseErrors are
6042 * skipped because of errata.
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006043 */
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006044static u8 bnx2_5706_stats_len_arr[BNX2_NUM_STATS] = {
Michael Chanb6016b72005-05-26 13:03:09 -07006045 8,0,8,8,8,8,8,8,8,8,
6046 4,0,4,4,4,4,4,4,4,4,
6047 4,4,4,4,4,4,4,4,4,4,
6048 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006049 4,4,4,4,4,4,
Michael Chanb6016b72005-05-26 13:03:09 -07006050};
6051
Michael Chan5b0c76a2005-11-04 08:45:49 -08006052static u8 bnx2_5708_stats_len_arr[BNX2_NUM_STATS] = {
6053 8,0,8,8,8,8,8,8,8,8,
6054 4,4,4,4,4,4,4,4,4,4,
6055 4,4,4,4,4,4,4,4,4,4,
6056 4,4,4,4,4,4,4,4,4,4,
Michael Chancea94db2006-06-12 22:16:13 -07006057 4,4,4,4,4,4,
Michael Chan5b0c76a2005-11-04 08:45:49 -08006058};
6059
Michael Chanb6016b72005-05-26 13:03:09 -07006060#define BNX2_NUM_TESTS 6
6061
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006062static struct {
Michael Chanb6016b72005-05-26 13:03:09 -07006063 char string[ETH_GSTRING_LEN];
6064} bnx2_tests_str_arr[BNX2_NUM_TESTS] = {
6065 { "register_test (offline)" },
6066 { "memory_test (offline)" },
6067 { "loopback_test (offline)" },
6068 { "nvram_test (online)" },
6069 { "interrupt_test (online)" },
6070 { "link_test (online)" },
6071};
6072
6073static int
6074bnx2_self_test_count(struct net_device *dev)
6075{
6076 return BNX2_NUM_TESTS;
6077}
6078
6079static void
6080bnx2_self_test(struct net_device *dev, struct ethtool_test *etest, u64 *buf)
6081{
Michael Chan972ec0d2006-01-23 16:12:43 -08006082 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006083
6084 memset(buf, 0, sizeof(u64) * BNX2_NUM_TESTS);
6085 if (etest->flags & ETH_TEST_FL_OFFLINE) {
Michael Chan80be4432006-11-19 14:07:28 -08006086 int i;
6087
Michael Chanb6016b72005-05-26 13:03:09 -07006088 bnx2_netif_stop(bp);
6089 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_DIAG);
6090 bnx2_free_skbs(bp);
6091
6092 if (bnx2_test_registers(bp) != 0) {
6093 buf[0] = 1;
6094 etest->flags |= ETH_TEST_FL_FAILED;
6095 }
6096 if (bnx2_test_memory(bp) != 0) {
6097 buf[1] = 1;
6098 etest->flags |= ETH_TEST_FL_FAILED;
6099 }
Michael Chanbc5a0692006-01-23 16:13:22 -08006100 if ((buf[2] = bnx2_test_loopback(bp)) != 0)
Michael Chanb6016b72005-05-26 13:03:09 -07006101 etest->flags |= ETH_TEST_FL_FAILED;
Michael Chanb6016b72005-05-26 13:03:09 -07006102
6103 if (!netif_running(bp->dev)) {
6104 bnx2_reset_chip(bp, BNX2_DRV_MSG_CODE_RESET);
6105 }
6106 else {
6107 bnx2_init_nic(bp);
6108 bnx2_netif_start(bp);
6109 }
6110
6111 /* wait for link up */
Michael Chan80be4432006-11-19 14:07:28 -08006112 for (i = 0; i < 7; i++) {
6113 if (bp->link_up)
6114 break;
6115 msleep_interruptible(1000);
6116 }
Michael Chanb6016b72005-05-26 13:03:09 -07006117 }
6118
6119 if (bnx2_test_nvram(bp) != 0) {
6120 buf[3] = 1;
6121 etest->flags |= ETH_TEST_FL_FAILED;
6122 }
6123 if (bnx2_test_intr(bp) != 0) {
6124 buf[4] = 1;
6125 etest->flags |= ETH_TEST_FL_FAILED;
6126 }
6127
6128 if (bnx2_test_link(bp) != 0) {
6129 buf[5] = 1;
6130 etest->flags |= ETH_TEST_FL_FAILED;
6131
6132 }
6133}
6134
6135static void
6136bnx2_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
6137{
6138 switch (stringset) {
6139 case ETH_SS_STATS:
6140 memcpy(buf, bnx2_stats_str_arr,
6141 sizeof(bnx2_stats_str_arr));
6142 break;
6143 case ETH_SS_TEST:
6144 memcpy(buf, bnx2_tests_str_arr,
6145 sizeof(bnx2_tests_str_arr));
6146 break;
6147 }
6148}
6149
6150static int
6151bnx2_get_stats_count(struct net_device *dev)
6152{
6153 return BNX2_NUM_STATS;
6154}
6155
6156static void
6157bnx2_get_ethtool_stats(struct net_device *dev,
6158 struct ethtool_stats *stats, u64 *buf)
6159{
Michael Chan972ec0d2006-01-23 16:12:43 -08006160 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006161 int i;
6162 u32 *hw_stats = (u32 *) bp->stats_blk;
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006163 u8 *stats_len_arr = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07006164
6165 if (hw_stats == NULL) {
6166 memset(buf, 0, sizeof(u64) * BNX2_NUM_STATS);
6167 return;
6168 }
6169
Michael Chan5b0c76a2005-11-04 08:45:49 -08006170 if ((CHIP_ID(bp) == CHIP_ID_5706_A0) ||
6171 (CHIP_ID(bp) == CHIP_ID_5706_A1) ||
6172 (CHIP_ID(bp) == CHIP_ID_5706_A2) ||
6173 (CHIP_ID(bp) == CHIP_ID_5708_A0))
Michael Chanb6016b72005-05-26 13:03:09 -07006174 stats_len_arr = bnx2_5706_stats_len_arr;
Michael Chan5b0c76a2005-11-04 08:45:49 -08006175 else
6176 stats_len_arr = bnx2_5708_stats_len_arr;
Michael Chanb6016b72005-05-26 13:03:09 -07006177
6178 for (i = 0; i < BNX2_NUM_STATS; i++) {
6179 if (stats_len_arr[i] == 0) {
6180 /* skip this counter */
6181 buf[i] = 0;
6182 continue;
6183 }
6184 if (stats_len_arr[i] == 4) {
6185 /* 4-byte counter */
6186 buf[i] = (u64)
6187 *(hw_stats + bnx2_stats_offset_arr[i]);
6188 continue;
6189 }
6190 /* 8-byte counter */
6191 buf[i] = (((u64) *(hw_stats +
6192 bnx2_stats_offset_arr[i])) << 32) +
6193 *(hw_stats + bnx2_stats_offset_arr[i] + 1);
6194 }
6195}
6196
6197static int
6198bnx2_phys_id(struct net_device *dev, u32 data)
6199{
Michael Chan972ec0d2006-01-23 16:12:43 -08006200 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006201 int i;
6202 u32 save;
6203
6204 if (data == 0)
6205 data = 2;
6206
6207 save = REG_RD(bp, BNX2_MISC_CFG);
6208 REG_WR(bp, BNX2_MISC_CFG, BNX2_MISC_CFG_LEDMODE_MAC);
6209
6210 for (i = 0; i < (data * 2); i++) {
6211 if ((i % 2) == 0) {
6212 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE);
6213 }
6214 else {
6215 REG_WR(bp, BNX2_EMAC_LED, BNX2_EMAC_LED_OVERRIDE |
6216 BNX2_EMAC_LED_1000MB_OVERRIDE |
6217 BNX2_EMAC_LED_100MB_OVERRIDE |
6218 BNX2_EMAC_LED_10MB_OVERRIDE |
6219 BNX2_EMAC_LED_TRAFFIC_OVERRIDE |
6220 BNX2_EMAC_LED_TRAFFIC);
6221 }
6222 msleep_interruptible(500);
6223 if (signal_pending(current))
6224 break;
6225 }
6226 REG_WR(bp, BNX2_EMAC_LED, 0);
6227 REG_WR(bp, BNX2_MISC_CFG, save);
6228 return 0;
6229}
6230
Michael Chan4666f872007-05-03 13:22:28 -07006231static int
6232bnx2_set_tx_csum(struct net_device *dev, u32 data)
6233{
6234 struct bnx2 *bp = netdev_priv(dev);
6235
6236 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Michael Chan6460d942007-07-14 19:07:52 -07006237 return (ethtool_op_set_tx_ipv6_csum(dev, data));
Michael Chan4666f872007-05-03 13:22:28 -07006238 else
6239 return (ethtool_op_set_tx_csum(dev, data));
6240}
6241
Jeff Garzik7282d492006-09-13 14:30:00 -04006242static const struct ethtool_ops bnx2_ethtool_ops = {
Michael Chanb6016b72005-05-26 13:03:09 -07006243 .get_settings = bnx2_get_settings,
6244 .set_settings = bnx2_set_settings,
6245 .get_drvinfo = bnx2_get_drvinfo,
Michael Chan244ac4f2006-03-20 17:48:46 -08006246 .get_regs_len = bnx2_get_regs_len,
6247 .get_regs = bnx2_get_regs,
Michael Chanb6016b72005-05-26 13:03:09 -07006248 .get_wol = bnx2_get_wol,
6249 .set_wol = bnx2_set_wol,
6250 .nway_reset = bnx2_nway_reset,
6251 .get_link = ethtool_op_get_link,
6252 .get_eeprom_len = bnx2_get_eeprom_len,
6253 .get_eeprom = bnx2_get_eeprom,
6254 .set_eeprom = bnx2_set_eeprom,
6255 .get_coalesce = bnx2_get_coalesce,
6256 .set_coalesce = bnx2_set_coalesce,
6257 .get_ringparam = bnx2_get_ringparam,
6258 .set_ringparam = bnx2_set_ringparam,
6259 .get_pauseparam = bnx2_get_pauseparam,
6260 .set_pauseparam = bnx2_set_pauseparam,
6261 .get_rx_csum = bnx2_get_rx_csum,
6262 .set_rx_csum = bnx2_set_rx_csum,
6263 .get_tx_csum = ethtool_op_get_tx_csum,
Michael Chan4666f872007-05-03 13:22:28 -07006264 .set_tx_csum = bnx2_set_tx_csum,
Michael Chanb6016b72005-05-26 13:03:09 -07006265 .get_sg = ethtool_op_get_sg,
6266 .set_sg = ethtool_op_set_sg,
Michael Chanb6016b72005-05-26 13:03:09 -07006267 .get_tso = ethtool_op_get_tso,
Michael Chanb11d6212006-06-29 12:31:21 -07006268 .set_tso = bnx2_set_tso,
Michael Chanb6016b72005-05-26 13:03:09 -07006269 .self_test_count = bnx2_self_test_count,
6270 .self_test = bnx2_self_test,
6271 .get_strings = bnx2_get_strings,
6272 .phys_id = bnx2_phys_id,
6273 .get_stats_count = bnx2_get_stats_count,
6274 .get_ethtool_stats = bnx2_get_ethtool_stats,
John W. Linville24b8e052005-09-12 14:45:08 -07006275 .get_perm_addr = ethtool_op_get_perm_addr,
Michael Chanb6016b72005-05-26 13:03:09 -07006276};
6277
6278/* Called with rtnl_lock */
6279static int
6280bnx2_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
6281{
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006282 struct mii_ioctl_data *data = if_mii(ifr);
Michael Chan972ec0d2006-01-23 16:12:43 -08006283 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006284 int err;
6285
6286 switch(cmd) {
6287 case SIOCGMIIPHY:
6288 data->phy_id = bp->phy_addr;
6289
6290 /* fallthru */
6291 case SIOCGMIIREG: {
6292 u32 mii_regval;
6293
Michael Chan7b6b8342007-07-07 22:50:15 -07006294 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
6295 return -EOPNOTSUPP;
6296
Michael Chandad3e452007-05-03 13:18:03 -07006297 if (!netif_running(dev))
6298 return -EAGAIN;
6299
Michael Chanc770a652005-08-25 15:38:39 -07006300 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006301 err = bnx2_read_phy(bp, data->reg_num & 0x1f, &mii_regval);
Michael Chanc770a652005-08-25 15:38:39 -07006302 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006303
6304 data->val_out = mii_regval;
6305
6306 return err;
6307 }
6308
6309 case SIOCSMIIREG:
6310 if (!capable(CAP_NET_ADMIN))
6311 return -EPERM;
6312
Michael Chan7b6b8342007-07-07 22:50:15 -07006313 if (bp->phy_flags & REMOTE_PHY_CAP_FLAG)
6314 return -EOPNOTSUPP;
6315
Michael Chandad3e452007-05-03 13:18:03 -07006316 if (!netif_running(dev))
6317 return -EAGAIN;
6318
Michael Chanc770a652005-08-25 15:38:39 -07006319 spin_lock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006320 err = bnx2_write_phy(bp, data->reg_num & 0x1f, data->val_in);
Michael Chanc770a652005-08-25 15:38:39 -07006321 spin_unlock_bh(&bp->phy_lock);
Michael Chanb6016b72005-05-26 13:03:09 -07006322
6323 return err;
6324
6325 default:
6326 /* do nothing */
6327 break;
6328 }
6329 return -EOPNOTSUPP;
6330}
6331
6332/* Called with rtnl_lock */
6333static int
6334bnx2_change_mac_addr(struct net_device *dev, void *p)
6335{
6336 struct sockaddr *addr = p;
Michael Chan972ec0d2006-01-23 16:12:43 -08006337 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006338
Michael Chan73eef4c2005-08-25 15:39:15 -07006339 if (!is_valid_ether_addr(addr->sa_data))
6340 return -EINVAL;
6341
Michael Chanb6016b72005-05-26 13:03:09 -07006342 memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
6343 if (netif_running(dev))
6344 bnx2_set_mac_addr(bp);
6345
6346 return 0;
6347}
6348
6349/* Called with rtnl_lock */
6350static int
6351bnx2_change_mtu(struct net_device *dev, int new_mtu)
6352{
Michael Chan972ec0d2006-01-23 16:12:43 -08006353 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006354
6355 if (((new_mtu + ETH_HLEN) > MAX_ETHERNET_JUMBO_PACKET_SIZE) ||
6356 ((new_mtu + ETH_HLEN) < MIN_ETHERNET_PACKET_SIZE))
6357 return -EINVAL;
6358
6359 dev->mtu = new_mtu;
6360 if (netif_running(dev)) {
6361 bnx2_netif_stop(bp);
6362
6363 bnx2_init_nic(bp);
6364
6365 bnx2_netif_start(bp);
6366 }
6367 return 0;
6368}
6369
6370#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
6371static void
6372poll_bnx2(struct net_device *dev)
6373{
Michael Chan972ec0d2006-01-23 16:12:43 -08006374 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006375
6376 disable_irq(bp->pdev->irq);
David Howells7d12e782006-10-05 14:55:46 +01006377 bnx2_interrupt(bp->pdev->irq, dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006378 enable_irq(bp->pdev->irq);
6379}
6380#endif
6381
Michael Chan253c8b72007-01-08 19:56:01 -08006382static void __devinit
6383bnx2_get_5709_media(struct bnx2 *bp)
6384{
6385 u32 val = REG_RD(bp, BNX2_MISC_DUAL_MEDIA_CTRL);
6386 u32 bond_id = val & BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID;
6387 u32 strap;
6388
6389 if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_C)
6390 return;
6391 else if (bond_id == BNX2_MISC_DUAL_MEDIA_CTRL_BOND_ID_S) {
6392 bp->phy_flags |= PHY_SERDES_FLAG;
6393 return;
6394 }
6395
6396 if (val & BNX2_MISC_DUAL_MEDIA_CTRL_STRAP_OVERRIDE)
6397 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL) >> 21;
6398 else
6399 strap = (val & BNX2_MISC_DUAL_MEDIA_CTRL_PHY_CTRL_STRAP) >> 8;
6400
6401 if (PCI_FUNC(bp->pdev->devfn) == 0) {
6402 switch (strap) {
6403 case 0x4:
6404 case 0x5:
6405 case 0x6:
6406 bp->phy_flags |= PHY_SERDES_FLAG;
6407 return;
6408 }
6409 } else {
6410 switch (strap) {
6411 case 0x1:
6412 case 0x2:
6413 case 0x4:
6414 bp->phy_flags |= PHY_SERDES_FLAG;
6415 return;
6416 }
6417 }
6418}
6419
Michael Chan883e5152007-05-03 13:25:11 -07006420static void __devinit
6421bnx2_get_pci_speed(struct bnx2 *bp)
6422{
6423 u32 reg;
6424
6425 reg = REG_RD(bp, BNX2_PCICFG_MISC_STATUS);
6426 if (reg & BNX2_PCICFG_MISC_STATUS_PCIX_DET) {
6427 u32 clkreg;
6428
6429 bp->flags |= PCIX_FLAG;
6430
6431 clkreg = REG_RD(bp, BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS);
6432
6433 clkreg &= BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET;
6434 switch (clkreg) {
6435 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_133MHZ:
6436 bp->bus_speed_mhz = 133;
6437 break;
6438
6439 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_95MHZ:
6440 bp->bus_speed_mhz = 100;
6441 break;
6442
6443 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_66MHZ:
6444 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_80MHZ:
6445 bp->bus_speed_mhz = 66;
6446 break;
6447
6448 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_48MHZ:
6449 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_55MHZ:
6450 bp->bus_speed_mhz = 50;
6451 break;
6452
6453 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_LOW:
6454 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_32MHZ:
6455 case BNX2_PCICFG_PCI_CLOCK_CONTROL_BITS_PCI_CLK_SPD_DET_38MHZ:
6456 bp->bus_speed_mhz = 33;
6457 break;
6458 }
6459 }
6460 else {
6461 if (reg & BNX2_PCICFG_MISC_STATUS_M66EN)
6462 bp->bus_speed_mhz = 66;
6463 else
6464 bp->bus_speed_mhz = 33;
6465 }
6466
6467 if (reg & BNX2_PCICFG_MISC_STATUS_32BIT_DET)
6468 bp->flags |= PCI_32BIT_FLAG;
6469
6470}
6471
Michael Chanb6016b72005-05-26 13:03:09 -07006472static int __devinit
6473bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
6474{
6475 struct bnx2 *bp;
6476 unsigned long mem_len;
Michael Chan58fc2ea2007-07-07 22:52:02 -07006477 int rc, i, j;
Michael Chanb6016b72005-05-26 13:03:09 -07006478 u32 reg;
Michael Chan40453c82007-05-03 13:19:18 -07006479 u64 dma_mask, persist_dma_mask;
Michael Chanb6016b72005-05-26 13:03:09 -07006480
6481 SET_MODULE_OWNER(dev);
6482 SET_NETDEV_DEV(dev, &pdev->dev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006483 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006484
6485 bp->flags = 0;
6486 bp->phy_flags = 0;
6487
6488 /* enable device (incl. PCI PM wakeup), and bus-mastering */
6489 rc = pci_enable_device(pdev);
6490 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006491 dev_err(&pdev->dev, "Cannot enable PCI device, aborting.");
Michael Chanb6016b72005-05-26 13:03:09 -07006492 goto err_out;
6493 }
6494
6495 if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006496 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006497 "Cannot find PCI device base address, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006498 rc = -ENODEV;
6499 goto err_out_disable;
6500 }
6501
6502 rc = pci_request_regions(pdev, DRV_MODULE_NAME);
6503 if (rc) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006504 dev_err(&pdev->dev, "Cannot obtain PCI resources, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006505 goto err_out_disable;
6506 }
6507
6508 pci_set_master(pdev);
6509
6510 bp->pm_cap = pci_find_capability(pdev, PCI_CAP_ID_PM);
6511 if (bp->pm_cap == 0) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006512 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006513 "Cannot find power management capability, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006514 rc = -EIO;
6515 goto err_out_release;
6516 }
6517
Michael Chanb6016b72005-05-26 13:03:09 -07006518 bp->dev = dev;
6519 bp->pdev = pdev;
6520
6521 spin_lock_init(&bp->phy_lock);
Michael Chan1b8227c2007-05-03 13:24:05 -07006522 spin_lock_init(&bp->indirect_lock);
David Howellsc4028952006-11-22 14:57:56 +00006523 INIT_WORK(&bp->reset_task, bnx2_reset_task);
Michael Chanb6016b72005-05-26 13:03:09 -07006524
6525 dev->base_addr = dev->mem_start = pci_resource_start(pdev, 0);
Michael Chan59b47d82006-11-19 14:10:45 -08006526 mem_len = MB_GET_CID_ADDR(TX_TSS_CID + 1);
Michael Chanb6016b72005-05-26 13:03:09 -07006527 dev->mem_end = dev->mem_start + mem_len;
6528 dev->irq = pdev->irq;
6529
6530 bp->regview = ioremap_nocache(dev->base_addr, mem_len);
6531
6532 if (!bp->regview) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006533 dev_err(&pdev->dev, "Cannot map register space, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006534 rc = -ENOMEM;
6535 goto err_out_release;
6536 }
6537
6538 /* Configure byte swap and enable write to the reg_window registers.
6539 * Rely on CPU to do target byte swapping on big endian systems
6540 * The chip's target access swapping will not swap all accesses
6541 */
6542 pci_write_config_dword(bp->pdev, BNX2_PCICFG_MISC_CONFIG,
6543 BNX2_PCICFG_MISC_CONFIG_REG_WINDOW_ENA |
6544 BNX2_PCICFG_MISC_CONFIG_TARGET_MB_WORD_SWAP);
6545
Pavel Machek829ca9a2005-09-03 15:56:56 -07006546 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006547
6548 bp->chip_id = REG_RD(bp, BNX2_MISC_ID);
6549
Michael Chan883e5152007-05-03 13:25:11 -07006550 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
6551 if (pci_find_capability(pdev, PCI_CAP_ID_EXP) == 0) {
6552 dev_err(&pdev->dev,
6553 "Cannot find PCIE capability, aborting.\n");
6554 rc = -EIO;
6555 goto err_out_unmap;
6556 }
6557 bp->flags |= PCIE_FLAG;
6558 } else {
Michael Chan59b47d82006-11-19 14:10:45 -08006559 bp->pcix_cap = pci_find_capability(pdev, PCI_CAP_ID_PCIX);
6560 if (bp->pcix_cap == 0) {
6561 dev_err(&pdev->dev,
6562 "Cannot find PCIX capability, aborting.\n");
6563 rc = -EIO;
6564 goto err_out_unmap;
6565 }
6566 }
6567
Michael Chan8e6a72c2007-05-03 13:24:48 -07006568 if (CHIP_ID(bp) != CHIP_ID_5706_A0 && CHIP_ID(bp) != CHIP_ID_5706_A1) {
6569 if (pci_find_capability(pdev, PCI_CAP_ID_MSI))
6570 bp->flags |= MSI_CAP_FLAG;
6571 }
6572
Michael Chan40453c82007-05-03 13:19:18 -07006573 /* 5708 cannot support DMA addresses > 40-bit. */
6574 if (CHIP_NUM(bp) == CHIP_NUM_5708)
6575 persist_dma_mask = dma_mask = DMA_40BIT_MASK;
6576 else
6577 persist_dma_mask = dma_mask = DMA_64BIT_MASK;
6578
6579 /* Configure DMA attributes. */
6580 if (pci_set_dma_mask(pdev, dma_mask) == 0) {
6581 dev->features |= NETIF_F_HIGHDMA;
6582 rc = pci_set_consistent_dma_mask(pdev, persist_dma_mask);
6583 if (rc) {
6584 dev_err(&pdev->dev,
6585 "pci_set_consistent_dma_mask failed, aborting.\n");
6586 goto err_out_unmap;
6587 }
6588 } else if ((rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK)) != 0) {
6589 dev_err(&pdev->dev, "System does not support DMA, aborting.\n");
6590 goto err_out_unmap;
6591 }
6592
Michael Chan883e5152007-05-03 13:25:11 -07006593 if (!(bp->flags & PCIE_FLAG))
6594 bnx2_get_pci_speed(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006595
6596 /* 5706A0 may falsely detect SERR and PERR. */
6597 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
6598 reg = REG_RD(bp, PCI_COMMAND);
6599 reg &= ~(PCI_COMMAND_SERR | PCI_COMMAND_PARITY);
6600 REG_WR(bp, PCI_COMMAND, reg);
6601 }
6602 else if ((CHIP_ID(bp) == CHIP_ID_5706_A1) &&
6603 !(bp->flags & PCIX_FLAG)) {
6604
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006605 dev_err(&pdev->dev,
Jeff Garzik2e8a5382006-06-27 10:47:51 -04006606 "5706 A1 can only be used in a PCIX bus, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006607 goto err_out_unmap;
6608 }
6609
6610 bnx2_init_nvram(bp);
6611
Michael Chane3648b32005-11-04 08:51:21 -08006612 reg = REG_RD_IND(bp, BNX2_SHM_HDR_SIGNATURE);
6613
6614 if ((reg & BNX2_SHM_HDR_SIGNATURE_SIG_MASK) ==
Michael Chan24cb2302007-01-25 15:49:56 -08006615 BNX2_SHM_HDR_SIGNATURE_SIG) {
6616 u32 off = PCI_FUNC(pdev->devfn) << 2;
6617
6618 bp->shmem_base = REG_RD_IND(bp, BNX2_SHM_HDR_ADDR_0 + off);
6619 } else
Michael Chane3648b32005-11-04 08:51:21 -08006620 bp->shmem_base = HOST_VIEW_SHMEM_BASE;
6621
Michael Chanb6016b72005-05-26 13:03:09 -07006622 /* Get the permanent MAC address. First we need to make sure the
6623 * firmware is actually running.
6624 */
Michael Chane3648b32005-11-04 08:51:21 -08006625 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_SIGNATURE);
Michael Chanb6016b72005-05-26 13:03:09 -07006626
6627 if ((reg & BNX2_DEV_INFO_SIGNATURE_MAGIC_MASK) !=
6628 BNX2_DEV_INFO_SIGNATURE_MAGIC) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006629 dev_err(&pdev->dev, "Firmware not running, aborting.\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006630 rc = -ENODEV;
6631 goto err_out_unmap;
6632 }
6633
Michael Chan58fc2ea2007-07-07 22:52:02 -07006634 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_DEV_INFO_BC_REV);
6635 for (i = 0, j = 0; i < 3; i++) {
6636 u8 num, k, skip0;
6637
6638 num = (u8) (reg >> (24 - (i * 8)));
6639 for (k = 100, skip0 = 1; k >= 1; num %= k, k /= 10) {
6640 if (num >= k || !skip0 || k == 1) {
6641 bp->fw_version[j++] = (num / k) + '0';
6642 skip0 = 0;
6643 }
6644 }
6645 if (i != 2)
6646 bp->fw_version[j++] = '.';
6647 }
6648 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_BC_STATE_CONDITION);
6649 reg &= BNX2_CONDITION_MFW_RUN_MASK;
6650 if (reg != BNX2_CONDITION_MFW_RUN_UNKNOWN &&
6651 reg != BNX2_CONDITION_MFW_RUN_NONE) {
6652 int i;
6653 u32 addr = REG_RD_IND(bp, bp->shmem_base + BNX2_MFW_VER_PTR);
6654
6655 bp->fw_version[j++] = ' ';
6656 for (i = 0; i < 3; i++) {
6657 reg = REG_RD_IND(bp, addr + i * 4);
6658 reg = swab32(reg);
6659 memcpy(&bp->fw_version[j], &reg, 4);
6660 j += 4;
6661 }
6662 }
Michael Chanb6016b72005-05-26 13:03:09 -07006663
Michael Chane3648b32005-11-04 08:51:21 -08006664 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_UPPER);
Michael Chanb6016b72005-05-26 13:03:09 -07006665 bp->mac_addr[0] = (u8) (reg >> 8);
6666 bp->mac_addr[1] = (u8) reg;
6667
Michael Chane3648b32005-11-04 08:51:21 -08006668 reg = REG_RD_IND(bp, bp->shmem_base + BNX2_PORT_HW_CFG_MAC_LOWER);
Michael Chanb6016b72005-05-26 13:03:09 -07006669 bp->mac_addr[2] = (u8) (reg >> 24);
6670 bp->mac_addr[3] = (u8) (reg >> 16);
6671 bp->mac_addr[4] = (u8) (reg >> 8);
6672 bp->mac_addr[5] = (u8) reg;
6673
6674 bp->tx_ring_size = MAX_TX_DESC_CNT;
Michael Chan932f3772006-08-15 01:39:36 -07006675 bnx2_set_rx_ring_size(bp, 255);
Michael Chanb6016b72005-05-26 13:03:09 -07006676
6677 bp->rx_csum = 1;
6678
6679 bp->rx_offset = sizeof(struct l2_fhdr) + 2;
6680
6681 bp->tx_quick_cons_trip_int = 20;
6682 bp->tx_quick_cons_trip = 20;
6683 bp->tx_ticks_int = 80;
6684 bp->tx_ticks = 80;
Jeff Garzik6aa20a22006-09-13 13:24:59 -04006685
Michael Chanb6016b72005-05-26 13:03:09 -07006686 bp->rx_quick_cons_trip_int = 6;
6687 bp->rx_quick_cons_trip = 6;
6688 bp->rx_ticks_int = 18;
6689 bp->rx_ticks = 18;
6690
6691 bp->stats_ticks = 1000000 & 0xffff00;
6692
6693 bp->timer_interval = HZ;
Michael Chancd339a02005-08-25 15:35:24 -07006694 bp->current_interval = HZ;
Michael Chanb6016b72005-05-26 13:03:09 -07006695
Michael Chan5b0c76a2005-11-04 08:45:49 -08006696 bp->phy_addr = 1;
6697
Michael Chanb6016b72005-05-26 13:03:09 -07006698 /* Disable WOL support if we are running on a SERDES chip. */
Michael Chan253c8b72007-01-08 19:56:01 -08006699 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6700 bnx2_get_5709_media(bp);
6701 else if (CHIP_BOND_ID(bp) & CHIP_BOND_ID_SERDES_BIT)
Michael Chanb6016b72005-05-26 13:03:09 -07006702 bp->phy_flags |= PHY_SERDES_FLAG;
Michael Chanbac0dff2006-11-19 14:15:05 -08006703
Michael Chan0d8a6572007-07-07 22:49:43 -07006704 bp->phy_port = PORT_TP;
Michael Chanbac0dff2006-11-19 14:15:05 -08006705 if (bp->phy_flags & PHY_SERDES_FLAG) {
Michael Chan0d8a6572007-07-07 22:49:43 -07006706 bp->phy_port = PORT_FIBRE;
Michael Chanb6016b72005-05-26 13:03:09 -07006707 bp->flags |= NO_WOL_FLAG;
Michael Chanbac0dff2006-11-19 14:15:05 -08006708 if (CHIP_NUM(bp) != CHIP_NUM_5706) {
Michael Chan5b0c76a2005-11-04 08:45:49 -08006709 bp->phy_addr = 2;
Michael Chane3648b32005-11-04 08:51:21 -08006710 reg = REG_RD_IND(bp, bp->shmem_base +
Michael Chan5b0c76a2005-11-04 08:45:49 -08006711 BNX2_SHARED_HW_CFG_CONFIG);
6712 if (reg & BNX2_SHARED_HW_CFG_PHY_2_5G)
6713 bp->phy_flags |= PHY_2_5G_CAPABLE_FLAG;
6714 }
Michael Chan0d8a6572007-07-07 22:49:43 -07006715 bnx2_init_remote_phy(bp);
6716
Michael Chan261dd5c2007-01-08 19:55:46 -08006717 } else if (CHIP_NUM(bp) == CHIP_NUM_5706 ||
6718 CHIP_NUM(bp) == CHIP_NUM_5708)
6719 bp->phy_flags |= PHY_CRC_FIX_FLAG;
Michael Chanb659f442007-02-02 00:46:35 -08006720 else if (CHIP_ID(bp) == CHIP_ID_5709_A0)
6721 bp->phy_flags |= PHY_DIS_EARLY_DAC_FLAG;
Michael Chanb6016b72005-05-26 13:03:09 -07006722
Michael Chan16088272006-06-12 22:16:43 -07006723 if ((CHIP_ID(bp) == CHIP_ID_5708_A0) ||
6724 (CHIP_ID(bp) == CHIP_ID_5708_B0) ||
6725 (CHIP_ID(bp) == CHIP_ID_5708_B1))
Michael Chandda1e392006-01-23 16:08:14 -08006726 bp->flags |= NO_WOL_FLAG;
6727
Michael Chanb6016b72005-05-26 13:03:09 -07006728 if (CHIP_ID(bp) == CHIP_ID_5706_A0) {
6729 bp->tx_quick_cons_trip_int =
6730 bp->tx_quick_cons_trip;
6731 bp->tx_ticks_int = bp->tx_ticks;
6732 bp->rx_quick_cons_trip_int =
6733 bp->rx_quick_cons_trip;
6734 bp->rx_ticks_int = bp->rx_ticks;
6735 bp->comp_prod_trip_int = bp->comp_prod_trip;
6736 bp->com_ticks_int = bp->com_ticks;
6737 bp->cmd_ticks_int = bp->cmd_ticks;
6738 }
6739
Michael Chanf9317a42006-09-29 17:06:23 -07006740 /* Disable MSI on 5706 if AMD 8132 bridge is found.
6741 *
6742 * MSI is defined to be 32-bit write. The 5706 does 64-bit MSI writes
6743 * with byte enables disabled on the unused 32-bit word. This is legal
6744 * but causes problems on the AMD 8132 which will eventually stop
6745 * responding after a while.
6746 *
6747 * AMD believes this incompatibility is unique to the 5706, and
Michael Ellerman88187df2007-01-25 19:34:07 +11006748 * prefers to locally disable MSI rather than globally disabling it.
Michael Chanf9317a42006-09-29 17:06:23 -07006749 */
6750 if (CHIP_NUM(bp) == CHIP_NUM_5706 && disable_msi == 0) {
6751 struct pci_dev *amd_8132 = NULL;
6752
6753 while ((amd_8132 = pci_get_device(PCI_VENDOR_ID_AMD,
6754 PCI_DEVICE_ID_AMD_8132_BRIDGE,
6755 amd_8132))) {
Michael Chanf9317a42006-09-29 17:06:23 -07006756
Auke Kok44c10132007-06-08 15:46:36 -07006757 if (amd_8132->revision >= 0x10 &&
6758 amd_8132->revision <= 0x13) {
Michael Chanf9317a42006-09-29 17:06:23 -07006759 disable_msi = 1;
6760 pci_dev_put(amd_8132);
6761 break;
6762 }
6763 }
6764 }
6765
Michael Chandeaf3912007-07-07 22:48:00 -07006766 bnx2_set_default_link(bp);
Michael Chanb6016b72005-05-26 13:03:09 -07006767 bp->req_flow_ctrl = FLOW_CTRL_RX | FLOW_CTRL_TX;
6768
Michael Chancd339a02005-08-25 15:35:24 -07006769 init_timer(&bp->timer);
6770 bp->timer.expires = RUN_AT(bp->timer_interval);
6771 bp->timer.data = (unsigned long) bp;
6772 bp->timer.function = bnx2_timer;
6773
Michael Chanb6016b72005-05-26 13:03:09 -07006774 return 0;
6775
6776err_out_unmap:
6777 if (bp->regview) {
6778 iounmap(bp->regview);
Michael Chan73eef4c2005-08-25 15:39:15 -07006779 bp->regview = NULL;
Michael Chanb6016b72005-05-26 13:03:09 -07006780 }
6781
6782err_out_release:
6783 pci_release_regions(pdev);
6784
6785err_out_disable:
6786 pci_disable_device(pdev);
6787 pci_set_drvdata(pdev, NULL);
6788
6789err_out:
6790 return rc;
6791}
6792
Michael Chan883e5152007-05-03 13:25:11 -07006793static char * __devinit
6794bnx2_bus_string(struct bnx2 *bp, char *str)
6795{
6796 char *s = str;
6797
6798 if (bp->flags & PCIE_FLAG) {
6799 s += sprintf(s, "PCI Express");
6800 } else {
6801 s += sprintf(s, "PCI");
6802 if (bp->flags & PCIX_FLAG)
6803 s += sprintf(s, "-X");
6804 if (bp->flags & PCI_32BIT_FLAG)
6805 s += sprintf(s, " 32-bit");
6806 else
6807 s += sprintf(s, " 64-bit");
6808 s += sprintf(s, " %dMHz", bp->bus_speed_mhz);
6809 }
6810 return str;
6811}
6812
Michael Chanb6016b72005-05-26 13:03:09 -07006813static int __devinit
6814bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
6815{
6816 static int version_printed = 0;
6817 struct net_device *dev = NULL;
6818 struct bnx2 *bp;
6819 int rc, i;
Michael Chan883e5152007-05-03 13:25:11 -07006820 char str[40];
Michael Chanb6016b72005-05-26 13:03:09 -07006821
6822 if (version_printed++ == 0)
6823 printk(KERN_INFO "%s", version);
6824
6825 /* dev zeroed in init_etherdev */
6826 dev = alloc_etherdev(sizeof(*bp));
6827
6828 if (!dev)
6829 return -ENOMEM;
6830
6831 rc = bnx2_init_board(pdev, dev);
6832 if (rc < 0) {
6833 free_netdev(dev);
6834 return rc;
6835 }
6836
6837 dev->open = bnx2_open;
6838 dev->hard_start_xmit = bnx2_start_xmit;
6839 dev->stop = bnx2_close;
6840 dev->get_stats = bnx2_get_stats;
6841 dev->set_multicast_list = bnx2_set_rx_mode;
6842 dev->do_ioctl = bnx2_ioctl;
6843 dev->set_mac_address = bnx2_change_mac_addr;
6844 dev->change_mtu = bnx2_change_mtu;
6845 dev->tx_timeout = bnx2_tx_timeout;
6846 dev->watchdog_timeo = TX_TIMEOUT;
6847#ifdef BCM_VLAN
6848 dev->vlan_rx_register = bnx2_vlan_rx_register;
Michael Chanb6016b72005-05-26 13:03:09 -07006849#endif
6850 dev->poll = bnx2_poll;
6851 dev->ethtool_ops = &bnx2_ethtool_ops;
6852 dev->weight = 64;
6853
Michael Chan972ec0d2006-01-23 16:12:43 -08006854 bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006855
6856#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER)
6857 dev->poll_controller = poll_bnx2;
6858#endif
6859
Michael Chan1b2f9222007-05-03 13:20:19 -07006860 pci_set_drvdata(pdev, dev);
6861
6862 memcpy(dev->dev_addr, bp->mac_addr, 6);
6863 memcpy(dev->perm_addr, bp->mac_addr, 6);
6864 bp->name = board_info[ent->driver_data].name;
6865
Stephen Hemmingerd212f872007-06-27 00:47:37 -07006866 dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
Michael Chan4666f872007-05-03 13:22:28 -07006867 if (CHIP_NUM(bp) == CHIP_NUM_5709)
Stephen Hemmingerd212f872007-06-27 00:47:37 -07006868 dev->features |= NETIF_F_IPV6_CSUM;
6869
Michael Chan1b2f9222007-05-03 13:20:19 -07006870#ifdef BCM_VLAN
6871 dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
6872#endif
6873 dev->features |= NETIF_F_TSO | NETIF_F_TSO_ECN;
Michael Chan4666f872007-05-03 13:22:28 -07006874 if (CHIP_NUM(bp) == CHIP_NUM_5709)
6875 dev->features |= NETIF_F_TSO6;
Michael Chan1b2f9222007-05-03 13:20:19 -07006876
Michael Chanb6016b72005-05-26 13:03:09 -07006877 if ((rc = register_netdev(dev))) {
Jeff Garzik9b91cf92006-06-27 11:39:50 -04006878 dev_err(&pdev->dev, "Cannot register net device\n");
Michael Chanb6016b72005-05-26 13:03:09 -07006879 if (bp->regview)
6880 iounmap(bp->regview);
6881 pci_release_regions(pdev);
6882 pci_disable_device(pdev);
6883 pci_set_drvdata(pdev, NULL);
6884 free_netdev(dev);
6885 return rc;
6886 }
6887
Michael Chan883e5152007-05-03 13:25:11 -07006888 printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, "
Michael Chanb6016b72005-05-26 13:03:09 -07006889 "IRQ %d, ",
6890 dev->name,
6891 bp->name,
6892 ((CHIP_ID(bp) & 0xf000) >> 12) + 'A',
6893 ((CHIP_ID(bp) & 0x0ff0) >> 4),
Michael Chan883e5152007-05-03 13:25:11 -07006894 bnx2_bus_string(bp, str),
Michael Chanb6016b72005-05-26 13:03:09 -07006895 dev->base_addr,
6896 bp->pdev->irq);
6897
6898 printk("node addr ");
6899 for (i = 0; i < 6; i++)
6900 printk("%2.2x", dev->dev_addr[i]);
6901 printk("\n");
6902
Michael Chanb6016b72005-05-26 13:03:09 -07006903 return 0;
6904}
6905
6906static void __devexit
6907bnx2_remove_one(struct pci_dev *pdev)
6908{
6909 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006910 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006911
Michael Chanafdc08b2005-08-25 15:34:29 -07006912 flush_scheduled_work();
6913
Michael Chanb6016b72005-05-26 13:03:09 -07006914 unregister_netdev(dev);
6915
6916 if (bp->regview)
6917 iounmap(bp->regview);
6918
6919 free_netdev(dev);
6920 pci_release_regions(pdev);
6921 pci_disable_device(pdev);
6922 pci_set_drvdata(pdev, NULL);
6923}
6924
6925static int
Pavel Machek829ca9a2005-09-03 15:56:56 -07006926bnx2_suspend(struct pci_dev *pdev, pm_message_t state)
Michael Chanb6016b72005-05-26 13:03:09 -07006927{
6928 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006929 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006930 u32 reset_code;
6931
6932 if (!netif_running(dev))
6933 return 0;
6934
Michael Chan1d60290f2006-03-20 17:50:08 -08006935 flush_scheduled_work();
Michael Chanb6016b72005-05-26 13:03:09 -07006936 bnx2_netif_stop(bp);
6937 netif_device_detach(dev);
6938 del_timer_sync(&bp->timer);
Michael Chandda1e392006-01-23 16:08:14 -08006939 if (bp->flags & NO_WOL_FLAG)
Michael Chan6c4f0952006-06-29 12:38:15 -07006940 reset_code = BNX2_DRV_MSG_CODE_UNLOAD_LNK_DN;
Michael Chandda1e392006-01-23 16:08:14 -08006941 else if (bp->wol)
Michael Chanb6016b72005-05-26 13:03:09 -07006942 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_WOL;
6943 else
6944 reset_code = BNX2_DRV_MSG_CODE_SUSPEND_NO_WOL;
6945 bnx2_reset_chip(bp, reset_code);
6946 bnx2_free_skbs(bp);
Michael Chan30c517b2007-05-03 13:20:40 -07006947 pci_save_state(pdev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006948 bnx2_set_power_state(bp, pci_choose_state(pdev, state));
Michael Chanb6016b72005-05-26 13:03:09 -07006949 return 0;
6950}
6951
6952static int
6953bnx2_resume(struct pci_dev *pdev)
6954{
6955 struct net_device *dev = pci_get_drvdata(pdev);
Michael Chan972ec0d2006-01-23 16:12:43 -08006956 struct bnx2 *bp = netdev_priv(dev);
Michael Chanb6016b72005-05-26 13:03:09 -07006957
6958 if (!netif_running(dev))
6959 return 0;
6960
Michael Chan30c517b2007-05-03 13:20:40 -07006961 pci_restore_state(pdev);
Pavel Machek829ca9a2005-09-03 15:56:56 -07006962 bnx2_set_power_state(bp, PCI_D0);
Michael Chanb6016b72005-05-26 13:03:09 -07006963 netif_device_attach(dev);
6964 bnx2_init_nic(bp);
6965 bnx2_netif_start(bp);
6966 return 0;
6967}
6968
6969static struct pci_driver bnx2_pci_driver = {
Peter Hagervall14ab9b82005-08-10 14:18:16 -07006970 .name = DRV_MODULE_NAME,
6971 .id_table = bnx2_pci_tbl,
6972 .probe = bnx2_init_one,
6973 .remove = __devexit_p(bnx2_remove_one),
6974 .suspend = bnx2_suspend,
6975 .resume = bnx2_resume,
Michael Chanb6016b72005-05-26 13:03:09 -07006976};
6977
6978static int __init bnx2_init(void)
6979{
Jeff Garzik29917622006-08-19 17:48:59 -04006980 return pci_register_driver(&bnx2_pci_driver);
Michael Chanb6016b72005-05-26 13:03:09 -07006981}
6982
6983static void __exit bnx2_cleanup(void)
6984{
6985 pci_unregister_driver(&bnx2_pci_driver);
6986}
6987
6988module_init(bnx2_init);
6989module_exit(bnx2_cleanup);
6990
6991
6992